1

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:

cropped window

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:

New dialog

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.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • 1
    I assume your code changes the size of the dialog and this should be reproducible under the debugger. My approach would be: First comment out your call to RestoreWindowPosition() in OnInitDialog() - then probably the bug doesn't appear any more? Second reproducing the bug in the debugger, see how the window size being set changes. Of course you must not change the effective window size, which was adjusted to your screen scaling! – Nick Dec 03 '19 at 10:34
  • @Nick Correct. If i comment out my `RestoreWindowPosition()` method the window shows with the right (scaled) size. – Andrew Truckle Dec 03 '19 at 10:38
  • 1
    As I see you restore the exact window size at is was saved formerly. My attempt for this problem was saving the size normalized to 100% screen scaling and when restoring multiplying it with the actual screen scaling. In your case (you're relying on MFC/Windows standard scaling mechanisms) you should rather only change the window position and leave its size. – Nick Dec 03 '19 at 10:48
  • @Nick How do you save the size normalized for 100% screen scaling and vice-versa? – Andrew Truckle Dec 03 '19 at 10:51
  • 1
    Use API function GetDpiForMonitor(), divide by LOGPIXELSX (=96) to get the scaling as a floating number (you can just refer to the X values as X and Y scaling are always identical). Then divide by it to normalize to 100% and multiply with it to get the current screeen's correct coordinates or sizes. – Nick Dec 03 '19 at 11:07
  • For some reason `GetDpiPerMonitor` is not a known function for me. – Andrew Truckle Dec 03 '19 at 11:25
  • 1
    For me either (I'm using another approach for this)... Maybe an extended SDK? But you can also use GetDeviceCaps(hDC, LOGPIXELSX) on a DC in this window. – Nick Dec 03 '19 at 11:45
  • The latter works. I will have to decide what I want to do. When I have something working I will add an answer. Unless someone comes forward in the meantime. – Andrew Truckle Dec 03 '19 at 11:48
  • @Nick I updated my question with my results. – Andrew Truckle Dec 03 '19 at 12:44
  • So I'm looking forward to your findings! (Btw. I'm extending an existing application to become per monitor DPI aware, which is a real challenge. Starting on the right monitor with the right size is still not completely solved on my side....) – Nick Dec 03 '19 at 12:56
  • @Nick it doesn't make sense. If I just take the default dialog size (no resize) for 100% it is 594 wide. When using 125% it is 692 wide. I can't calculate this 692 from 594. – Andrew Truckle Dec 03 '19 at 13:12
  • 1
    The reason is that a dialog's size depends on dialogbaseunits, which depend on its font. As font proportions cannot be calculated by simple multiplications, they appear to be inpredictable for an application's code and you must rely on the results of Windows/MFC. So you should not resize your dialog window but only reposition it. – Nick Dec 03 '19 at 15:38

1 Answers1

0

I don't know if this is the best way but I have taken on board some of the comments. This gives me 95% solution.

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;
            }

            if (m_bOnlyStorePosition)
            {
                // We must override the dimensions of the dialog. This is because the user
                // might have text scale in effect.
                CRect rtOrg;
                GetWindowRect(&rtOrg);
                // But we want to show it in the previous place (albeit slightly off position)
                pWindow->MoveWindow(rtWindow.left, rtWindow.top, rtOrg.Width(), rtOrg.Height());
            }
            else
            {
                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);
        }
    }
}

The primary problem was when we were restoring windows that had a fixed size (since resizeable windows can just be resized if they are wrong by the user).

So I added a little bit of code to just restore the window at the X/ Y, but with the native width and height. However the MFC mechanics does it the values are always correct here so it makes sense to just use them.

The only problem is that the x/y origin is not taking into account the changes to the text scaling but at least they can move the window now and it would be OK.

Please let me know if you can think of any improvements to this code tweak I made to my function. I hope it is useful for others in this predicament.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • 1
    Your code looks reasonable to me if you leave out the part changing the dialog's size. – Nick Dec 03 '19 at 15:39
  • 1
    @Nick I did tweak it a bit. The previous code was returning early so it was not setting the width and height. But I have re-jigged it to do the other tests still to massage the top left corner. Working OK. – Andrew Truckle Dec 03 '19 at 19:54