Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MFC dialog Border padding changed after switching from VS2010 to 2012 or later

After rebuilding an MFC app in VS2015, where the border padding set by Windows changed from being added to the outside of the dialog frame to the inside of it. As a result of the change instead of a thick border making the dialog larger, the dialog size remains constant and the amount of space available for controls is reduced.

The default value of the border padding has changed between different versions of Windows. It went from a smaller value (0?) to 4 pixels when Vista came out to make glass more noticeable and appears to've stayed there through 8.x, only to drop back to 0 for Win10. (Caveat, I don't have any 8/10 machines available at work and am going off of Google here.)

This means that the amount of space for controls is varying between different Windows versions. As a result it seems impossible to have dialogs that look good on all versions of the OS. If I lay them for the 4px borders that are the default in V7/8 I'll end up with a noticeable amount of extra space on the bottom/right on a default W10 system. If I optimize for W10, my bottom buttons will be cut off on W7/8.

This isn't happening in a clean test project, so it's something to do with specific code in my application.

I've attached a picture of what 0 vs 4 pixel borders look like in an app build in VS2010 or newer versions. The image is captioned VS2015; but additional testing determined that the change was introduced with the V110 runtime (Visual Studio 2012).

The dialog sizing appears to be getting messed up in code that's using MoveWindow() to position the smaller dialogs around the main one.

I've extracted the code involved in doing one dialog below:

RECT             DlgRect;
double Fx, Fy, Fw, Fh;      // the dialog in the screenshots
double Px, Py, Pw, Ph;      // another dialog 
double ScreenHeight = (double)GetSystemMetrics(SM_CYSCREEN);

g_pRedactedDlg = new CRedactedDlg(NULL);
g_pRedactedDlg->GetClientRect(&DlgRect);
Fw = DlgRect.right + 10;    // 10
Fh = DlgRect.bottom + 20;   // 20

Py = 100; //size and position data for a different 
Ph = 50;  //dialog, calculated in code not shown

Fx = 0.0;
Fy = ((Py + Ph + 5.0 + Fh) > ScreenHeight) ? (ScreenHeight - Fh) : (Py + Ph + 5.0);

g_pRedactedDlg->MoveWindow((int)Fx, (int)Fy, (int)Fw, (int)Fh, TRUE);

Based on comments from @snowdude and @MichaelWalz I suspect the size being got from GetClientRect() and the size expected by MoveWindow() differ in how they handle the size of the dialog border; but haven't traced through it all yet to see what changes when I change the border size.

enter image description here

FYI The border padding setting is at: Control Panel - Personalization - Window Color - Advanced Appearance Settings - Border Padding.

like image 589
Dan Is Fiddling By Firelight Avatar asked Nov 23 '15 20:11

Dan Is Fiddling By Firelight


2 Answers

The behavior of GetWindowRect() and MoveWindow() was changed between VS2010 and 2012. In 2010, GetWindowRect() returns the dialog area without border padding, and MoveWindowRect() expects the dialog area with it; the size of the rendered dialog has the padding added. In 2012 the dialog area is returned with the padding added, and no padding is added to the rendered dialog size.

This was reported on MS Connect and traced to a linker flag. /SUBSYSTEM:WINDOWS,5.01 gives the old behavior, /SUBSYSTEM:WINDOWS,6,00 gives the new behavior. VS2015s doesn't appear to allow specifying the version to be passed here. Project Properties-Linker-All Options-Subsystem, is a drop down and only has a single option for Windows.

It's possible that the breaking change is the result of removing a compatibility hack that was added when Vista was released.

For my application, I fixed this by using GetWindowRect() to compute the size of the dialog instead of GetClientRect() and then adding a hard coded padding value.

g_pRedactedDlg->GetWindowRect(&DlgRect);
Fw = DlgRect.right - DlgRect.left;
Fh = DlgRect.bottom - DlgRect.top;

This doesn't produce identical behavior to the old version, because the hard coded height offset is 12 pixels too small under Windows 7 and was truncating the bottom of dialogs as shown in the RC designer. It's possible the offsets were correct under older versions of Windows; the MFC codebase dates back at least to Visual Studio 97/NT4.

like image 88
Dan Is Fiddling By Firelight Avatar answered Nov 04 '22 14:11

Dan Is Fiddling By Firelight


Setting in linker /SUBSYSTEM:WINDOWS,5.01 I resolved the problem.

In Visual Studio 2015 is possible to set /SUBSYSTEM:WINDOWS,5.01:

  • Project Properties / Linker / System
  • set SubSystem = Windows (/SUBSYSTEM:WINDOWS)
  • set Minimum required Version = 5.01
like image 30
HJoe Avatar answered Nov 04 '22 13:11

HJoe