Я работаю с собственным MFC-приложением, которое пытается программным образом изменить размер шрифта диалога, найдя его в структуре DLGTEMPLATEEX, полученной с помощью функции WinR LoadResource, и записав непосредственно в член размера шрифта этой структуры. При запуске под отладчиком в VS 2019 это вызывает нарушение прав доступа к записи в память.
BOOL CMk20Dlg::Create(UINT nIDTemplate, CWnd* pParentWnd)
{
LPCTSTR lpszTemplateName = MAKEINTRESOURCE(nIDTemplate);
ASSERT(IS_INTRESOURCE(lpszTemplateName) || AfxIsValidString(lpszTemplateName));
m_lpszTemplateName = lpszTemplateName;
if (IS_INTRESOURCE(m_lpszTemplateName) && m_nIDHelp == 0)
m_nIDHelp = LOWORD(reinterpret_cast<DWORD_PTR>(m_lpszTemplateName));
HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);
HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG);
if (hResource == NULL)
TRACE(_T("FindResource failed with error %d\n"), ::GetLastError());
HGLOBAL hTemplate = ::LoadResource(hInst, hResource);
DLGTEMPLATE* lpTemplate = static_cast<DLGTEMPLATE*>(::LockResource(hTemplate));
WORD* pwFontSize = GetResFontSizeOffset(lpTemplate);
*pwFontSize = static_cast<WORD>((8.0 * theApp.GetFontScaleFactor()) + 0.5);
// ^-- crash on write to *pwFontSize
Я полагаю, что код находит правильное целевое расположение памяти в возвращенной структуре, потому что структура имеет правильную подпись вожидаемое смещение (0xFFFF, идентифицирующее его как DLGTEMPLATEEX, а не просто DLGTEMPLATE - хотя в коде нет проверки на наличие ошибок, если это не так), и я пошагово код, который вычисляет указатель на член размера шрифта. Он указывает на DWORD со значением «8», что кажется разумным для размера системного шрифта.
WORD* CMk20Dlg::GetResFontSizeOffset(DLGTEMPLATE* lpTemplate)
{
WORD* pwPtr = reinterpret_cast<WORD*>(lpTemplate);
// lpTemplate is in the format of a DLGTEMPLATEEX
// Refer Win32 SDK documentation of "struct" DLGTEMPLATEEX
++pwPtr; // dlgVer
++pwPtr; // signature
/* ^-- At this point *pwPtr has value 0xFFFF in the debugger, indicating DLGTEMPLATEEX */
/* The ++'ing of pwPtr continues through the rest of the struct members,
then it skips over the menu array, window class array, title, etc. Finally: */
// We are now pointing at the font size word
return pwPtr;
}
Возвращаемое значение указывает на DWORD «8», когда код пытается фактически изменить это «8» надругой номер при записи через указатель сбой в отладчике Visual Studio 2019 с памятью «нарушение прав записи».
У меня много вопросов по поводу того, что я вижу здесь.
Первыйиз всего, удаляет ли что-либо такое засорение этой области памяти? Как ОС видит, что значение изменилось? Я ожидал бы, что правильным способом сделать это будет какой-нибудь вызов функции Win32, такой как «SetDlgFontSize» или что-то еще, не разбирающееся в структурах данных.
Во-вторых, как этот код вообще когда-либо работал? Это то, что работало на старых версиях Windows, но не на Windows 10? Это терпит неудачу сейчас, потому что я обновил проект до VS 2019 (ранее это было до 2012 года). Или отладчик VS 2019 (или сборка отладки) упреждающе устанавливает бит защиты от записи на страницах памяти со структурами операционной системы, которые я не должен писать?
В-третьих, мне нужно решить, следует ли это исправитьзакомментировав код сбоя или установив размер шрифта «правильно». Это зависит от того, действительно ли когда-либо нарушал код. Если это не так, я могу закомментировать это, но если мне нужно правильно воспроизвести эффект, единственный код MFC, который я нашел для этого, устанавливает размер шрифта и семейство шрифтов вместе. Тогда мне нужно будет добавить код, чтобы узнать правильный шрифт ...