aboutsummaryrefslogtreecommitdiff
path: root/c/common.h
blob: 3f27ba4d95930d6e1ece386d15ac4c526e9f0970 (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
138
139
140
141
142
143
#ifndef COMMON_H
#define COMMON_H

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

#ifdef UNICODE
#define WA "W"
#else
#define WA "A"
#endif

template <typename T> std::basic_string<T> BstrFromSz(const char* sz, int iCp = CP_UTF8);
int EBMessageBox(const TCHAR* tszText, const TCHAR* tszCaption, unsigned uType);

/* Conditionally choose between two values. */
template <bool B, typename X, typename Y>
constexpr std::enable_if_t<B == true, X> choose(X x, Y) { return x; }
template <bool B, typename X, typename Y>
constexpr std::enable_if_t<B == false, Y> choose(X, Y y) { return y; }

/* Conditionally choose between ANSI and wide string literal. */
#define AWTEXT(t, s) choose<std::is_same_v<t, wchar_t>>(L"" s, s)

/* Conditionally choose between ANSI and wide Windows API function. */
#define AWFUN(t, f) choose<std::is_same_v<t, wchar_t>>(f##W, f##A)

struct Win32Error : public std::exception
{
	Win32Error();
	Win32Error(DWORD dwErr);
	~Win32Error();
	template <typename T = char> const T* what() const noexcept;
	DWORD dwErr;
private:
	char* m_szMsg = NULL;
	wchar_t* m_wszMsg = NULL;
};

template <typename T>
const T* Win32Error::what() const noexcept
{
	TCHAR* tszMsg = choose<std::is_same_v<T, wchar_t>>(m_wszMsg, m_szMsg);
	if (!tszMsg)
		AWFUN(T, FormatMessage)(
		    FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
		    NULL,
		    dwErr,
		    MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
		    (TCHAR*)&tszMsg,
		    0, NULL);
	return tszMsg;
}

struct Library
{
	Library(const TCHAR* tszLibrary);
	~Library();
	template <class T> T* GetProcAddress(const char* szProc);
private:
	HMODULE m_hModule;
};

template <typename T>
T* Library::GetProcAddress(const char* const szProc)
{
	return (T*)(void*)::GetProcAddress(m_hModule, szProc);
}

/* Create and return an object of type C. If construction fails,
 * return nothing. The returned value must be checked before being
 * used, as dereferencing is undefined if the value is empty. */
template <typename T, typename... U>
std::optional<T> maybe_make(U... xs)
{
	try {
		return T(xs...);
	} catch (...) {
		return {};
	}
}

/* Variable template for caching values from GetSystemMetrics. */
template <int I>
const auto Metric = GetSystemMetrics(I);

/* 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<TCHAR>(),
		    TEXT("System Error"), MB_ICONWARNING);
		return (T)NULL;
	}
	return x;
}

/* Return integer scaled for current DPI. */
inline int Dpi(const int i)
{
	extern int g_iDPI;
	return MulDiv(i, g_iDPI, 96);
}

inline int Cmp(const int a, const int b)
{
	if (a == b) return 0;
	if (a > b) return 1;
	return -1;
}

/* Get window rectangle relative to parent. */
inline BOOL GetRelativeRect(const HWND hWnd, RECT* const pRr)
{
	if (!GetClientRect(hWnd, pRr)) return 0;
	return MapWindowPoints(hWnd, GetParent(hWnd), (POINT*)pRr, 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);
}

#endif