From bc4cef92d8efbf97a9215122abc2d7247c287f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Fri, 2 Sep 2022 20:16:04 +0200 Subject: Improve Window object. --- c/win32.h | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 c/win32.h (limited to 'c/win32.h') diff --git a/c/win32.h b/c/win32.h new file mode 100644 index 0000000..c4e57b7 --- /dev/null +++ b/c/win32.h @@ -0,0 +1,147 @@ +#ifndef WIN32_H +#define WIN32_H + +#include +#include +#include +#include + +/* Convert narrow to wide string. */ +std::wstring WideFromNarrow(const std::string_view src, const int cp = CP_UTF8); + +/* Run given procedure at creation of next window. */ +void WithNextWindow(void (*proc)(HWND)); + +/* Display message box centered in main window. */ +int EBMessageBox(std::wstring_view text, std::wstring_view data, UINT uType); + +/* Show message box for current exception. */ +void ShowException( + const wchar_t* fmt = L"An error occurred: %s", + const wchar_t* title = L"Error", + UINT uType = MB_ICONWARNING) noexcept; + +/* Retrieve mouse position relative to given window's client area. */ +int GetRelativeCursorPos(HWND hWnd, POINT* pt) noexcept; + +/* Cached values from GetSystemMetrics. */ +template auto Metric = GetSystemMetrics(I); + +struct WideException : public std::exception +{ + virtual const char* what() const noexcept = 0; + virtual const wchar_t* What() const noexcept = 0; +}; + +/* Exception for Windows API errors. */ +struct Win32Error : public WideException +{ + Win32Error(DWORD code = GetLastError(), HMODULE hModule = nullptr) noexcept; + ~Win32Error() noexcept; + const char* what() const noexcept override; + const wchar_t* What() const noexcept override; + DWORD code; +private: + HMODULE hModule; + char* m_szMsg = nullptr; + wchar_t* m_wszMsg = nullptr; +}; + +/* Exception for extended Wininet errors. */ +struct InternetError : public WideException +{ + InternetError(DWORD codeSystem = GetLastError()); + ~InternetError() noexcept; + const char* what() const noexcept override; + const wchar_t* What() const noexcept override; + DWORD code; +private: + char* m_szMsg = nullptr; + wchar_t* m_wszMsg = nullptr; +}; + +/* Wrapper for loading and freeing dynamically linked libraries. */ +struct Library +{ + /* Non-throwing named constructor. */ + static std::optional Maybe(const wchar_t* lib) noexcept; + + Library(const wchar_t* lib); + ~Library() noexcept; + + template T* GetProcAddress(const char* szProc) noexcept; +private: + /* Non-throwing constructor used by Maybe. */ + Library(HMODULE hModule) noexcept; + HMODULE m_hModule; +}; + +template +T* Library::GetProcAddress(const char* const szProc) noexcept +{ + return (T*)(void*)::GetProcAddress(m_hModule, szProc); +} + +/* Check result of Windows API call, throwing error on null. */ +template +inline T Require(const T x) +{ + if (!x) throw Win32Error(); + return x; +} + +/* Check result of Windows API call, showing a warning on null. */ +template +inline T Prefer(const T x) +{ + if (!x) { + EBMessageBox(Win32Error().What(), L"System Error", MB_ICONWARNING); + return (T)0; + } + return x; +} + +/* Return integer scaled for current DPI. */ +inline int Dpi(const int i) +{ + extern int g_dpi; + return MulDiv(i, g_dpi, 96); +} + +/* Retrieve given window's rectangle relative to parent's client area. */ +inline BOOL GetRelativeRect(const HWND hWnd, RECT* const rr) +{ + if (!GetClientRect(hWnd, rr)) return 0; + return MapWindowPoints(hWnd, GetParent(hWnd), reinterpret_cast(rr), 2); +} + +inline BOOL SetWindowRect(const HWND hWnd, + const long left, const long top, const long right, const long bottom) +{ + return MoveWindow(hWnd, + left, top, + right-left, bottom-top, + TRUE); +} + +inline BOOL SetWindowRect(const HWND hWnd, const RECT r) +{ + return SetWindowRect(hWnd, r.left, r.top, r.right, r.bottom); +} + +/* The following two functions call uxtheme.dll functions, if + * uxtheme.dll exists, and otherwise do nothing. */ +inline BOOL EBIsThemeActive() +{ + extern BOOL (__stdcall *IsThemeActive)(); + return IsThemeActive? IsThemeActive(): 0; +} + +inline HRESULT EBSetWindowTheme(const HWND hWnd, const wchar_t* const pszSubAppName, + const wchar_t* const pszSubIdList) +{ + extern HRESULT (__stdcall *SetWindowTheme)(HWND, const wchar_t*, const wchar_t*); + return SetWindowTheme? SetWindowTheme(hWnd, pszSubAppName, pszSubIdList): 0; +} + +#endif -- cgit v1.2.3