153 lines
4.2 KiB
C++
153 lines
4.2 KiB
C++
// 6 april 2015
|
|
#include "uipriv_windows.hpp"
|
|
|
|
HINSTANCE uipriv_hInstance = NULL;
|
|
int uipriv_nCmdShow;
|
|
|
|
#ifndef uiStatic
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpvReserved)
|
|
{
|
|
if (fdwReason == DLL_PROCESS_ATTACH)
|
|
uipriv_hInstance = hInstance;
|
|
return TRUE;
|
|
}
|
|
|
|
static inline void setHInstance(void)
|
|
{
|
|
// do nothing; set by DllMain() above
|
|
}
|
|
|
|
#else
|
|
|
|
// see https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483
|
|
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
|
|
|
static inline void setHInstance(void)
|
|
{
|
|
uipriv_hInstance = (HINSTANCE) (&__ImageBase);
|
|
}
|
|
|
|
#endif
|
|
|
|
//HFONT hMessageFont;
|
|
|
|
#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)
|
|
|
|
// TODO add format string warning detection to all these functions, where available
|
|
#define uiprivInitReturnHRESULT(err, msg, hr) uiprivInitReturnErrorf(err, "%s: 0x%08I32X", msg, hr)
|
|
|
|
static DWORD mainThread;
|
|
|
|
bool uiprivSysInit(void *options, uiInitError *err)
|
|
{
|
|
STARTUPINFOW si;
|
|
HICON hDefaultIcon;
|
|
HCURSOR hDefaultCursor;
|
|
INITCOMMONCONTROLSEX icc;
|
|
HRESULT hr;
|
|
|
|
setHInstance();
|
|
uipriv_nCmdShow = SW_SHOWDEFAULT;
|
|
GetStartupInfoW(&si);
|
|
if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0)
|
|
uipriv_nCmdShow = si.wShowWindow;
|
|
|
|
hr = uiprivHrLoadIconW(NULL, IDI_APPLICATION, &hDefaultIcon);
|
|
if (hr != S_OK)
|
|
return uiprivInitReturnHRESULT(err, "failed to load default icon", hr);
|
|
hr = uiprivHrLoadCursorW(NULL, IDC_ARROW, &hDefaultCursor);
|
|
if (hr != S_OK)
|
|
return uiprivInitReturnHRESULT(err, "failed to load default cursor", hr);
|
|
|
|
hr = uiprivInitUtilWindow(hDefaultIcon, hDefaultCursor);
|
|
if (hr != S_OK)
|
|
return uiprivInitReturnHRESULT(err, "failed to initialize the utility window", hr);
|
|
|
|
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
|
|
icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
|
|
icc.dwICC = wantedICCClasses;
|
|
if (InitCommonControlsEx(&icc) == 0) {
|
|
DWORD lasterr;
|
|
|
|
lasterr = GetLastError();
|
|
if (lasterr == 0)
|
|
return uiprivInitReturnErrorf(err, "InitCommonControlsEx() failed, but didn't specify why. This usually means you forgot the Common Controls v6 manifest; refer to the libui documentation for instructions.");
|
|
hr = HRESULT_FROM_WIN32(lasterr);
|
|
return uiprivInitReturnHRESULT(err, "InitCommonControlsEx() failed", hr);
|
|
}
|
|
|
|
/* hr = CoInitialize(NULL);
|
|
if (hr != S_OK && hr != S_FALSE)
|
|
return uiprivInitReturnHRESULT(err, "CoInitialize() failed", hr);
|
|
// TODO initialize COM security
|
|
// TODO turn off COM exception handling
|
|
*/
|
|
mainThread = GetCurrentThreadId();
|
|
return true;
|
|
}
|
|
|
|
void uiMain(void)
|
|
{
|
|
MSG msg;
|
|
HRESULT hr;
|
|
|
|
if (!uiprivCheckInitializedAndThread())
|
|
return;
|
|
for (;;) {
|
|
hr = uiprivHrGetMessageW(&msg, NULL, 0, 0);
|
|
if (hr == S_FALSE) // WM_QUIT
|
|
return;
|
|
if (hr != S_OK)
|
|
uiprivInternalError("GetMessageW() failed in uiMain(): 0x%08I32X", hr);
|
|
// TODO IsDialogMessage()
|
|
TranslateMessage(&msg);
|
|
DispatchMessageW(&msg);
|
|
}
|
|
}
|
|
|
|
void uiQuit(void)
|
|
{
|
|
if (!uiprivCheckInitializedAndThread())
|
|
return;
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
void uiprivSysQueueMain(void (*f)(void *data), void *data)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = uiprivHrPostMessageW(uiprivUtilWindow, uiprivUtilWindowMsgQueueMain, (WPARAM) f, (LPARAM) data);
|
|
if (hr != S_OK)
|
|
uiprivInternalError("PostMessageW() failed in uiQueueMain(): 0x%08I32X", hr);
|
|
}
|
|
|
|
bool uiprivSysCheckThread(void)
|
|
{
|
|
return GetCurrentThreadId() == mainThread;
|
|
}
|
|
|
|
void uiprivReportError(const char *prefix, const char *msg, const char *suffix, bool internal)
|
|
{
|
|
// Print to both stderr and the debugger; the former handles the case of a console and the latter handles the case of not.
|
|
// TODO find a reliable way to check if stderr is connected (the mere presence of a console window is not one)
|
|
fprintf(stderr, "*** %s: %s. %s\n", prefix, msg, suffix);
|
|
// Use OutputDebugStringA() directly because these *are* runtime MBCS strings.
|
|
OutputDebugStringA(prefix);
|
|
OutputDebugStringA(": ");
|
|
OutputDebugStringA(msg);
|
|
OutputDebugStringA(". ");
|
|
OutputDebugStringA(suffix);
|
|
OutputDebugStringA("\n");
|
|
DebugBreak();
|
|
abort(); // we shouldn't reach here
|
|
}
|