diff --git a/windows/init.c b/windows/init.c deleted file mode 100644 index b049ee0f..00000000 --- a/windows/init.c +++ /dev/null @@ -1,208 +0,0 @@ -// 6 april 2015 -#include "uipriv_windows.h" - -HINSTANCE hInstance; -int nCmdShow; - -HFONT hMessageFont; - -HBRUSH hollowBrush; - -// TODO this won't work if initAlloc() failed - -#define initErrorFormat L"error %s: %s%s%s %I32u (0x%I32X)%s" -#define initErrorArgs wmessage, sysmsg, beforele, label, value, value, afterle - -static const char *initerr(const char *message, const WCHAR *label, DWORD value) -{ - WCHAR *sysmsg; - BOOL hassysmsg; - WCHAR *beforele; - WCHAR *afterle; - int n; - WCHAR *wmessage; - WCHAR *wstr; - const char *str; - - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, value, 0, (LPWSTR) (&sysmsg), 0, NULL) != 0) { - hassysmsg = TRUE; - beforele = L" ("; - afterle = L")"; - } else { - hassysmsg = FALSE; - sysmsg = L""; - beforele = L""; - afterle = L""; - } - wmessage = toUTF16(message); - n = _scwprintf(initErrorFormat, initErrorArgs); - wstr = (WCHAR *) uiAlloc((n + 1) * sizeof (WCHAR), "WCHAR[]"); - _snwprintf(wstr, n + 1, initErrorFormat, initErrorArgs); - str = toUTF8(wstr); - uiFree(wstr); - if (hassysmsg) - if (LocalFree(sysmsg) != NULL) - logLastError("error freeing system message in loadLastError()"); - uiFree(wmessage); - return str; -} - -static const char *loadLastError(const char *message) -{ - return initerr(message, L"GetLastError() ==", GetLastError()); -} - -static const char *loadHRESULT(const char *message, HRESULT hr) -{ - return initerr(message, L"HRESULT", (DWORD) hr); -} - -static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) -{ - switch (dwCtrlType) { - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - // the handler is run in a separate thread - SendMessageW(utilWindow, msgConsoleEndSession, 0, 0); - // we handled it here - // this WON'T terminate the program because this is a DLL - // at least, that's the best I can gather from the MSDN page on the handler function - // it says that functions registered by a DLL replace the default handler function (which ends the process) - // it works, anyway - return TRUE; - } - return FALSE; -} - -uiInitOptions options; - -#define wantedICCClasses ( \ - ICC_STANDARD_CLASSES | /* user32.dll controls */ \ - ICC_PROGRESS_CLASS | /* progress bars */ \ - ICC_TAB_CLASSES | /* tabs */ \ - ICC_LISTVIEW_CLASSES | /* table headers */ \ - ICC_UPDOWN_CLASS | /* spinboxes */ \ - ICC_BAR_CLASSES | /* trackbar */ \ - ICC_DATE_CLASSES | /* date/time picker */ \ - 0) - -const char *uiInit(uiInitOptions *o) -{ - STARTUPINFOW si; - const char *ce; - HICON hDefaultIcon; - HCURSOR hDefaultCursor; - NONCLIENTMETRICSW ncm; - INITCOMMONCONTROLSEX icc; - HRESULT hr; - - options = *o; - - if (initAlloc() == 0) - return loadLastError("error initializing memory allocations"); - - initResizes(); - - nCmdShow = SW_SHOWDEFAULT; - GetStartupInfoW(&si); - if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0) - nCmdShow = si.wShowWindow; - - hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION); - if (hDefaultIcon == NULL) - return loadLastError("loading default icon for window classes"); - hDefaultCursor = LoadCursorW(NULL, IDC_ARROW); - if (hDefaultCursor == NULL) - return loadLastError("loading default cursor for window classes"); - - ce = initUtilWindow(hDefaultIcon, hDefaultCursor); - if (ce != NULL) - return loadLastError(ce); - - if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0) - return loadLastError("registering uiWindow window class"); - - ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW)); - ncm.cbSize = sizeof (NONCLIENTMETRICSW); - if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0) - return loadLastError("getting default fonts"); - hMessageFont = CreateFontIndirectW(&(ncm.lfMessageFont)); - if (hMessageFont == NULL) - return loadLastError("loading default messagebox font; this is the default UI font"); - - // TODO rewrite this error message - if (initContainer(hDefaultIcon, hDefaultCursor) == 0) - return loadLastError("initializing uiMakeContainer() window class"); - - if (SetConsoleCtrlHandler(consoleCtrlHandler, TRUE) == 0) - return loadLastError("setting up console end session handler"); - - hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH); - if (hollowBrush == NULL) - return loadLastError("getting hollow brush"); - - ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX)); - icc.dwSize = sizeof (INITCOMMONCONTROLSEX); - icc.dwICC = wantedICCClasses; - if (InitCommonControlsEx(&icc) == 0) - return loadLastError("initializing Common Controls"); - - hr = CoInitialize(NULL); - if (hr != S_OK && hr != S_FALSE) - return loadHRESULT("initializing COM", hr); - // TODO initialize COM security - // TODO (windows vista) turn off COM exception handling - - hr = initDraw(); - if (hr != S_OK) - return loadHRESULT("initializing Direct2D", hr); - - hr = initDrawText(); - if (hr != S_OK) - return loadHRESULT("initializing DirectWrite", hr); - - if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0) - return loadLastError("registering uiArea window class"); - if (registerAreaFilter() == 0) - return loadLastError("registering uiArea message filter"); - - if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0) - return loadLastError("initializing D2D scratch window class"); - - return NULL; -} - -void uiUninit(void) -{ - uninitMenus(); - unregisterD2DScratchClass(); - unregisterArea(); - uninitDrawText(); - uninitDraw(); - CoUninitialize(); - if (DeleteObject(hollowBrush) == 0) - logLastError("error freeing hollow brush in uiUninit()"); - if (SetConsoleCtrlHandler(consoleCtrlHandler, FALSE) == 0) - logLastError("error unregistering console end session handler in uiUninit()"); - uninitContainer(); - if (DeleteObject(hMessageFont) == 0) - logLastError("error deleting control font in uiUninit()"); - unregisterWindowClass(); - // no need to delete the default icon or cursor; see http://stackoverflow.com/questions/30603077/ - uninitUtilWindow(); - uninitResizes(); - uninitTypes(); - uninitAlloc(); -} - -void uiFreeInitError(const char *err) -{ - uiFree((void *) err); -} - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - hInstance = hinstDLL; - return TRUE; -} diff --git a/windows/init.cpp b/windows/init.cpp new file mode 100644 index 00000000..22e33986 --- /dev/null +++ b/windows/init.cpp @@ -0,0 +1,170 @@ +// 6 april 2015 +#include "uipriv_windows.hpp" + +HINSTANCE hInstance; +int nCmdShow; + +HFONT hMessageFont; + +// TODO needed? +HBRUSH hollowBrush; + +// the returned pointer is actually to the second character +// if the first character is - then free, otherwise don't +static const char *initerr(const char *message, const WCHAR *label, DWORD code) +{ + WCHAR *sysmsg; + BOOL hassysmsg; + WCHAR *wmessage; + WCHAR *out; + char *out; + + hassysmsg = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, value, 0, (LPWSTR) (&sysmsg), 0, NULL) != 0; + if (!hassysmsg) + sysmsg = L""; + wmessage = toUTF16(message + 1); + wout = debugstrf(L"-error initializing libui: %s; code %I32d (0x%08I32X) %s", + wmessage, + value, value, + sysmsg); + uiFree(wmessage); + if (hassysmsg) + LocalFree(sysmsg); // ignore error + if (wout == NULL) // debugstrf() failed; return message raw + return message + 1; + out = toUTF8(wout); + uiFree(wout); + return out + 1; +} + +#define ieLastErr(msg) initerr("=" message, L"GetLastError() ==", GetLastError()) +#define ieHRESULT(msg, hr) initerr("=" message, L"HRESULT", (DWORD) hr) + +// TODO make common +uiInitOptions options; + +#define wantedICCClasses ( \ + ICC_STANDARD_CLASSES | /* user32.dll controls */ \ + ICC_PROGRESS_CLASS | /* progress bars */ \ + ICC_TAB_CLASSES | /* tabs */ \ + ICC_LISTVIEW_CLASSES | /* table headers */ \ + ICC_UPDOWN_CLASS | /* spinboxes */ \ + ICC_BAR_CLASSES | /* trackbar */ \ + ICC_DATE_CLASSES | /* date/time picker */ \ + 0) + +const char *uiInit(uiInitOptions *o) +{ + STARTUPINFOW si; + const char *ce; + HICON hDefaultIcon; + HCURSOR hDefaultCursor; + NONCLIENTMETRICSW ncm; + INITCOMMONCONTROLSEX icc; + HRESULT hr; + + options = *o; + + initAlloc(); + + initResizes(); + + nCmdShow = SW_SHOWDEFAULT; + GetStartupInfoW(&si); + if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0) + nCmdShow = si.wShowWindow; + + hDefaultIcon = LoadIconW(NULL, IDI_APPLICATION); + if (hDefaultIcon == NULL) + return ieLastErr("loading default icon for window classes"); + hDefaultCursor = LoadCursorW(NULL, IDC_ARROW); + if (hDefaultCursor == NULL) + return ieLastErr("loading default cursor for window classes"); + + ce = initUtilWindow(hDefaultIcon, hDefaultCursor); + if (ce != NULL) + return ieLastErr(ce); + + if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0) + return ieLastErr("registering uiWindow window class"); + + ZeroMemory(&ncm, sizeof (NONCLIENTMETRICSW)); + ncm.cbSize = sizeof (NONCLIENTMETRICSW); + if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof (NONCLIENTMETRICSW), &ncm, sizeof (NONCLIENTMETRICSW)) == 0) + return ieLastErr("getting default fonts"); + hMessageFont = CreateFontIndirectW(&(ncm.lfMessageFont)); + if (hMessageFont == NULL) + return ieLastErr("loading default messagebox font; this is the default UI font"); + + // TODO rewrite this error message + if (initContainer(hDefaultIcon, hDefaultCursor) == 0) + return ieLastErr("initializing uiMakeContainer() window class"); + + hollowBrush = (HBRUSH) GetStockObject(HOLLOW_BRUSH); + if (hollowBrush == NULL) + return ieLastErr("getting hollow brush"); + + ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX)); + icc.dwSize = sizeof (INITCOMMONCONTROLSEX); + icc.dwICC = wantedICCClasses; + if (InitCommonControlsEx(&icc) == 0) + return ieLastErr("initializing Common Controls"); + + hr = CoInitialize(NULL); + if (hr != S_OK && hr != S_FALSE) + return ieHRESULT("initializing COM", hr); + // TODO initialize COM security + // TODO (windows vista) turn off COM exception handling + + hr = initDraw(); + if (hr != S_OK) + return ieHRESULT("initializing Direct2D", hr); + + hr = initDrawText(); + if (hr != S_OK) + return ieHRESULT("initializing DirectWrite", hr); + + if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0) + return ieLastErr("registering uiArea window class"); + if (registerAreaFilter() == 0) + return ieLastErr("registering uiArea message filter"); + + if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0) + return ieLastErr("initializing D2D scratch window class"); + + return NULL; +} + +void uiUninit(void) +{ + uninitMenus(); + unregisterD2DScratchClass(); + unregisterArea(); + uninitDrawText(); + uninitDraw(); + CoUninitialize(); + if (DeleteObject(hollowBrush) == 0) + logLastError(L"error freeing hollow brush"); + uninitContainer(); + if (DeleteObject(hMessageFont) == 0) + logLastError(L"error deleting control font"); + unregisterWindowClass(); + // no need to delete the default icon or cursor; see http://stackoverflow.com/questions/30603077/ + uninitUtilWindow(); + uninitResizes(); + uninitTypes(); + uninitAlloc(); +} + +void uiFreeInitError(const char *err) +{ + if (*(err - 1) == '-') + uiFree((void *) err); +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + hInstance = hinstDLL; + return TRUE; +} diff --git a/windows/uipriv_windows_new.hpp b/windows/uipriv_windows_new.hpp index 7e420f6b..55663a10 100644 --- a/windows/uipriv_windows_new.hpp +++ b/windows/uipriv_windows_new.hpp @@ -1,5 +1,9 @@ // 21 april 2016 +// alloc.cpp +extern void initAlloc(void); +extern void uninitAlloc(void); + // events.cpp extern BOOL runWM_COMMAND(WPARAM wParam, LPARAM lParam, LRESULT *lResult); extern BOOL runWM_NOTIFY(WPARAM wParam, LPARAM lParam, LRESULT *lResult); @@ -43,3 +47,10 @@ extern HWND parentToplevel(HWND child); extern WCHAR *windowTextAndLen(HWND hwnd, LRESULT *len); extern WCHAR *windowText(HWND hwnd); extern void setWindowText(HWND hwnd, WCHAR *wtext); + +// init.cpp +extern HINSTANCE hInstance; +extern int nCmdShow; +extern HFONT hMessageFont; +extern HBRUSH hollowBrush; +extern uiInitOptions options;