aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2022-09-07 00:40:26 +0200
committerJohn Ankarström <john@ankarstrom.se>2022-09-07 00:40:26 +0200
commit2f7b69d6d4cf18ca9ca04d9a44aaa6871ce51160 (patch)
treed016a9456621b91ca902f0c1caf48468e899a553
parent5b1a07607ba593050e37598f731f833b6faabee4 (diff)
downloadEpisodeBrowser-2f7b69d6d4cf18ca9ca04d9a44aaa6871ce51160.tar.gz
Improve error handling.
-rw-r--r--c/data.cpp5
-rw-r--r--c/drag.cpp12
-rw-r--r--c/episodelistview.cpp8
-rw-r--r--c/err.cpp7
-rw-r--r--c/err.h32
-rw-r--r--c/listview.cpp11
-rw-r--r--c/main.cpp127
-rw-r--r--c/util.h11
-rw-r--r--c/win32.cpp107
-rw-r--r--c/win32.h54
-rw-r--r--c/window.h10
11 files changed, 161 insertions, 223 deletions
diff --git a/c/data.cpp b/c/data.cpp
index a75111a..32e059f 100644
--- a/c/data.cpp
+++ b/c/data.cpp
@@ -118,7 +118,7 @@ void WaitFor(Window& window, void (*f)(unsigned char*))
static auto procThread = [](void (*f)(unsigned char*)) noexcept -> void
{
- SET_TERMINATE;
+ std::set_terminate(OnTerminate);
while (!(sig & READY))
Sleep(100);
sig = 0;
@@ -152,7 +152,8 @@ void WaitFor(Window& window, void (*f)(unsigned char*))
s_window = &window;
std::thread(procThread, f).detach();
s_window->Status(L".", 1);
- Prefer(iTimer = SetTimer(nullptr, iTimer, 500, procTimer));
+ if (!(iTimer = SetTimer(nullptr, iTimer, 500, procTimer)))
+ throw Err(WINDOWS, L"Timer could not be started: %s");
}
void FetchData(unsigned char* sig)
diff --git a/c/drag.cpp b/c/drag.cpp
index b92429a..1622653 100644
--- a/c/drag.cpp
+++ b/c/drag.cpp
@@ -24,7 +24,8 @@ bool Dragger::IsDown() const
bool Dragger::HandleLButtonDown()
{
POINT pt;
- Require(GetRelativeCursorPos(parent.hWnd, &pt));
+ if (!GetRelativeCursorPos(parent.hWnd, &pt))
+ throw Err(WINDOWS, L"Mouse cursor position could not be retrieved: %s");
if (!InDragArea(pt.x, pt.y)) return false;
if (IsDouble(GetMessageTime(), pt)) {
@@ -39,7 +40,8 @@ bool Dragger::HandleLButtonDown()
bool Dragger::HandleSetCursor()
{
POINT pt;
- Require(GetRelativeCursorPos(parent.hWnd, &pt));
+ if (!GetRelativeCursorPos(parent.hWnd, &pt))
+ throw Err(WINDOWS, L"Mouse cursor position could not be retrieved: %s");
extern HCURSOR g_hcSizeNs;
bool r = true;
@@ -60,7 +62,8 @@ bool Dragger::HandleSetCursor()
bool DlvDragger::InDragArea(const int x, const int y) const
{
RECT rrDlv;
- Require(GetRelativeRect(parent.dlv.hWnd, &rrDlv));
+ if (!GetRelativeRect(parent.dlv.hWnd, &rrDlv))
+ throw Err(WINDOWS, L"Data list view rectangle could not be retrieved: %s");
const int pad = EBIsThemeActive()? Dpi(6): 0;
const int extra = EBIsThemeActive()? 0: Dpi(2);
@@ -72,7 +75,8 @@ bool DlvDragger::InDragArea(const int x, const int y) const
void DlvDragger::Drag(const int, const int y) const
{
RECT rrDlv;
- Require(GetRelativeRect(parent.dlv.hWnd, &rrDlv));
+ if (!GetRelativeRect(parent.dlv.hWnd, &rrDlv))
+ throw Err(WINDOWS, L"Data list view rectangle could not be retrieved: %s");
if (y < Dpi(50) || y > rrDlv.bottom-Dpi(20)) return;
diff --git a/c/episodelistview.cpp b/c/episodelistview.cpp
index b683114..db67ca9 100644
--- a/c/episodelistview.cpp
+++ b/c/episodelistview.cpp
@@ -162,7 +162,8 @@ LRESULT EpisodeListView::HandleNotify(const LPARAM lParam)
const ElvDataA& e = parent.fvElv.At(nm->nmcd.lItemlParam-1);
if (!e.bWatched) {
extern HFONT g_hfBold;
- Require(SelectObject(nm->nmcd.hdc, g_hfBold));
+ if (!SelectObject(nm->nmcd.hdc, g_hfBold))
+ throw Err(WINDOWS, L"Bold font could not be selected: %s");
return CDRF_NEWFONT;
}
break;
@@ -183,8 +184,9 @@ LRESULT EpisodeListView::HandleNotify(const LPARAM lParam)
case NM_RCLICK:
{
const DWORD pos = GetMessagePos();
- Require(TrackPopupMenu(parent.hMenuPopup, TPM_RIGHTBUTTON,
- LOWORD(pos), HIWORD(pos), 0, parent.hWnd, nullptr));
+ if (!TrackPopupMenu(parent.hMenuPopup, TPM_RIGHTBUTTON,
+ LOWORD(pos), HIWORD(pos), 0, parent.hWnd, nullptr))
+ throw Err(WINDOWS, L"Context menu could not be opened: %s");
return 0;
}
diff --git a/c/err.cpp b/c/err.cpp
index fd35ddd..77bf394 100644
--- a/c/err.cpp
+++ b/c/err.cpp
@@ -77,11 +77,14 @@ std::wstring What(std::exception_ptr ex)
std::rethrow_exception(ex);
} catch (const Err& e) {
return e.what;
- } catch (const WideException& e) {
- return e.What();
} catch (const std::exception& e) {
return WideFromNarrow(e.what());
} catch (...) {
return L"Unknown exception";
}
}
+
+void OnTerminate()
+{
+ EBMessageBox(What(), L"Fatal Error", MB_ICONERROR);
+}
diff --git a/c/err.h b/c/err.h
index d4a9976..4c6e829 100644
--- a/c/err.h
+++ b/c/err.h
@@ -4,6 +4,8 @@
#include <exception>
#include <string>
+#include "win32.h"
+
enum ErrType : unsigned char
{
GENERIC,
@@ -22,4 +24,34 @@ struct Err
/* Return a wide string describing exception. */
std::wstring What(std::exception_ptr e = std::current_exception());
+/* Exit gracefully on uncaught exception. */
+void OnTerminate();
+
+/* Exception-catching version of F that warns on exception. */
+template <auto F>
+auto Except = (decltype(F))[](auto... xs)
+{
+ try {
+ return F(xs...);
+ } catch (...) {
+ EBMessageBox(What(), L"Error");
+ if constexpr (!std::is_same_v<decltype(F(xs...)), void>)
+ return decltype(F(xs...)){};
+ }
+};
+
+/* Exception-catching version of F that exits on exception. */
+template <auto F>
+auto Noexcept = (decltype(F))[](auto... xs)
+{
+ try {
+ return F(xs...);
+ } catch (...) {
+ EBMessageBox(What(), L"Fatal Error", MB_ICONERROR);
+ exit(1);
+ if constexpr (!std::is_same_v<decltype(F(xs...)), void>)
+ return decltype(F(xs...)){};
+ }
+};
+
#endif
diff --git a/c/listview.cpp b/c/listview.cpp
index b638f7b..0615ed0 100644
--- a/c/listview.cpp
+++ b/c/listview.cpp
@@ -2,6 +2,7 @@
#include <commctrl.h>
#include "drag.h"
+#include "err.h"
#include "listview.h"
#include "win32.h"
#include "window.h"
@@ -14,17 +15,19 @@ ListView::ListView(Window& parent, const HMENU hMenu, const DWORD dwStyle) : par
{
extern HFONT g_hfNormal;
- hWnd = Require(CreateWindowExW(
+ if (!(hWnd = CreateWindowExW(
WS_EX_CLIENTEDGE,
WC_LISTVIEW,
L"",
dwStyle|WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP|LVS_REPORT|LVS_SHOWSELALWAYS,
0, 0, 0, 0,
- parent.hWnd, hMenu, GetModuleHandle(nullptr), this));
+ parent.hWnd, hMenu, GetModuleHandle(nullptr), this)))
+ throw Err(WINDOWS, L"List view could not be created: %s");
m_proc0 = reinterpret_cast<WNDPROC>(SetWindowLongPtr(
- hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(::WndProc)));
+ hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(Except<::WndProc>)));
- Require(SetPropW(hWnd, L"this", reinterpret_cast<HANDLE>(this)));
+ if (!SetPropW(hWnd, L"this", reinterpret_cast<HANDLE>(this)))
+ throw Err(WINDOWS, L"List view property could not be set: %s");
ListView_SetExtendedListViewStyle(hWnd, LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER);
SendMessageW(hWnd, WM_SETFONT, reinterpret_cast<WPARAM>(g_hfNormal), MAKELPARAM(FALSE, 0));
}
diff --git a/c/main.cpp b/c/main.cpp
index f9d4a42..236b6d3 100644
--- a/c/main.cpp
+++ b/c/main.cpp
@@ -2,6 +2,7 @@
#include <stdexcept>
#include <windows.h>
#include <commctrl.h>
+#include <shlobj.h>
#include <libxml/xmlversion.h>
#include "datalistview.h"
@@ -40,8 +41,8 @@ BOOL (__stdcall *IsThemeActive)();
HRESULT (__stdcall *SetWindowTheme)(HWND, const wchar_t*, const wchar_t*);
/* Initialize important global state on parent window creation. */
-static void InitializeMainWindow(HWND) noexcept;
-/* Process parent window commands. */
+static void InitializeMainWindow(HWND);
+/* Process main window commands. */
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
/* Handle messages to Help > About dialog. */
static INT_PTR CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM);
@@ -54,8 +55,7 @@ int WINAPI WinMain(
_In_ char* const,
_In_ const int nCmdShow)
{
- /* Exit gracefully on uncaught exception. */
- SET_TERMINATE;
+ std::set_terminate(OnTerminate);
setbuf(stdout, nullptr);
LIBXML_TEST_VERSION;
@@ -63,12 +63,16 @@ int WINAPI WinMain(
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(icc);
icc.dwICC = ICC_WIN95_CLASSES;
- Require(InitCommonControlsEx(&icc));
+ if (!InitCommonControlsEx(&icc))
+ throw Err(WINDOWS, L"Common controls could not be initialized: %s");
+
+ if (CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED) != S_OK)
+ throw Err(GENERIC, L"COM library could not be initialized");
WNDCLASSEX wc;
memset(&wc, 0, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
- wc.lpfnWndProc = WndProc;
+ wc.lpfnWndProc = Except<WndProc>;
wc.hInstance = hInstance;
wc.hIcon = LoadIconW(nullptr, IDI_APPLICATION);
wc.hCursor = g_hcArrow;
@@ -76,27 +80,31 @@ int WINAPI WinMain(
wc.lpszMenuName = MAKEINTRESOURCEW(IDR_MENU);
wc.lpszClassName = L"Episode Browser";
wc.hIconSm = LoadIconW(nullptr, IDI_APPLICATION);
- Require(RegisterClassExW(&wc));
+ if (!RegisterClassExW(&wc))
+ throw Err(WINDOWS, L"Window class could not be registered: %s");
/* InitializeMainWindow is called before the first message is
* sent to WndProc. This is important, as it initializes
* global state on which WndProc relies. */
- WithNextWindow(InitializeMainWindow);
- const HWND hWnd = Require(CreateWindowExW(
+ WithNextWindow(Noexcept<InitializeMainWindow>);
+ HWND hWnd;
+ if (!(hWnd = CreateWindowExW(
0,
L"Episode Browser",
L"Episode Browser",
WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,
XMAIN, YMAIN, 0, 0,
- nullptr, nullptr, hInstance, nullptr));
+ nullptr, nullptr, hInstance, nullptr)))
+ throw Err(WINDOWS, L"Main window could not be created: %s");
- g_window->hWndStatus = Require(CreateWindowExW(
+ if (!(g_window->hWndStatus = CreateWindowExW(
0,
STATUSCLASSNAME,
nullptr,
WS_CHILD|WS_VISIBLE|SBARS_SIZEGRIP,
0, 0, 0, 0,
- hWnd, reinterpret_cast<HMENU>(IDR_STATUS), hInstance, nullptr));
+ hWnd, reinterpret_cast<HMENU>(IDR_STATUS), hInstance, nullptr)))
+ throw Err(WINDOWS, L"Status bar could not be created: %s");
ShowWindow(hWnd, nCmdShow);
@@ -119,7 +127,7 @@ int WINAPI WinMain(
return 0;
}
-static void InitializeMainWindow_(const HWND hWnd)
+static void InitializeMainWindow(const HWND hWnd)
{
/* This code is run ONCE, at the creation of the top-level
* window -- before WndProc! This is important, as it
@@ -139,17 +147,22 @@ static void InitializeMainWindow_(const HWND hWnd)
m.cbSize -= 4;
#endif
- Require(SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &m, 0));
- g_hfNormal = Require(CreateFontIndirectW(&m.lfMessageFont));
+ if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &m, 0))
+ throw Err(WINDOWS, L"Non-client metrics could not be queried: %s");
+ if (!(g_hfNormal = CreateFontIndirectW(&m.lfMessageFont)))
+ throw Err(WINDOWS, L"System message font could not be loaded: %s");
} else
- g_hfNormal = static_cast<HFONT>(Require(GetStockObject(DEFAULT_GUI_FONT)));
+ if (!(g_hfNormal = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT))))
+ throw Err(WINDOWS, L"System GUI font could not be loaded: %s");
/* Load bold font. */
{
LOGFONTW lf;
- Require(GetObjectW(g_hfNormal, sizeof(LOGFONTW), &lf));
+ if (!GetObjectW(g_hfNormal, sizeof(LOGFONTW), &lf))
+ throw Err(WINDOWS, L"Logical system font could not be loaded: %s");
lf.lfWeight = FW_BOLD;
- g_hfBold = Require(CreateFontIndirectW(&lf));
+ if (!(g_hfBold = CreateFontIndirectW(&lf)))
+ throw Err(WINDOWS, L"Bold font could not be loaded: %s");
}
/* Load theme functions, if available. */
@@ -161,36 +174,21 @@ static void InitializeMainWindow_(const HWND hWnd)
g_window = new Window(hWnd);
}
-void InitializeMainWindow(const HWND hWnd) noexcept
-{
- try {
- InitializeMainWindow_(hWnd);
- } catch (...) {
- EBMessageBox(What(), L"Initialization Error", MB_ICONERROR);
- exit(1);
- }
-}
-
LRESULT CALLBACK WndProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
{
- try {
- return g_window->WndProc(hWnd, uMsg, wParam, lParam);
- } catch (...) {
- EBMessageBox(What(), L"Error");
- }
- return DefWindowProc(hWnd, uMsg, wParam, lParam);
+ return g_window->WndProc(hWnd, uMsg, wParam, lParam);
}
INT_PTR CALLBACK AboutDlgProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM)
{
switch (uMsg) {
case WM_CLOSE:
- EndDialog(hWnd, IDOK);
+ EndDialog(hWnd, IDCANCEL);
return TRUE;
case WM_COMMAND:
- if (LOWORD(wParam) == IDOK)
- EndDialog(hWnd, IDOK);
+ if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+ EndDialog(hWnd, LOWORD(wParam));
return TRUE;
default:
@@ -200,19 +198,33 @@ INT_PTR CALLBACK AboutDlgProc(const HWND hWnd, const UINT uMsg, const WPARAM wPa
INT_PTR CALLBACK PreferencesDlgProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM)
{
- switch (uMsg) {
- case WM_CLOSE:
- EndDialog(hWnd, IDOK);
+ if (uMsg == WM_CLOSE) {
+ EndDialog(hWnd, IDCANCEL);
return TRUE;
-
- case WM_COMMAND:
- if (LOWORD(wParam) == IDOK)
- EndDialog(hWnd, IDOK);
+ } else if (uMsg == WM_COMMAND) {
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(hWnd, LOWORD(wParam));
+ return TRUE;
+ case IDC_BROWSE:
+ {
+ wchar_t path[MAX_PATH];
+ BROWSEINFOW bi = {hWnd, nullptr, path,
+ L"Episode Browser will look for local episode files in the"
+ L" chosen directory and its subdirectories.",
+ BIF_EDITBOX|BIF_NEWDIALOGSTYLE|BIF_NONEWFOLDERBUTTON};
+ if (auto pidl = SHBrowseForFolderW(&bi)) {
+ if (!SHGetPathFromIDListW(pidl, path))
+ throw Err(GENERIC, L"Invalid path selected.");
+ EBMessageBox(path, L"You Chose");
+ }
+ return TRUE;
+ }
+ }
return TRUE;
-
- default:
+ } else
return FALSE;
- }
}
LRESULT CALLBACK Window::WndProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
@@ -265,11 +277,12 @@ LRESULT CALLBACK Window::WndProc(const HWND hWnd, const UINT uMsg, const WPARAM
/* Get new window position/size. */
{
const RECT* const r = reinterpret_cast<RECT*>(lParam);
- Prefer(SetWindowPos(hWnd, nullptr,
+ if (!SetWindowPos(hWnd, nullptr,
r->left, r->top,
r->right-r->left,
r->bottom-r->top,
- SWP_NOZORDER|SWP_NOACTIVATE));
+ SWP_NOZORDER|SWP_NOACTIVATE))
+ throw Err(WINDOWS, L"");
UpdateLayout(r->right-r->left, r->bottom-r->top);
}
return 0;
@@ -395,7 +408,7 @@ void Window::HandleMainMenu(const HWND hWnd, const WORD command)
GetModuleHandle(nullptr),
MAKEINTRESOURCE(IDD_PREFERENCES),
hWnd,
- PreferencesDlgProc);
+ Except<PreferencesDlgProc>);
break;
case IDM_FILE_FETCH_DATA:
@@ -417,7 +430,7 @@ void Window::HandleMainMenu(const HWND hWnd, const WORD command)
GetModuleHandle(nullptr),
MAKEINTRESOURCE(IDD_ABOUT),
hWnd,
- AboutDlgProc);
+ Except<AboutDlgProc>);
break;
case IDM_VIEW_WATCHED:
@@ -465,16 +478,20 @@ void Window::UpdateLayout(int w, int h)
RECT rc, rrStatus;
if (w && h) rc = {0, 0, w, h};
- else Require(GetClientRect(hWnd, &rc));
- Require(GetRelativeRect(hWndStatus, &rrStatus));
+ else if (!GetClientRect(hWnd, &rc))
+ throw Err(WINDOWS, L"Window rectangle could not be retrieved: %s");
+ if (!GetRelativeRect(hWndStatus, &rrStatus))
+ throw Err(WINDOWS, L"Status bar rectangle could not be retrieved: %s");
SendMessageW(hWnd, WM_SETREDRAW, FALSE, 0);
/* Resize list views. */
const long pad = EBIsThemeActive()? Dpi(6): 0; /* Add padding in modern themes. */
const long cyDlv = rrStatus.top-dlv.Height()-pad;
- Require(SetWindowRect(dlv.hWnd, pad, cyDlv, rc.right-pad, rrStatus.top-pad));
- Require(SetWindowRect(elv.hWnd, pad, pad, rc.right-pad, cyDlv-pad));
+ if (!SetWindowRect(dlv.hWnd, pad, cyDlv, rc.right-pad, rrStatus.top-pad))
+ throw Err(WINDOWS, L"Data list view rectangle could not be updated: %s");
+ if (!SetWindowRect(elv.hWnd, pad, pad, rc.right-pad, cyDlv-pad))
+ throw Err(WINDOWS, L"Episode list view rectangle could not be updated: %s");
dlv.ResizeColumns(rc.right-pad-pad);
elv.ResizeColumns(rc.right-pad-pad);
diff --git a/c/util.h b/c/util.h
index 668d040..561e232 100644
--- a/c/util.h
+++ b/c/util.h
@@ -13,13 +13,6 @@
#define CONCAT(a, b) CONCAT_IMPL(a, b)
#define _ CONCAT(unused_, __LINE__)
-#define SET_TERMINATE \
- std::set_terminate([]() noexcept \
- { \
- EBMessageBox(What(), L"Fatal Error", MB_ICONERROR); \
- _Exit(1); \
- })
-
/* Scope guard. */
template <typename F>
struct Finally
@@ -98,12 +91,12 @@ struct UniqueOk
T v;
UniqueOk(Unique<T, F>&& u) : v(std::move(u.v))
{
- assert(u.ok, "UniqueOk may not be constructed from non-ok Unique");
+ assert(u.ok);
u.ok = false;
}
UniqueOk& operator =(Unique<T, F>&& u)
{
- assert(u.ok, "UniqueOk may not be constructed from non-ok Unique");
+ assert(u.ok);
F(v);
v = std::move(u.v);
u.ok = false;
diff --git a/c/win32.cpp b/c/win32.cpp
index fa5116d..73316e8 100644
--- a/c/win32.cpp
+++ b/c/win32.cpp
@@ -32,17 +32,21 @@ void WithNextWindow(void (*proc)(HWND))
static thread_local void (*procNext)(HWND);
static thread_local HHOOK hHook;
- procNext = proc;
- hHook = Require(SetWindowsHookExW(WH_CBT, [](const int nCode,
+ static const auto procCBT = [](const int nCode,
const WPARAM wParam, const LPARAM lParam) -> LRESULT CALLBACK
{
if (nCode == HCBT_CREATEWND) {
- Require(UnhookWindowsHookEx(hHook));
+ if (!UnhookWindowsHookEx(hHook))
+ throw Err(WINDOWS, L"Window hook could not be removed: %s");
procNext(reinterpret_cast<HWND>(wParam));
return 0;
} else
return CallNextHookEx(0, nCode, wParam, lParam);
- }, nullptr, GetCurrentThreadId()));
+ };
+
+ procNext = proc;
+ if (!(hHook = SetWindowsHookExW(WH_CBT, procCBT, nullptr, GetCurrentThreadId())))
+ throw Err(WINDOWS, L"Window hook could not be set: %s");
}
/* Display next created window in the center of given window. */
@@ -59,18 +63,16 @@ static void CenterNextWindow(HWND hWnd)
static thread_local HWND hWndParent;
static thread_local HWND hWndNext;
static thread_local HHOOK hHook;
-
- hWndParent = hWnd;
- hWndNext = nullptr;
- hHook = Require(SetWindowsHookExW(WH_CBT, [](const int nCode,
- const WPARAM wParam, const LPARAM lParam) noexcept -> LRESULT CALLBACK
+ static const auto procCBT = [](const int nCode,
+ const WPARAM wParam, const LPARAM lParam) -> LRESULT CALLBACK
{
if (!hWndNext && nCode == HCBT_CREATEWND) {
hWndNext = reinterpret_cast<HWND>(wParam);
return 0;
} else if (nCode == HCBT_ACTIVATE
&& reinterpret_cast<HWND>(wParam) == hWndNext) {
- Require(UnhookWindowsHookEx(hHook));
+ if (!UnhookWindowsHookEx(hHook))
+ throw Err(WINDOWS, L"Window hook could not be removed: %s");
long lStyle = GetWindowLongW(hWndNext, GWL_STYLE);
if (!(lStyle & WS_POPUP)) return 0;
@@ -87,7 +89,12 @@ static void CenterNextWindow(HWND hWnd)
return 0;
} else
return CallNextHookEx(0, nCode, wParam, lParam);
- }, nullptr, GetCurrentThreadId()));
+ };
+
+ hWndParent = hWnd;
+ hWndNext = nullptr;
+ if (!(hHook = SetWindowsHookExW(WH_CBT, procCBT, nullptr, GetCurrentThreadId())))
+ throw Err(WINDOWS, L"Window hook could not be set: %s");
}
int EBMessageBox(const std::wstring_view text, const std::wstring_view caption, const UINT uType)
@@ -112,84 +119,6 @@ int GetRelativeCursorPos(const HWND hWnd, POINT* const pt) noexcept
return 1;
}
-Win32Error::Win32Error(const DWORD code, const HMODULE hModule) noexcept
- : code(code), hModule(hModule) {}
-
-Win32Error::~Win32Error()
-{
- if (m_szMsg)
- HeapFree(GetProcessHeap(), 0, m_szMsg);
- if (m_wszMsg)
- HeapFree(GetProcessHeap(), 0, m_wszMsg);
-}
-
-const char* Win32Error::what() const noexcept
-{
- if (!m_szMsg)
- FormatMessageA(
- FORMAT_MESSAGE_ALLOCATE_BUFFER
- |FORMAT_MESSAGE_FROM_SYSTEM
- |FORMAT_MESSAGE_FROM_HMODULE
- |FORMAT_MESSAGE_IGNORE_INSERTS,
- hModule,
- code,
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
- (char*)&m_szMsg,
- 0, nullptr);
- return m_szMsg? m_szMsg: "An unknown error occurred";
-}
-
-const wchar_t* Win32Error::What() const noexcept
-{
- if (!m_wszMsg)
- FormatMessageW(
- FORMAT_MESSAGE_ALLOCATE_BUFFER
- |FORMAT_MESSAGE_FROM_SYSTEM
- |FORMAT_MESSAGE_FROM_HMODULE
- |FORMAT_MESSAGE_IGNORE_INSERTS,
- hModule,
- code,
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
- (wchar_t*)&m_wszMsg,
- 0, nullptr);
- return m_wszMsg? m_wszMsg: L"An unknown error occurred";
-}
-
-InternetError::InternetError(DWORD codeSystem)
-{
- if (codeSystem != ERROR_INTERNET_EXTENDED_ERROR)
- throw Win32Error(codeSystem, GetModuleHandle(L"wininet.dll"));
-
- DWORD len, cch;
- InternetGetLastResponseInfo(&code, nullptr, &len);
-
- cch = len+1;
- m_szMsg = new char[cch];
- if (!InternetGetLastResponseInfoA(&code, m_szMsg, &cch))
- throw Win32Error();
-
- cch = len+1;
- m_wszMsg = new wchar_t[cch];
- if (!InternetGetLastResponseInfoW(&code, m_wszMsg, &len))
- throw Win32Error();
-}
-
-InternetError::~InternetError()
-{
- delete m_szMsg;
- delete m_wszMsg;
-}
-
-const char* InternetError::what() const noexcept
-{
- return m_szMsg;
-}
-
-const wchar_t* InternetError::What() const noexcept
-{
- return m_wszMsg;
-}
-
std::optional<Library> Library::Maybe(const wchar_t* const lib) noexcept
{
HMODULE hModule = LoadLibraryW(lib);
diff --git a/c/win32.h b/c/win32.h
index c18e70f..0473f6c 100644
--- a/c/win32.h
+++ b/c/win32.h
@@ -6,8 +6,6 @@
#include <windows.h>
#include <commctrl.h>
-#include "err.h"
-
/* Convert narrow to wide string. */
std::wstring WideFromNarrow(const std::string_view src, const int cp = CP_UTF8);
@@ -23,39 +21,6 @@ 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
{
@@ -78,25 +43,6 @@ 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) Err(WINDOWS, L"System error: %s");
- 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)
{
diff --git a/c/window.h b/c/window.h
index daf7202..9d247ec 100644
--- a/c/window.h
+++ b/c/window.h
@@ -15,7 +15,15 @@ struct Window
HWND hWnd;
HWND hWndFocus = nullptr;
HWND hWndStatus = nullptr;
- HMENU hMenuPopup = Require(GetSubMenu(Require(LoadMenuW(nullptr, MAKEINTRESOURCE(IDR_POPUPMENU))), 0));
+ const HMENU hMenuPopup = []()
+ {
+ HMENU hm;
+ if (!(hm = LoadMenuW(nullptr, MAKEINTRESOURCE(IDR_POPUPMENU))))
+ throw Err(WINDOWS, L"Context menu could not be loaded: %s");
+ if (!GetSubMenu(hm, 0))
+ throw Err(WINDOWS, L"Submenu could not be retrieved: %s");
+ return hm;
+ }();
/* File views. */
FileView<CfgA> fvCfg = FileView<CfgA>::Initialized(L"cfg.dat", 1);