I have this base class for resizing dialogs and remembering their window state.
BOOL CResizingDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Save Initial window size to m_rcInit
GetWindowRect(&m_rcInit);
//if (!m_bOnlyStorePosition && !m_bDoNotShowResizeIcon)
//InitialiseResizeIcon(m_bmpResize, m_lblResize, this);
RestoreWindowPosition(m_strWindowID, this, true);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CResizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
// Set the minimum window size to initial size.
lpMMI->ptMinTrackSize.x = m_rcInit.Width();
lpMMI->ptMinTrackSize.y = m_rcInit.Height();
CDialogEx::OnGetMinMaxInfo(lpMMI);
}
void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
{
int max_x, max_y;
RECT rtWindow;
if (pWindow == nullptr)
return;
// Only restore if there is a previously saved position
if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("Top"), -1)) != -1 &&
(rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("Left"), -1)) != -1 &&
(rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("Bottom"), -1)) != -1 &&
(rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("Right"), -1)))
{
max_x = rtWindow.right - rtWindow.left;
max_y = rtWindow.bottom - rtWindow.top;
// Get a handle to the monitor
HMONITOR hMonitor = ::MonitorFromPoint(
CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
// Get the monitor info
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
AfxMessageBox(_T("GetMonitorInfo failed"));
else
{
// Adjust for work area
rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
// Ensure top left point is on screen
if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
{
rtWindow.left = monInfo.rcWork.left;
rtWindow.top = monInfo.rcWork.top;
}
rtWindow.right = rtWindow.left + max_x;
rtWindow.bottom = rtWindow.top + max_y;
// Restore window size
pWindow->MoveWindow(&rtWindow, FALSE);
}
if (bOverrideState)
{
// Let us override by restoring the window state
int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
pWindow->ShowWindow(iState);
}
}
}
Sometimes all I do is remember the window position. Well, a user reported this issue to me:
As you can see, the window has cropped the controls. I have not checked the users PC but for some reason the window (which is not resizable) has cropped the controls.
Update
I have been able to replicate the issue. I am using a HD (not Ultra HD) on my Windows 10 PC. If I set the text scaling for the operating system to 150% I can see this issue.
My MFC project is compiled with the setting DPI Per Monitor so it should be OK. It is failing and using the original size of the dialog and not the "scaled" size of the dialog.
I did more tests and it seems it is just this one window not behaving. This is the dialog resource:
IDD_DIALOG_OUR_CHRISTIAN_LIFE_AND_MINISTRY_STUDENTS DIALOGEX 0, 0, 385, 298
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Apply Yourself to the Field Ministry"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Main hall",IDC_STATIC,7,7,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_MH,29,16,29,8
LTEXT "Study #",IDC_STATIC_STUDY_MH,117,16,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_MH,154,16,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,15,29,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_MH_STUDENT,29,26,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_MH_STUDENT_STUDY,117,26,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_MH_ASSIST,154,26,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_MH,"MfcButton",WS_TABSTOP,242,26,15,15
LTEXT "#2",IDC_STATIC,15,46,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_MH_STUDENT,29,43,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_MH_STUDENT_STUDY,117,43,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_MH_ASSIST,154,43,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_MH,"MfcButton",WS_TABSTOP,242,43,15,15
LTEXT "#3",IDC_STATIC,15,62,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_MH_STUDENT,29,60,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_MH_STUDENT_STUDY,117,60,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_MH_ASSIST,154,60,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_MH,"MfcButton",WS_TABSTOP,242,60,15,15
LTEXT "#4",IDC_STATIC,15,80,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_MH_STUDENT,29,78,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_MH_STUDENT_STUDY,117,78,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_MH_ASSIST,154,78,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_MH,"MfcButton",WS_TABSTOP,241,78,15,15
GROUPBOX "Auxiliary Classroom 1",IDC_STATIC,7,102,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_C1,30,111,29,8
LTEXT "Study #",IDC_STATIC_STUDY_C1,117,111,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_C1,154,111,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,15,124,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C1_STUDENT,29,121,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_C1_STUDENT_STUDY,117,121,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C1_ASSIST,154,121,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_C1,"MfcButton",WS_TABSTOP,242,121,15,15
LTEXT "#2",IDC_STATIC,15,142,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C1_STUDENT,29,139,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_C1_STUDENT_STUDY,117,139,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C1_ASSIST,154,139,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_C1,"MfcButton",WS_TABSTOP,242,139,15,15
LTEXT "#3",IDC_STATIC,15,158,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C1_STUDENT,29,157,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_C1_STUDENT_STUDY,117,157,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C1_ASSIST,154,157,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_C1,"MfcButton",WS_TABSTOP,242,157,15,15
LTEXT "#4",IDC_STATIC,15,176,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C1_STUDENT,29,175,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_C1_STUDENT_STUDY,117,175,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C1_ASSIST,154,175,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_C1,"MfcButton",WS_TABSTOP,241,175,15,15
GROUPBOX "Auxiliary Classroom 2",IDC_STATIC,7,198,257,93
LTEXT "Student:",IDC_STATIC_STUDENT_C2,30,208,29,8
LTEXT "Study #",IDC_STATIC_STUDY_C2,117,207,27,8
LTEXT "Assistant:",IDC_STATIC_ASSIST_C2,154,208,33,8,0,WS_EX_RIGHT
LTEXT "#1",IDC_STATIC,16,222,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C2_STUDENT,29,219,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN2_C2_STUDENT_STUDY,117,219,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN2_C2_ASSIST,154,219,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM1_C2,"MfcButton",WS_TABSTOP,242,219,15,15
LTEXT "#2",IDC_STATIC,16,239,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C2_STUDENT,29,237,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN3_C2_STUDENT_STUDY,117,237,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN3_C2_ASSIST,154,237,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM2_C2,"MfcButton",WS_TABSTOP,242,237,15,15
LTEXT "#3",IDC_STATIC,16,255,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C2_STUDENT,29,254,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN4_C2_STUDENT_STUDY,117,254,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN4_C2_ASSIST,154,254,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM3_C2,"MfcButton",WS_TABSTOP,242,254,15,15
LTEXT "#4",IDC_STATIC,15,272,10,8
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C2_STUDENT,29,272,84,14,ES_AUTOHSCROLL | ES_READONLY
COMBOBOX IDC_COMBO_OCLM_AYFM_ASSIGN5_C2_STUDENT_STUDY,117,272,26,133,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_EDIT_OCLM_AYFM_ASSIGN5_C2_ASSIST,154,272,84,14,ES_AUTOHSCROLL | ES_READONLY
CONTROL "",IDC_MFCBUTTON_ITEM4_C2,"MfcButton",WS_TABSTOP,241,272,15,15
EDITTEXT IDC_EDIT_INFO,270,7,108,243,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL
DEFPUSHBUTTON "OK",IDOK,270,255,108,14
PUSHBUTTON "Cancel",IDCANCEL,270,274,108,14
END
I wondered if it was my code in CResizingDialog
that might be flawed? But then I read this answer. It implies that since I am compiling for DPI aware monitors the MFC project should work out of the box. So why am I ended up with a window size that has not compensated for the scaling setting?
I can verify that the embedded manifest also has this DPI setting (I ave snipped out some info for brevity):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
</windowsSettings>
</application>
</assembly>
Update
The issue has to do with RestoreWindowPosition
. Say that my last stored position was when I was using 100% font scaling. And now I am using 150% font scaling. The dimensions held in the registry for the window were for 100% scaling. Thus it is cropped.
Similarly, if I rem out my restore code, and use scaled text of 150% and close the window, the sizing in the registry is now for 150%. So if I revert to a 100% scaling the size is wrong.
I am not sure how to proceed. My code for saving the window position is here:
void CResizingDialog::SaveWindowPosition(CString strWindow, CWnd* pWindow)
{
WINDOWPLACEMENT wp;
if (pWindow == nullptr)
return;
pWindow->GetWindowPlacement(&wp);
// Commit to registry
AfxGetApp()->WriteProfileInt(strWindow, _T("Top"), wp.rcNormalPosition.top);
AfxGetApp()->WriteProfileInt(strWindow, _T("Left"), wp.rcNormalPosition.left);
AfxGetApp()->WriteProfileInt(strWindow, _T("Bottom"), wp.rcNormalPosition.bottom);
AfxGetApp()->WriteProfileInt(strWindow, _T("Right"), wp.rcNormalPosition.right);
AfxGetApp()->WriteProfileInt(strWindow, _T("ShowCmd"), wp.showCmd);
}
Clearly the values it is saving is dependant on the active scaling. #confused - headache.
Update
Based on the comments I tried to make some changes to store the positions normalised and then scale them. But it is nt quite right.
Here is the code:
void CResizingDialog::RestoreWindowPosition(CString strWindow, CWnd* pWindow, bool bOverrideState)
{
int max_x, max_y;
RECT rtWindow;
if (pWindow == nullptr)
return;
// Only restore if there is a previously saved position
if ((rtWindow.top = AfxGetApp()->GetProfileInt(strWindow, _T("TopDPI"), -1)) != -1 &&
(rtWindow.left = AfxGetApp()->GetProfileInt(strWindow, _T("LeftDPI"), -1)) != -1 &&
(rtWindow.bottom = AfxGetApp()->GetProfileInt(strWindow, _T("BottomDPI"), -1)) != -1 &&
(rtWindow.right = AfxGetApp()->GetProfileInt(strWindow, _T("RightDPI"), -1)))
{
CDC* screen = GetDC();
if (screen != nullptr)
{
double dpi = static_cast<double>(screen->GetDeviceCaps(LOGPIXELSX));
// 100% Scaled Text using 96 DPI
double dScaleFactor = dpi / 96.0;
rtWindow.top *= dScaleFactor;
rtWindow.left *= dScaleFactor;
rtWindow.bottom *= dScaleFactor;
rtWindow.right *= dScaleFactor;
ReleaseDC(screen);
}
max_x = rtWindow.right - rtWindow.left;
max_y = rtWindow.bottom - rtWindow.top;
// Get a handle to the monitor
HMONITOR hMonitor = ::MonitorFromPoint(
CPoint(rtWindow.left, rtWindow.top), MONITOR_DEFAULTTONEAREST);
// Get the monitor info
MONITORINFO monInfo;
monInfo.cbSize = sizeof(MONITORINFO);
if (::GetMonitorInfo(hMonitor, &monInfo) == 0)
AfxMessageBox(_T("GetMonitorInfo failed"));
else
{
// Adjust for work area
rtWindow.left += monInfo.rcWork.left - monInfo.rcMonitor.left;
rtWindow.top += monInfo.rcWork.top - monInfo.rcMonitor.top;
// Ensure top left point is on screen
if (CRect(monInfo.rcWork).PtInRect(CPoint(rtWindow.left, rtWindow.top)) == FALSE)
{
rtWindow.left = monInfo.rcWork.left;
rtWindow.top = monInfo.rcWork.top;
}
rtWindow.right = rtWindow.left + max_x;
rtWindow.bottom = rtWindow.top + max_y;
// Restore window size
pWindow->MoveWindow(&rtWindow, FALSE);
}
if (bOverrideState)
{
// Let us override by restoring the window state
int iState = AfxGetApp()->GetProfileInt(strWindow, _T("ShowCmd"), SW_SHOWNORMAL);
pWindow->ShowWindow(iState);
}
}
}
void CResizingDialog::SaveWindowPosition(CString strWindow, CWnd* pWindow)
{
WINDOWPLACEMENT wp;
if (pWindow == nullptr)
return;
pWindow->GetWindowPlacement(&wp);
CDC *screen = GetDC();
if (screen != nullptr)
{
double dpi = static_cast<double>(screen->GetDeviceCaps(LOGPIXELSX));
// 100% Scaled Text using 96 DPI
double dScaleFactor = dpi / 96.0;
AfxGetApp()->WriteProfileInt(strWindow, _T("TopDPI"), wp.rcNormalPosition.top / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("LeftDPI"), wp.rcNormalPosition.left / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("BottomDPI"), wp.rcNormalPosition.bottom / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("RightDPI"), wp.rcNormalPosition.right / dScaleFactor);
AfxGetApp()->WriteProfileInt(strWindow, _T("ShowCmd"), wp.showCmd);
ReleaseDC(screen);
}
}
Here is a dialog now when my PC is at a DPI of 120:
The good news is that I can now see all the controls. The bad news is that it is actually too wide. I tried commenting out the code that adjusts it for the work area and ensures the top left point is on screen but this only reduced it by a little.
I don't understand why it is now too wide? It is also slightly taller than it should be.