diff --git a/Contrib/Makensisw/resource.h b/Contrib/Makensisw/resource.h index f346e2bf..8cc29a7b 100644 --- a/Contrib/Makensisw/resource.h +++ b/Contrib/Makensisw/resource.h @@ -79,9 +79,10 @@ #define IDC_WNDCLASS 223 #define IDC_WNDUSERDATA 224 #define IDC_WNDSTYLE 225 -#define IDC_WNDSIZE 226 -#define IDC_WNDINFO 227 -#define IDC_WNDDPI 228 +#define IDC_WNDLOGISIZE 226 +#define IDC_WNDPHYSSIZE 227 +#define IDC_WNDINFO 229 +#define IDC_WNDDPI 230 #define IDM_MRU_FILE 6000 #define IDM_CMDBASE 500 diff --git a/Contrib/Makensisw/resource.rc b/Contrib/Makensisw/resource.rc index 26cafaba..4f30966f 100644 --- a/Contrib/Makensisw/resource.rc +++ b/Contrib/Makensisw/resource.rc @@ -246,7 +246,7 @@ BEGIN PUSHBUTTON "&Delete",IDC_DEL,6,102,50,14 END -DLG_WNDSPY DIALOGEX 0, 0, 236, 120 +DLG_WNDSPY DIALOGEX 0, 0, 236, 130 STYLE DS_SETFONT | DS_FIXEDSYS | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Window Info" FONT 8, "MS Shell Dlg", 0, 0, 0x0 @@ -263,12 +263,14 @@ BEGIN CONTROL "", IDC_WNDUSERDATA, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, 39, 64, 190, 10 CONTROL "Style:", IDC_STATIC, "Static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP , 7, 74, 32, 10 CONTROL "", IDC_WNDSTYLE, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL , 39, 74, 190, 10 - CONTROL "Size:", IDC_STATIC, "Static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP , 7, 84, 32, 10 - CONTROL "", IDC_WNDSIZE, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL , 39, 84, 190, 10 - CONTROL "Info:", IDC_STATIC, "Static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP , 7, 94, 32, 10 - CONTROL "", IDC_WNDINFO, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL , 39, 94, 190, 10 - CONTROL "DPI:", IDC_STATIC, "Static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP , 7, 104, 32, 10 - CONTROL "", IDC_WNDDPI, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL , 39, 104, 190, 10 + CONTROL "Logical:", IDC_STATIC, "Static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP , 7, 84, 32, 10 + CONTROL "", IDC_WNDLOGISIZE, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, 39, 84, 190, 10 + CONTROL "Physical:", IDC_STATIC, "Static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP , 7, 94, 32, 10 + CONTROL "", IDC_WNDPHYSSIZE, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL, 39, 94, 190, 10 + CONTROL "Info:", IDC_STATIC, "Static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP , 7, 104, 32, 10 + CONTROL "", IDC_WNDINFO, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL , 39, 104, 190, 10 + CONTROL "DPI:", IDC_STATIC, "Static", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP , 7, 114, 32, 10 + CONTROL "", IDC_WNDDPI, "Edit", ES_LEFT | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL , 39, 114, 190, 10 END ///////////////////////////////////////////////////////////////////////////// diff --git a/Contrib/Makensisw/utils.cpp b/Contrib/Makensisw/utils.cpp index 90d38d91..03ba440d 100644 --- a/Contrib/Makensisw/utils.cpp +++ b/Contrib/Makensisw/utils.cpp @@ -209,7 +209,7 @@ void SetLogColor(enum LOGCOLOR lc) enum { em_seteditstyle = (WM_USER + 204), ses_extendbackcolor = 4 }; HWND hEd = GetDlgItem(g_sdata.hwnd, IDC_LOGWIN); bool sysclr = lc >= LC_SYSCOLOR || !ReadRegSettingDW(REGCOLORIZE, true); - COLORREF clrs[] = { RGB(0, 50, 0), RGB(210, 255, 210), RGB(50, 30, 0), RGB(255, 220, 190), RGB(50, 0, 0), RGB(255, 210, 210) }; + static const COLORREF clrs[] = { RGB(0, 50, 0), RGB(210, 255, 210), RGB(50, 30, 0), RGB(255, 220, 190), RGB(50, 0, 0), RGB(255, 210, 210) }; CHARFORMAT cf; cf.cbSize = sizeof(cf), cf.dwMask = CFM_COLOR; cf.dwEffects = sysclr ? CFE_AUTOCOLOR : 0; @@ -644,8 +644,8 @@ void FreeSpawn(PROCESS_INFORMATION *pPI, HANDLE hRd, HANDLE hWr) { CloseHandle(hWr); } BOOL InitSpawn(STARTUPINFO &si, HANDLE &hRd, HANDLE &hWr) { - OSVERSIONINFO osv = {sizeof(osv)}; - GetVersionEx(&osv); + OSVERSIONINFO osv; + GetVersionEx((osv.dwOSVersionInfoSize = sizeof(osv), &osv)); const bool winnt = VER_PLATFORM_WIN32_NT == osv.dwPlatformId; memset(&si, 0, sizeof(STARTUPINFO)); @@ -1063,6 +1063,7 @@ HMENU FindSubMenu(HMENU hMenu, UINT uId) static UINT DpiGetClassicSystemDpiY() { HDC hDC = GetDC(NULL); UINT dpi = GetDeviceCaps(hDC, LOGPIXELSY); ReleaseDC(NULL, hDC); return dpi; } static HRESULT WINAPI DpiFallbackGetDpiForMonitor(HMONITOR hMon, int MDT, UINT*pX, UINT*pY) { return (*pX = *pY = DpiGetClassicSystemDpiY(), S_OK); } static UINT WINAPI DpiFallbackGetDpiForWindow(HWND hWnd) { return 0; } +static HMONITOR WINAPI DpiFallbackMonitorFromWindow(HWND hWnd, DWORD Flags) { return NULL; } static UINT DpiNativeGetForMonitor(HMONITOR hMon) { @@ -1071,9 +1072,20 @@ static UINT DpiNativeGetForMonitor(HMONITOR hMon) UINT x, y, mdt_effective_dpi = 0; return SUCCEEDED(f(hMon, mdt_effective_dpi, &x, &y)) ? y : 0; } -static UINT DpiGetForMonitor(HWND hWnd) +UINT DpiGetForMonitor(HWND hWnd) { - HMONITOR hMon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); + HMONITOR(WINAPI*monitorfromwindow)(HWND, DWORD); + if (SupportsWNT4() || SupportsW95()) + { + static HMONITOR(WINAPI*g)(HWND, DWORD); + if (!g && !((FARPROC&)g = GetSysProcAddr("USER32", "MonitorFromWindow"))) g = DpiFallbackMonitorFromWindow; + monitorfromwindow = g; + } + else + { + monitorfromwindow = MonitorFromWindow; + } + HMONITOR hMon = monitorfromwindow(hWnd, MONITOR_DEFAULTTONEAREST); return hMon ? DpiNativeGetForMonitor(hMon) : (UINT)(UINT_PTR) hMon; } @@ -1106,6 +1118,13 @@ HFONT CreateFontHelper(INT_PTR Data, int Height, DWORD p1, LPCTSTR Face) return CreateFont(Height, 0, 0, 0, w, FALSE, FALSE, FALSE, cs, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, paf, Face); } +BOOL FillRectColor(HDC hDC, const RECT &Rect, COLORREF Color) +{ + COLORREF orgclr = SetBkColor(hDC, Color); + ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &Rect, _T(""), 0, NULL); + return TRUE|SetBkColor(hDC, orgclr); +} + static BOOL DrawHorzGradient(HDC hDC, const RECT&rect, COLOR16 r1, COLOR16 g1, COLOR16 b1, COLOR16 r2, COLOR16 g2, COLOR16 b2) { TRIVERTEX v[2] = { {rect.left, rect.top, r1, g1, b1, 0xffff}, {rect.right, rect.bottom, r2, g2, b2, 0xffff} }; @@ -1115,9 +1134,7 @@ static BOOL DrawHorzGradient(HDC hDC, const RECT&rect, COLOR16 r1, COLOR16 g1, C { if (!((FARPROC&)gf = GetSysProcAddr("MSIMG32", "GradientFill"))) { - COLORREF orgclr = SetBkColor(hDC, RGB((((UINT)r1+r2)/2)>>8, (((UINT)g1+g2)/2)>>8, (((UINT)b1+b2)/2)>>8)); - ExtTextOut(hDC, rect.left, rect.top, ETO_OPAQUE, &rect, _T(""), 0, NULL); // TODO: Actually try to draw a gradient - return TRUE|SetBkColor(hDC, orgclr); + return FillRectColor(hDC, rect, RGB((((UINT)r1+r2)/2)>>8, (((UINT)g1+g2)/2)>>8, (((UINT)b1+b2)/2)>>8)); // TODO: Actually try to draw a gradient } } else diff --git a/Contrib/Makensisw/utils.h b/Contrib/Makensisw/utils.h index f0a08553..ffff6609 100644 --- a/Contrib/Makensisw/utils.h +++ b/Contrib/Makensisw/utils.h @@ -106,11 +106,13 @@ inline HFONT CreateFontPt(HWND hWndDPI, int Height, WORD Weight, BYTE PitchAndFa { return CreateFont((INT_PTR) hWndDPI, CFF_DPIFROMHWND|CFF_DPIPT, Height, Weight, PitchAndFamily, CharSet, Face); } +BOOL FillRectColor(HDC hDC, const RECT &Rect, COLORREF Color); BOOL DrawHorzGradient(HDC hDC, LONG l, LONG t, LONG r, LONG b, COLORREF c1, COLORREF c2); inline long RectW(const RECT&r) { return r.right - r.left; } inline long RectH(const RECT&r) { return r.bottom - r.top; } long DlgUnitToPixelX(HWND hDlg, long x); long DlgUnitToPixelY(HWND hDlg, long y); +UINT DpiGetForMonitor(HWND hWnd); UINT DpiGetForWindow(HWND hWnd); int DpiScaleY(HWND hWnd, int Val); diff --git a/Contrib/Makensisw/wndspy.cpp b/Contrib/Makensisw/wndspy.cpp index fa253afe..7daeafe0 100644 --- a/Contrib/Makensisw/wndspy.cpp +++ b/Contrib/Makensisw/wndspy.cpp @@ -17,29 +17,81 @@ #include "resource.h" #define InitializeApiFuncWithFallback(mn, fn) { FARPROC f = GetSysProcAddr((mn), (#fn)); g_##fn = Compat_##fn; if (f) (FARPROC&) g_##fn = f; } +#define InitializeApiFuncEx(mn, fn, ptr) ( (FARPROC&)(g_##ptr) = GetSysProcAddr((mn), (#fn)) ) #define InitializeApiFunc(mn, fn) ( (FARPROC&)(g_##fn) = GetSysProcAddr((mn), (#fn)) ) #define CallApiFunc(fn) ( g_##fn ) #define HasApiFunc(fn) ( !!(g_##fn) ) INT_PTR(WINAPI*g_SetThreadDpiAwarenessContext)(INT_PTR); UINT(WINAPI*g_GetDpiForWindow)(HWND); +BOOL(WINAPI*g_LogicalToPhysicalPoint)(HWND hWnd, LPPOINT lpPoint); +BOOL(WINAPI*g_PhysicalToLogicalPoint)(HWND hWnd, LPPOINT lpPoint); typedef struct _DPI { enum { a_invalid = -1, a_unaware = 0, a_system = 1, a_pm = 2 }; - enum { ac_invalid = 0, ac_unaware = -1, ac_system = -2, ac_pm1 = -3, ac_pm2 = -4 }; + enum { ac_invalid = 0, ac_unaware = -1, ac_system = -2, ac_pm1 = -3, ac_pm2 = -4, ac_count = ac_pm2 * -1 }; static inline INT_PTR SetThreadDpiAwarenessContext(INT_PTR a1) { return g_SetThreadDpiAwarenessContext(a1); } static inline UINT GetDpiForWindow(HWND a1) { return HasApiFunc(GetDpiForWindow) ? CallApiFunc(GetDpiForWindow)(a1) : 0; } + static inline UINT GetDpiForMonitor(HWND hWnd) { return DpiGetForMonitor(hWnd); } } DPI; -static INT_PTR WINAPI Compat_SetThreadDpiAwarenessContext(INT_PTR AC) -{ - return 0; -} +static INT_PTR WINAPI Compat_SetThreadDpiAwarenessContext(INT_PTR AC) { return 0; } +static BOOL WINAPI Compat_LogicalToPhysicalPoint(HWND hWnd, LPPOINT lpPoint) { return TRUE; } +static BOOL WINAPI Compat_PhysicalToLogicalPoint(HWND hWnd, LPPOINT lpPoint) { return TRUE; } static void InitializeDpiApi() { InitializeApiFuncWithFallback("USER32", SetThreadDpiAwarenessContext); InitializeApiFunc("USER32", GetDpiForWindow); + InitializeApiFuncEx("USER32", LogicalToPhysicalPointForPerMonitorDPI, LogicalToPhysicalPoint); + if (!HasApiFunc(LogicalToPhysicalPoint)) InitializeApiFuncWithFallback("USER32", LogicalToPhysicalPoint); + InitializeApiFuncEx("USER32", PhysicalToLogicalPointForPerMonitorDPI, PhysicalToLogicalPoint); + if (!HasApiFunc(PhysicalToLogicalPoint)) InitializeApiFuncWithFallback("USER32", PhysicalToLogicalPoint); +} + +static BOOL LogicalToPhysical(HWND hWnd, POINT&Pt) { return CallApiFunc(LogicalToPhysicalPoint)(hWnd, &Pt); } +static BOOL PhysicalToLogical(HWND hWnd, POINT&Pt) { return CallApiFunc(PhysicalToLogicalPoint)(hWnd, &Pt); } + +static void LogicalToPhysical(HWND hWnd, RECT&Rect) +{ + POINT *p = (POINT*) &Rect; + LogicalToPhysical(hWnd, p[0]), LogicalToPhysical(hWnd, p[1]); +} +static void PhysicalToLogical(HWND hWnd, RECT&Rect) +{ + POINT *p = (POINT*) &Rect; + PhysicalToLogical(hWnd, p[0]), PhysicalToLogical(hWnd, p[1]); +} + +static BOOL GetPhysicalWindowRect(HWND hWnd, RECT&Rect, HWND hWndCaller) +{ + BOOL succ = GetWindowRect(hWnd, &Rect); + LogicalToPhysical(hWndCaller, Rect); + return succ; +} + +static BOOL GetPhysicalClientRect(HWND hWnd, RECT&Rect, HWND hWndCaller) +{ + BOOL succ = GetClientRect(hWnd, &Rect); + LogicalToPhysical(hWndCaller, Rect); + return succ; +} + +static inline void PhysicalToLogical(HWND hWnd, RECT&Rect, HWND hWndCaller) +{ + PhysicalToLogical(hWndCaller, Rect); +} + +static void ConvertLogicalToLogical(RECT&Rect, HWND hSrc, HWND hDst) +{ + LogicalToPhysical(hSrc, Rect), PhysicalToLogical(hDst, Rect); +} + +static BOOL GetLogicalWindowRect(HWND hWnd, RECT&Rect, HWND hWndCaller) +{ + BOOL succ = GetWindowRect(hWnd, &Rect); + if (succ) ConvertLogicalToLogical(Rect, hWndCaller, hWnd); + return succ; } static HWND GetParentWindow(HWND hWnd) @@ -50,8 +102,9 @@ static HWND GetParentWindow(HWND hWnd) typedef struct _DIALOGDATA { BOOL Dragging; - HWND hWndTarget; - int DialogAwarenessContext; + HWND hWndTarget, hWndOutline; + int DialogAwarenessContext; // Canonical DPI awareness context + _DIALOGDATA() : hWndOutline(0) {} static struct _DIALOGDATA* Get(HWND hDlg) { return (struct _DIALOGDATA*) GetWindowLongPtr(hDlg, DWLP_USER); } } DIALOGDATA; @@ -129,6 +182,36 @@ static BOOL IsHung(HWND hWnd) } } +static LRESULT CALLBACK OutlineWindowProc(HWND hWnd, UINT Msg, WPARAM WParam, LPARAM LParam) +{ + WNDPROC orgProc = (WNDPROC) GetWindowLongPtr(hWnd, GWLP_USERDATA); + switch(Msg) + { + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS wp = *(WINDOWPOS*) LParam; + int size = GetSystemMetrics(SM_CXBORDER) * 2, sizeX = size, sizeY = size; + if (sizeX >= wp.cx) sizeX = 1; + if (sizeY >= wp.cy) sizeY = 1; + HRGN hRgn = CreateRectRgn(0, 0, wp.cx, wp.cy); + HRGN hRgnInner = CreateRectRgn(sizeX, sizeY, wp.cx - sizeX, wp.cy - sizeY); + if (sizeX * 2 < wp.cx && sizeY * 2 < wp.cy) CombineRgn(hRgn, hRgn, hRgnInner, RGN_XOR); + DeleteObject(hRgnInner); + SetWindowRgn(hWnd, hRgn, TRUE); + } + return 0; + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(hWnd, &ps); + FillRectColor(hDC, ps.rcPaint, RGB(255, 0, 255)); + EndPaint(hWnd, &ps); + } + return 0; + } + return orgProc ? CallWindowProc(orgProc, hWnd, Msg, WParam, LParam) : DefWindowProc(hWnd, Msg, WParam, LParam); +} + static void SetDragSourceImage(HWND hDlg, INT_PTR Dragging = false) { HCURSOR hCur = Dragging ? NULL : LoadCursor(NULL, IDC_CROSS); @@ -159,35 +242,52 @@ static void ShowWindowInfo(HWND hDlg, HWND hWnd) SetDlgItemText(hDlg, IDC_WNDSTYLE, buf); RECT rw, rc; - GetWindowRect(hWnd, &rw), GetClientRect(hWnd, &rc); - wsprintf(buf, _T("%dx%d..%dx%d \x2248 %dx%d (%dx%d)"), rw.left, rw.top, rw.right, rw.bottom, rw.right - rw.left, rw.bottom - rw.top, rc.right - rc.left, rc.bottom - rc.top); // '\x2245' is not present on XP - SetDlgItemText(hDlg, IDC_WNDSIZE, hWnd ? buf : NULL); + GetLogicalWindowRect(hWnd, rw, hDlg); + wsprintf(buf, _T("%dx%d..%dx%d \x2248 %dx%d"), rw.left, rw.top, rw.right, rw.bottom, rw.right - rw.left, rw.bottom - rw.top); // '\x2245' is not present on XP + SetDlgItemText(hDlg, IDC_WNDLOGISIZE, hWnd ? buf : NULL); + + GetPhysicalWindowRect(hWnd, rw, hDlg); + GetPhysicalClientRect(hWnd, rc, hDlg); + wsprintf(buf, _T("%dx%d..%dx%d \x2248 %dx%d (%dx%d)"), rw.left, rw.top, rw.right, rw.bottom, rw.right - rw.left, rw.bottom - rw.top, rc.right - rc.left, rc.bottom - rc.top); + SetDlgItemText(hDlg, IDC_WNDPHYSSIZE, hWnd ? buf : NULL); *buf = _T('\0'); if (IsWindowUnicode(hWnd)) lstrcat(buf, _T("Unicode")); if (IsWindowVisible(hWnd)) lstrcat(*buf ? lstrcat(buf, _T(", ")) : buf, _T("Visible")); // IsWindowVisible is not exactly the same as WS_VISIBLE if (!(style & WS_DISABLED)) lstrcat(*buf ? lstrcat(buf, _T(", ")) : buf, _T("Enabled")); + if (GetWindow(hWnd, GW_OWNER)) lstrcat(*buf ? lstrcat(buf, _T(", ")) : buf, _T("Owned")); if (IsHung(hWnd)) lstrcat(*buf ? lstrcat(buf, _T(", ")) : buf, _T("Hung")); SetDlgItemText(hDlg, IDC_WNDINFO, hWnd ? buf : NULL); - UINT dpi = DPI::GetDpiForWindow(hWnd); - wsprintf(buf, dpi ? _T("%u") : _T("?"), dpi); + UINT dpi = DPI::GetDpiForWindow(hWnd), mondpi = DPI::GetDpiForMonitor(hWnd); +#ifndef _M_ARM64 // Not i386, AMD64 nor ARM(32-bit) + if (!dpi) + { + OSVERSIONINFO osv; + GetVersionEx((osv.dwOSVersionInfoSize = sizeof(osv), &osv)); + if (MAKELONG(osv.dwMinorVersion, osv.dwMajorVersion) < MAKELONG(3, 6)) + dpi = mondpi; // <= 8.0 has the same DPI on all monitors (blogs.windows.com/windowsexperience/2013/07/15/windows-8-1-dpi-scaling-enhancements/) + } +#endif + UINT cch = wsprintf(buf, dpi ? _T("%u") : _T("?"), dpi); + if ((DpiAwarePerMonitor() || dpi) && dpi != mondpi) wsprintf(buf + cch, _T(" (on %u)"), mondpi); // Don't display on >= 8.1 && < 10FU1607 (because we are not PMv1). GetDpiForWindow will also fail on those systems. SetDlgItemText(hDlg, IDC_WNDDPI, hWnd ? buf : NULL); } static INT_PTR CALLBACK SpyDlgProc(HWND hDlg, UINT Msg, WPARAM WParam, LPARAM LParam) { + enum { TID_OUTLINE = 1 }; DIALOGDATA*pDD = DIALOGDATA::Get(hDlg); switch(Msg) { case WM_INITDIALOG: SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR) (pDD = (DIALOGDATA*) LParam)); CenterOnParent(hDlg); - // On >= 10.1703 we are PMv2 and Windows scales our dialog and child controls. - // On >= 10.1607 && < 10.1703 we are System aware but try to upgrade this thread to + // On >= 10FU1703 we are PMv2 and Windows scales our dialog and child controls. + // On >= 10FU1607 && < 10FU1703 we are System aware but try to upgrade this thread to // PMv1 to reduce compatibility handling in other USER32 functions. We don't want - // the dialog HWND to be PMv1 because we are not going to reposition our controls. - // On < 10.1607 we only have the process awareness (not ideal). + // the dialog HWND to be PMv1 because we are not going to manually reposition our controls. + // On < 10FU1607 we only have the process awareness (not ideal). if (pDD->DialogAwarenessContext > DPI::ac_pm2) // Is the dialog AC < PMv2? Note: The canonical AC numbers are negative. DPI::SetThreadDpiAwarenessContext(DPI::ac_pm1); SendMessage(hDlg, WM_CAPTURECHANGED, 0, 0); @@ -225,6 +325,20 @@ static INT_PTR CALLBACK SpyDlgProc(HWND hDlg, UINT Msg, WPARAM WParam, LPARAM LP } break; case WM_LBUTTONUP: + if (pDD->Dragging && pDD->hWndTarget) + { + if (!pDD->hWndOutline) + { + pDD->hWndOutline = CreateWindowEx(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, WC_STATIC, NULL, WS_POPUP|WS_DISABLED|SS_BLACKRECT, 0, 0, 0, 0, hDlg, 0, 0, 0); + SetWindowLongPtr(pDD->hWndOutline, GWLP_USERDATA, SetWindowLongPtr(pDD->hWndOutline, GWLP_WNDPROC, (LONG_PTR) OutlineWindowProc)); + } + SetWindowPos(pDD->hWndOutline, HWND_BOTTOM, -32767, -32767, 1, 1, SWP_SHOWWINDOW|SWP_NOCOPYBITS|SWP_NOACTIVATE|SWP_NOOWNERZORDER); // MSDN says LogicalToPhysicalPoint requires a visible window + RECT r; + GetPhysicalWindowRect(pDD->hWndTarget, r, hDlg), PhysicalToLogical(pDD->hWndOutline, r, hDlg); + if (GetAncestor(pDD->hWndTarget, GA_ROOT) != hDlg) + SetWindowPos(pDD->hWndOutline, HWND_TOPMOST, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_SHOWWINDOW|SWP_NOCOPYBITS|SWP_NOACTIVATE|SWP_NOOWNERZORDER); + SetTimer(hDlg, TID_OUTLINE, 2 * 1000, NULL); + } ReleaseCapture(); break; case WM_CAPTURECHANGED: @@ -232,6 +346,13 @@ static INT_PTR CALLBACK SpyDlgProc(HWND hDlg, UINT Msg, WPARAM WParam, LPARAM LP pDD->Dragging = 0; SetDragSourceImage(hDlg, FALSE); break; + case WM_TIMER: + if (WParam == TID_OUTLINE) + { + KillTimer(hDlg, WParam); + ShowWindow(pDD->hWndOutline, SW_HIDE); + } + break; } return FALSE; } @@ -245,7 +366,7 @@ struct ScopedThreadDpiAwarenessContext { // Note: Assumes InitializeDpiApi() has }; ScopedThreadDpiAwarenessContext(List ACList) : m_OrgAC(0) { - for (UINT s = 4, list = ACList.GetBits(); (m_AC = -(int)s); --s) + for (UINT s = DPI::ac_count, list = ACList.GetBits(); (m_AC = -(int)s); --s) if ((1 << s) & list) if ((m_OrgAC = DPI::SetThreadDpiAwarenessContext((INT_PTR) m_AC))) break; diff --git a/Source/manifest.h b/Source/manifest.h index 0ed5f3ac..3d885b94 100644 --- a/Source/manifest.h +++ b/Source/manifest.h @@ -27,7 +27,7 @@ namespace manifest enum flags { disablewindowfiltering = 0x01, // Win8+ (Allow EnumWindows() to return Windows 8 immersive apps) - gdiscaling = 0x02, // Win10FU1703+ + gdiscaling = 0x02, // Win10FU1703+ blogs.windows.com/windowsdeveloper/2017/05/19/improving-high-dpi-experience-gdi-based-desktop-apps/ flags_default = 0 };