aboutsummaryrefslogtreecommitdiff
path: root/c/win.h
blob: 26a21b213790265012d665e4808cc29abae0032e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#ifndef WIN_H
#define WIN_H

#include <optional>
#include <string_view>
#include <windows.h>

/* 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, const wchar_t* title, 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 <int I> 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<Library> Maybe(const wchar_t* lib) noexcept;

	Library(const wchar_t* lib);
	~Library() noexcept;

	template <class T> T* GetProcAddress(const char* szProc) noexcept;
private:
	/* Non-throwing constructor used by Maybe. */
	Library(HMODULE hModule) noexcept;
	HMODULE m_hModule;
};

template <typename T>
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 <typename T>
inline T Require(const T x)
{
	if (!x) throw Win32Error();
	return x;
}

/* Check result of Windows API call, showing a warning on null. */
template <typename T>
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<POINT*>(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 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;
}

#endif