I'm working with an in-house MFC application which attempts to programmatically change the font size of a dialog by finding it in a DLGTEMPLATEEX structure obtained using the Win32 LoadResource function and writing directly to the font size member of that structure. When running under the Debugger in VS 2019, this triggers a memory write access violation.
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
I believe the code is finding the correct target memory location in the returned structure, because the structure has the correct signature at the expected offset (0xFFFF identifying it as a DLGTEMPLATEEX not just a DLGTEMPLATE -- although the code doesn't have any error checking for if it were not), and I single-stepped the code which computes the pointer to the font size member. It points to a DWORD of value "8" which seems reasonable for the system font size.
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;
}
The return value points at a DWORD "8" when the code tries to actually change that "8" to another number by writing through the pointer, it crashes in the Visual Studio 2019 debugger with a memory "write access violation".
I have many concerns about what I'm seeing here.
First of all, does clobbering this memory location like this even accomplish anything? How does the OS see that the value changed? I would expect the correct way to do it to be some Win32 function call like "SetDlgFontSize" or something, not spelunking around in data structures.
Second, how did this code ever work at all? Is it something that worked on older versions of Windows, but not on Windows 10? Is it failing now because I upgraded the project to VS 2019 (previously it was up to 2012). Or is the VS 2019 Debugger (or Debug build) pre-emptively setting a write-protect bit on memory pages with operating system structures I shouldn't be writing?
Third, I need to decide whether to fix this by commenting out the crashing code or setting the font size "properly." That depends on whether the offending code actually ever had an effect. If it didn't I can comment it out, but if I need to replicate the effect correctly the only MFC code I've found so far for doing this sets the font size and font family together. So then I'd need to also add code to find out the correct font...