I'm saving/restoring my window position using GetWindowPlacement/SetWindowPlacement on Windows 10. My application is DPI aware. The issue occurs when SetWindowPlacement is both sizing and moving the window from monitor #1 with one DPI to monitor #2 with a different DPI. The coordinates have been saved as the correct size for monitor #2 in the WINDOWPLACEMENT structure.
The window is first resized during SetWindowPlacement while it's still on monitor #1. Then window is moved to monitor #2, which causes a WM_DPICHANGED message to fire, saying the window size should be changed. The suggested size is incorrect since it's changing the size of the window which was already the correct size for monitor #2. What is the correct way to solve this? Should I be setting a flag before SetWindowPlacement to ignore WM_DPICHANGED messages until that call is done? Are there cases where that will cause me to miss a message I shouldn't be ignoring? Thanks
Edit: Attached repro for @SongZhu-MSFT. In this test case I'm using a Surface Studio 2 as my primary monitor, running at 4500x3000, using 175% scaling. On the right of that monitor, aligned to the bottom is a 1920x1080 monitor set to 100% scaling. This code attempts to open the monitor on the right monitor with a set size, however a DPICHANGE message comes through during the SetWindowPlacement() call which causes the size to be adjusted incorrectly, unless I manually avoid it. Sample code is edited from: https://docs.microsoft.com/en-us/windows/win32/learnwin32/windows-hello-world-sample
#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const wchar_t CLASS_NAME[] = L"Sample Window Class";
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class
L"Learn to Program Windows", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
WINDOWPLACEMENT wp = {};
wp.length = sizeof(wp);
wp.showCmd = 1;
wp.ptMaxPosition.x = -1;
wp.ptMaxPosition.y = -1;
wp.ptMinPosition.x = -1;
wp.ptMinPosition.y = -1;
wp.rcNormalPosition.left = 4510;
wp.rcNormalPosition.top = 2320;
wp.rcNormalPosition.right = wp.rcNormalPosition.left + 1850;
wp.rcNormalPosition.bottom = 2909;
::SetWindowPlacement((HWND)hwnd, &wp);
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_DPICHANGED:
{
int dpi = HIWORD(wParam);
{
RECT* const prcNewWindow = (RECT*)lParam;
SetWindowPos(hwnd,
NULL,
prcNewWindow->left,
prcNewWindow->top,
prcNewWindow->right - prcNewWindow->left,
prcNewWindow->bottom - prcNewWindow->top,
SWP_NOZORDER | SWP_NOACTIVATE);
}
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// All painting occurs here, between BeginPaint and EndPaint.
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
And the .manifest I'm using.
<?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>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,permonitor</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
</windowsSettings>
</application>
</assembly>
SetWindowPlacement
? – Daniel SękThe suggested size is incorrect since it's changing the size of the window which was already the correct size for monitor #2.
And you can provide some screenshots to illustrate the results you expect and what actually happened, which will help us solve the problem. Thank you for your understanding. – Song Zhu