From 805cc4cec440525629758af918d50a850209ec0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Tue, 9 Aug 2022 21:49:18 +0200 Subject: Add WithNextWindow function. I'm not sure if this clarifies or complicates the control flow. My hope is the former. --- c/win.cpp | 130 ++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 46 deletions(-) (limited to 'c/win.cpp') diff --git a/c/win.cpp b/c/win.cpp index 593b340..a68d5b3 100644 --- a/c/win.cpp +++ b/c/win.cpp @@ -3,6 +3,90 @@ #include "win.h" +void WithNextWindow(void (*proc)(HWND)) +{ + /* WithNextWindow uses a CBT hook to call an arbitrary + * procedure just before the creation of the next window. The + * hook is removed as soon as HCBT_CREATEWND is received. + * Thus, proc is guaranteed to be executed only once. Note + * that static storage must be used, as SetWindowHookEx cannot + * accept a capturing lambda as the hook procedure. */ + + static __thread auto procNext = proc; + static __thread HHOOK hHook = Require(SetWindowsHookEx(WH_CBT, [](const int nCode, + const WPARAM wParam, const LPARAM lParam) -> LRESULT CALLBACK + { + if (nCode == HCBT_CREATEWND) { + Require(UnhookWindowsHookEx(hHook)); + procNext(reinterpret_cast(wParam)); + return 0; + } else + return CallNextHookEx(0, nCode, wParam, lParam); + }, nullptr, GetCurrentThreadId())); +} + +/* Display next created window in the center of given window. */ +static void CenterNextWindow(HWND hWnd) +{ + if (!hWnd) + return; + + /* CenterNextWindow employs a trick similar to that above. + * Note, however, that repositioning does not work unless it + * is delayed until the new window is activated. This + * complicates the code somewhat. */ + + static __thread HWND hWndParent = hWnd; + static __thread HWND hWndNext = nullptr; + static __thread HHOOK hHook = Require(SetWindowsHookEx(WH_CBT, [](const int nCode, + const WPARAM wParam, const LPARAM lParam) noexcept -> LRESULT CALLBACK + { + if (!hWndNext && nCode == HCBT_CREATEWND) { + hWndNext = reinterpret_cast(wParam); + return 0; + } else if (nCode == HCBT_ACTIVATE + && reinterpret_cast(wParam) == hWndNext) { + Require(UnhookWindowsHookEx(hHook)); + + long lStyle = GetWindowLong(hWndNext, GWL_STYLE); + if (!(lStyle & WS_POPUP)) return 0; + + RECT rcMain, rcMsg; + GetWindowRect(hWndParent, &rcMain); + GetWindowRect(hWndNext, &rcMsg); + SetWindowPos(hWndNext, nullptr, + rcMain.left+(rcMain.right-rcMain.left)/2-(rcMsg.right-rcMsg.left)/2, + rcMain.top+(rcMain.bottom-rcMain.top)/2-(rcMsg.bottom-rcMsg.top)/2, + -1, -1, + SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE); + + return 0; + } else + return CallNextHookEx(0, nCode, wParam, lParam); + }, nullptr, GetCurrentThreadId())); +} + +int EBMessageBox(const wchar_t* const wszText, const wchar_t* const wszCaption, const UINT uType) +{ + extern HWND g_hWnd; + CenterNextWindow(g_hWnd); + return MessageBox(g_hWnd, wszText, wszCaption, uType); +} + +int GetRelativeCursorPos(const HWND hWnd, POINT* const pt) noexcept +{ + RECT rc; + if (!GetClientRect(hWnd, &rc)) return 0; + SetLastError(ERROR_SUCCESS); + if (!MapWindowPoints(hWnd, nullptr, (POINT*)&rc, 2)) return 0; + + POINT ptMouse; + if (!GetCursorPos(&ptMouse)) return 0; + pt->x = ptMouse.x-rc.left; + pt->y = ptMouse.y-rc.top; + return 1; +} + Win32Error::Win32Error() noexcept : code(GetLastError()) {} @@ -64,49 +148,3 @@ Library::~Library() { FreeLibrary(m_hModule); } - -int EBMessageBox(const wchar_t* const wszText, const wchar_t* const wszCaption, const UINT uType) -{ - extern HWND g_hWnd; - - auto proc = [](const int nCode, const WPARAM wParam, const LPARAM lParam) noexcept - -> LRESULT CALLBACK - { - if (!g_hWnd || nCode < 0 || nCode != HCBT_ACTIVATE) - return CallNextHookEx(0, nCode, wParam, lParam); - - HWND hWnd = reinterpret_cast(wParam); - long lStyle = GetWindowLong(hWnd, GWL_STYLE); - if (!(lStyle & WS_POPUP)) return 0; - - RECT rcMain, rcMsg; - GetWindowRect(g_hWnd, &rcMain); - GetWindowRect(hWnd, &rcMsg); - SetWindowPos(hWnd, nullptr, - rcMain.left+(rcMain.right-rcMain.left)/2-(rcMsg.right-rcMsg.left)/2, - rcMain.top+(rcMain.bottom-rcMain.top)/2-(rcMsg.bottom-rcMsg.top)/2, - -1, -1, - SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE); - - return 0; - }; - - HHOOK hHook = Require(SetWindowsHookEx(WH_CBT, proc, nullptr, GetCurrentThreadId())); - int r = MessageBox(g_hWnd, wszText, wszCaption, uType); - Require(UnhookWindowsHookEx(hHook)); - return r; -} - -int GetRelativeCursorPos(const HWND hWnd, POINT* const pt) -{ - RECT rc; - if (!GetClientRect(hWnd, &rc)) return 0; - SetLastError(ERROR_SUCCESS); - if (!MapWindowPoints(hWnd, nullptr, (POINT*)&rc, 2)) return 0; - - POINT ptMouse; - if (!GetCursorPos(&ptMouse)) return 0; - pt->x = ptMouse.x-rc.left; - pt->y = ptMouse.y-rc.top; - return 1; -} -- cgit v1.2.3