From 2f7b69d6d4cf18ca9ca04d9a44aaa6871ce51160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Wed, 7 Sep 2022 00:40:26 +0200 Subject: Improve error handling. --- c/data.cpp | 5 +- c/drag.cpp | 12 +++-- c/episodelistview.cpp | 8 ++-- c/err.cpp | 7 ++- c/err.h | 32 +++++++++++++ c/listview.cpp | 11 +++-- c/main.cpp | 127 ++++++++++++++++++++++++++++---------------------- c/util.h | 11 +---- c/win32.cpp | 107 +++++++----------------------------------- c/win32.h | 54 --------------------- c/window.h | 10 +++- 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 #include +#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 Except = (decltype(F))[](auto... xs) +{ + try { + return F(xs...); + } catch (...) { + EBMessageBox(What(), L"Error"); + if constexpr (!std::is_same_v) + return decltype(F(xs...)){}; + } +}; + +/* Exception-catching version of F that exits on exception. */ +template +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) + 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 #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(SetWindowLongPtr( - hWnd, GWLP_WNDPROC, reinterpret_cast(::WndProc))); + hWnd, GWLP_WNDPROC, reinterpret_cast(Except<::WndProc>))); - Require(SetPropW(hWnd, L"this", reinterpret_cast(this))); + if (!SetPropW(hWnd, L"this", reinterpret_cast(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(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 #include #include +#include #include #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; 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); + 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(IDR_STATUS), hInstance, nullptr)); + hWnd, reinterpret_cast(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(Require(GetStockObject(DEFAULT_GUI_FONT))); + if (!(g_hfNormal = static_cast(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(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); 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); 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 struct Finally @@ -98,12 +91,12 @@ struct UniqueOk T v; UniqueOk(Unique&& 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&& 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(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(wParam); return 0; } else if (nCode == HCBT_ACTIVATE && reinterpret_cast(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::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 #include -#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 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 -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 -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 fvCfg = FileView::Initialized(L"cfg.dat", 1); -- cgit v1.2.3