Mercurial > foo_out_sdl
view foosdk/sdk/libPPUI/win32_utility.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
line wrap: on
line source
#include "stdafx.h" #include "win32_utility.h" #include "win32_op.h" #include <list> SIZE QueryContextDPI(HDC dc) { return {GetDeviceCaps(dc,LOGPIXELSX), GetDeviceCaps(dc,LOGPIXELSY)}; } unsigned QueryScreenDPI(HWND wnd) { HDC dc = GetDC(wnd); unsigned ret = GetDeviceCaps(dc, LOGPIXELSY); ReleaseDC(wnd, dc); return ret; } unsigned QueryScreenDPI_X(HWND wnd) { HDC dc = GetDC(wnd); unsigned ret = GetDeviceCaps(dc, LOGPIXELSX); ReleaseDC(wnd, dc); return ret; } unsigned QueryScreenDPI_Y(HWND wnd) { HDC dc = GetDC(wnd); unsigned ret = GetDeviceCaps(dc, LOGPIXELSY); ReleaseDC(wnd, dc); return ret; } SIZE QueryScreenDPIEx(HWND wnd) { HDC dc = GetDC(wnd); SIZE ret = { GetDeviceCaps(dc,LOGPIXELSX), GetDeviceCaps(dc,LOGPIXELSY) }; ReleaseDC(wnd, dc); return ret; } void HeaderControl_SetSortIndicator(HWND header_, int column, bool isUp) { CHeaderCtrl header(header_); const int total = header.GetItemCount(); for (int walk = 0; walk < total; ++walk) { HDITEM item = {}; item.mask = HDI_FORMAT; if (header.GetItem(walk, &item)) { auto newFormat = item.fmt; newFormat &= ~(HDF_SORTUP | HDF_SORTDOWN); if (walk == column) { newFormat |= isUp ? HDF_SORTUP : HDF_SORTDOWN; } if (newFormat != item.fmt) { item.fmt = newFormat; header.SetItem(walk, &item); } } } } HINSTANCE GetThisModuleHandle() { return (HINSTANCE)_AtlBaseModule.m_hInst; } WinResourceRef_t WinLoadResource(HMODULE hMod, const TCHAR * name, const TCHAR * type, WORD wLang) { SetLastError(0); HRSRC res = wLang ? FindResourceEx(hMod, type, name, wLang) : FindResource(hMod, name, type); if ( res == NULL ) WIN32_OP_FAIL(); SetLastError(0); HGLOBAL hglob = LoadResource(hMod, res); if ( hglob == NULL ) WIN32_OP_FAIL(); SetLastError(0); void * ptr = LockResource(hglob); if ( ptr == nullptr ) WIN32_OP_FAIL(); WinResourceRef_t ref; ref.ptr = ptr; ref.bytes = SizeofResource(hMod, res); return ref; } CComPtr<IStream> WinLoadResourceAsStream(HMODULE hMod, const TCHAR * name, const TCHAR * type, WORD wLang) { auto res = WinLoadResource(hMod, name, type, wLang ); auto str = SHCreateMemStream( (const BYTE*) res.ptr, (UINT) res.bytes ); if ( str == nullptr ) throw std::bad_alloc(); CComPtr<IStream> ret; ret.Attach( str ); return ret; } UINT GetFontHeight(HFONT font) { UINT ret; HDC dc = CreateCompatibleDC(0); SelectObject(dc, font); ret = GetTextHeight(dc); DeleteDC(dc); return ret; } UINT GetTextHeight(HDC dc) { TEXTMETRIC tm; POINT pt[2]; GetTextMetrics(dc, &tm); pt[0].x = 0; pt[0].y = tm.tmHeight; pt[1].x = 0; pt[1].y = 0; LPtoDP(dc, pt, 2); int ret = pt[0].y - pt[1].y; return ret > 1 ? (unsigned)ret : 1; } LRESULT RelayEraseBkgnd(HWND p_from, HWND p_to, HDC p_dc) { CDCHandle dc(p_dc); DCStateScope scope(dc); CRect client; if (GetClientRect(p_from, client)) { dc.IntersectClipRect(client); } LRESULT status; POINT pt = { 0, 0 }, pt_old = { 0,0 }; MapWindowPoints(p_from, p_to, &pt, 1); OffsetWindowOrgEx(p_dc, pt.x, pt.y, &pt_old); status = SendMessage(p_to, WM_ERASEBKGND, (WPARAM)p_dc, 0); SetWindowOrgEx(p_dc, pt_old.x, pt_old.y, 0); return status; } static LRESULT CALLBACK EraseHandlerProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg == WM_ERASEBKGND) { HWND wndTarget = reinterpret_cast<HWND>(dwRefData); PFC_ASSERT(wndTarget != NULL); return RelayEraseBkgnd(hWnd, wndTarget, (HDC)wParam); } return DefSubclassProc(hWnd, uMsg, wParam, lParam); } static LRESULT CALLBACK CtlColorProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { switch (uMsg) { case WM_CTLCOLORMSGBOX: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: return SendMessage(GetParent(hWnd), uMsg, wParam, lParam); default: return DefSubclassProc(hWnd, uMsg, wParam, lParam); } } void InjectEraseHandler(HWND wnd, HWND sendTo) { PFC_ASSERT(sendTo != NULL); WIN32_OP_D(SetWindowSubclass(wnd, EraseHandlerProc, 0, reinterpret_cast<DWORD_PTR>(sendTo))); } void InjectParentEraseHandler(HWND wnd) { InjectEraseHandler(wnd, GetParent(wnd)); } void InjectParentCtlColorHandler(HWND wnd) { WIN32_OP_D(SetWindowSubclass(wnd, CtlColorProc, 0, 0)); } static LRESULT CALLBACK BounceNextDlgCtlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { if (uMsg == WM_NEXTDLGCTL) { return ::SendMessage((HWND)dwRefData, uMsg, wParam, lParam); } return DefSubclassProc(hWnd, uMsg, wParam, lParam); } void BounceNextDlgCtl(HWND wnd, HWND wndTo) { ::SetWindowSubclass(wnd, BounceNextDlgCtlProc, 0, (DWORD_PTR)wndTo); } pfc::string8 EscapeTooltipText(const char * src) { pfc::string8 out; while (*src) { if (*src == '&') { out.add_string("&&&"); src++; while (*src == '&') { out.add_string("&&"); src++; } } else out.add_byte(*(src++)); } return out; } bool IsMenuNonEmpty(HMENU menu) { unsigned n, m = GetMenuItemCount(menu); for (n = 0; n < m; n++) { if (GetSubMenu(menu, n)) return true; if (!(GetMenuState(menu, n, MF_BYPOSITION)&MF_SEPARATOR)) return true; } return false; } void SetDefaultMenuItem(HMENU p_menu, unsigned p_id) { MENUITEMINFO info = { sizeof(info) }; info.fMask = MIIM_STATE; GetMenuItemInfo(p_menu, p_id, FALSE, &info); info.fState |= MFS_DEFAULT; SetMenuItemInfo(p_menu, p_id, FALSE, &info); } static bool FetchWineInfoAppend(pfc::string_base & out) { typedef const char *(__cdecl *t_wine_get_build_id)(void); typedef void(__cdecl *t_wine_get_host_version)(const char **sysname, const char **release); const HMODULE ntdll = GetModuleHandle(_T("ntdll.dll")); if (ntdll == NULL) return false; t_wine_get_build_id wine_get_build_id; t_wine_get_host_version wine_get_host_version; wine_get_build_id = (t_wine_get_build_id)GetProcAddress(ntdll, "wine_get_build_id"); wine_get_host_version = (t_wine_get_host_version)GetProcAddress(ntdll, "wine_get_host_version"); if (wine_get_build_id == NULL || wine_get_host_version == NULL) { if (GetProcAddress(ntdll, "wine_server_call") != NULL) { out << "wine (unknown version)"; return true; } return false; } const char * sysname = NULL; const char * release = NULL; wine_get_host_version(&sysname, &release); out << wine_get_build_id() << ", on: " << sysname << " / " << release; return true; } static void GetOSVersionStringAppend(pfc::string_base & out) { if (FetchWineInfoAppend(out)) return; OSVERSIONINFO ver = {}; ver.dwOSVersionInfoSize = sizeof(ver); WIN32_OP_D(GetVersionEx(&ver)); SYSTEM_INFO info = {}; GetNativeSystemInfo(&info); out << "Windows " << (int)ver.dwMajorVersion << "." << (int)ver.dwMinorVersion << "." << (int)ver.dwBuildNumber; if (ver.szCSDVersion[0] != 0) out << " " << pfc::stringcvt::string_utf8_from_os(ver.szCSDVersion, PFC_TABSIZE(ver.szCSDVersion)); switch (info.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_AMD64: out << " x64"; break; case PROCESSOR_ARCHITECTURE_IA64: out << " IA64"; break; case PROCESSOR_ARCHITECTURE_INTEL: out << " x86"; break; case PROCESSOR_ARCHITECTURE_ARM64: out << " ARM64"; break; } } void GetOSVersionString(pfc::string_base & out) { out.reset(); GetOSVersionStringAppend(out); } WORD GetOSVersionCode() { OSVERSIONINFO ver = {sizeof(ver)}; WIN32_OP_D(GetVersionEx(&ver)); DWORD ret = ver.dwMinorVersion; ret += ver.dwMajorVersion << 8; return (WORD)ret; } bool IsWine() { static bool ret = [] { HMODULE module = GetModuleHandle(_T("ntdll.dll")); if (!module) return false; return GetProcAddress(module, "wine_server_call") != NULL; } (); return ret; } static BOOL CALLBACK EnumChildWindowsProc(HWND w, LPARAM p) { auto f = reinterpret_cast<std::function<void(HWND)>*>(p); (*f)(w); return TRUE; } void EnumChildWindows(HWND w, std::function<void(HWND)> f) { ::EnumChildWindows(w, EnumChildWindowsProc, reinterpret_cast<LPARAM>(&f)); } void EnumChildWindowsHere(HWND parent, std::function<void(HWND)> f) { for (HWND walk = GetWindow(parent, GW_CHILD); walk != NULL; walk = GetWindow(walk, GW_HWNDNEXT)) { f(walk); } } static DWORD Win10BuildNumber_() { OSVERSIONINFO ver = { sizeof(ver) }; WIN32_OP_D(GetVersionEx(&ver)); return ver.dwMajorVersion == 10 ? ver.dwBuildNumber : 0; } DWORD Win10BuildNumber() { static DWORD b = Win10BuildNumber_(); return b; } #include "hookWindowMessages.h" #include <algorithm> namespace { class CWindowHook_Map : public CWindowImpl<CWindowHook_Map, CWindow> { public: CMessageMap* m_target = nullptr; DWORD m_targetID = 0; std::vector< DWORD > m_messages; void setup(std::initializer_list<DWORD>&& arg) { m_messages = std::move(arg); std::sort(m_messages.begin(), m_messages.end()); } bool isMsgWanted(DWORD msg) const { return std::binary_search(m_messages.begin(), m_messages.end(), msg); } BEGIN_MSG_MAP(CWindowHook) if (isMsgWanted(uMsg)) { CHAIN_MSG_MAP_ALT_MEMBER((*m_target), m_targetID); } END_MSG_MAP() }; class CWindowHook_Proc : public CWindowImpl<CWindowHook_Proc, CWindow> { public: CWindowHook_Proc(PP::messageHook_t proc) : m_proc(proc) {} const PP::messageHook_t m_proc; BEGIN_MSG_MAP(CWindowHook) if (m_proc(hWnd, uMsg, wParam, lParam, lResult)) return TRUE; END_MSG_MAP() }; } void PP::hookWindowMessages(HWND wnd, CMessageMap* target, DWORD targetID, std::initializer_list<DWORD>&& msgs) { auto obj = PP::subclassThisWindow< CWindowHook_Map >(wnd); obj->m_target = target; obj->m_targetID = targetID; obj->setup(std::move(msgs)); } void PP::hookWindowMessages(HWND wnd, messageHook_t h) { PP::subclassThisWindow< CWindowHook_Proc >(wnd, h); } namespace PP { static LONG regReadHelper(HKEY root, const wchar_t* path, const wchar_t* value, LONG def) { wchar_t buf[64] = {}; DWORD cb = (DWORD)((std::size(buf) - 1) * sizeof(buf[0])); if (RegGetValue(root, path, value, RRF_RT_REG_SZ, NULL, buf, &cb) == 0) { return _wtol(buf); } return def; } static SIZE querySystemDragThreshold() { constexpr DWORD def = 1; static constexpr wchar_t path[] = L"Control Panel\\Desktop"; return { (LONG)regReadHelper(HKEY_CURRENT_USER, path, L"DragWidth", def), (LONG)regReadHelper(HKEY_CURRENT_USER, path, L"DragHeight", def) }; } SIZE queryDragThresholdForDPI(SIZE dpi) { PFC_ASSERT(dpi.cx > 0 && dpi.cy > 0); static SIZE sys = {}; if ( sys.cx == 0 || sys.cy == 0 ) sys = querySystemDragThreshold(); return { MulDiv(sys.cx, dpi.cx, 96), MulDiv(sys.cy, dpi.cy, 96) }; } SIZE queryDragThreshold(HWND wndFor) { return queryDragThresholdForDPI(QueryScreenDPIEx(wndFor)); } }
