diff options
Diffstat (limited to 'c/main.cpp')
-rw-r--r-- | c/main.cpp | 127 |
1 files changed, 72 insertions, 55 deletions
@@ -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); |