5
votes

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.

3
Is it a standard dialog drawn in the ressource editor or is it a window/dialog constructed programatically ? Show some code.Jabberwocky
@MichaelWalz I think I've pulled everything relevant from the .RC file; this is happening with all of the dialogs in the app so the details of what the other controls are shouldn't matter.Dan Is Fiddling By Firelight
Does it also happen with a newly created minimal MFC app ?Jabberwocky
That shouldn't happen on a standard dialog based window, everything is in dialog units and will be translated to screen units based on factors such as font scaling. I imagine you have two windows here, an outer one and an inner Dialog one. You need to resize the outer one based on GetClientRect of the inner one.snowdude
@MichaelWalz An empty/default wizard created MFC dialog app doesn't have whatever the problem I'm running into with the app I'm working on. If it'd be helpful in trying to figure out where something that's non-standard by current practice would be located at; the MFC version of this app dates back at least as far as Visual Studio 6. Getting it to look and play with a current version of Visual Studio and look like a modern application has been a large part of my ongoing work on it.Dan Is Fiddling By Firelight

3 Answers

3
votes

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.

2
votes

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
0
votes

In the linker options deaktivate System => SubSystem by selecting "not specified" or "inherit from parent or project defaults". In Commandline specify an additional option "/SubSystem:Windows,5.01"