#ifndef WIN_H #define WIN_H #include #include #include #include /* 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 (*IsThemeActive)(); return IsThemeActive? IsThemeActive(): 0; } inline BOOL EBSetWindowTheme(const HWND hWnd, const wchar_t* const pszSubAppName, const wchar_t* const pszSubIdList) { extern BOOL (*SetWindowTheme)(HWND, const wchar_t*, const wchar_t*); return SetWindowTheme? SetWindowTheme(hWnd, pszSubAppName, pszSubIdList): 0; } inline void Status(const wchar_t* msg, unsigned short i = 0) { extern HWND g_hWndStatus; SendMessage(g_hWndStatus, SB_SETTEXT, MAKEWPARAM(i,0), reinterpret_cast(msg)); } #endif