Implemented uiMain() and friends on Windows. As a result, started the new HRESULT wrapper stuff.
This commit is contained in:
parent
49bde22f81
commit
812c559b11
|
@ -4,6 +4,32 @@
|
|||
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 ( \
|
||||
|
@ -16,15 +42,18 @@ int uipriv_nCmdShow;
|
|||
ICC_DATE_CLASSES | /* date/time picker */ \
|
||||
0)
|
||||
|
||||
// see https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483
|
||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
#define errGetDefaultIconFailed "failed to load default icon"
|
||||
#define errGetDefaultCursorFailed "failed to load default cursor"
|
||||
#define errInitUtilWindowFailed "failed to initialize the utility window"
|
||||
#define errICCFailed "InitCommonControlsEx() failed"
|
||||
#define errICCFailedNoLastError "InitCommonControlsEx() failed, but didn't specify why. This usually means you forgot the Common Controls v6 manifest; refer to the libui documentation for instructions."
|
||||
#define errCoInitializeFailed "CoInitialize() failed"
|
||||
|
||||
#define errHRESULTInitErrorsSuffix ": 0x00000000"
|
||||
static const char *initErrors[] = {
|
||||
errGetDefaultIconFailed errHRESULTInitErrorsSuffix
|
||||
errGetDefaultCursorFailed errHRESULTInitErrorsSuffix
|
||||
errInitUtilWindowFailed errHRESULTInitErrorsSuffix
|
||||
errICCFailed errHRESULTInitErrorsSuffix,
|
||||
errICCFailedNoLastError,
|
||||
errCoInitializeFailed errHRESULTInitErrorsSuffix,
|
||||
|
@ -35,19 +64,31 @@ static const char *initErrors[] = {
|
|||
int uiInit(void *options, uiInitError *err)
|
||||
{
|
||||
STARTUPINFOW si;
|
||||
HICON hDefaultIcon;
|
||||
HCURSOR hDefaultCursor;
|
||||
INITCOMMONCONTROLSEX icc;
|
||||
HRESULT hr;
|
||||
|
||||
if (!uiprivInitCheckParams(options, err, initErrors))
|
||||
return 0;
|
||||
|
||||
if (uipriv_hInstance == NULL)
|
||||
uipriv_hInstance = (HINSTANCE) (&__ImageBase);
|
||||
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, errLoadDefaultIconFailed, hr);
|
||||
hr = uiprivHrLoadCursorW(NULL, IDC_ARROW, &hDefaultCursor);
|
||||
if (hr != S_OK)
|
||||
return uiprivInitReturnHRESULT(err, errLoadDefaultCursorFailed, hr);
|
||||
|
||||
hr = uiprivInitUtilWindow(hDefaultIcon, hDefaultCursor);
|
||||
if (hr != S_OK)
|
||||
return uiprivInitReturnHRESULT(err, errInitUtilWindowFailed, hr);
|
||||
|
||||
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
|
||||
icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
|
||||
icc.dwICC = wantedICCClasses;
|
||||
|
@ -57,7 +98,8 @@ int uiInit(void *options, uiInitError *err)
|
|||
lasterr = GetLastError();
|
||||
if (lasterr == 0)
|
||||
return uiprivInitReturnError(err, errICCFailedNoLastError);
|
||||
return uiprivInitReturnHRESULT(err, errICCFailed, HRESULT_FROM_WIN32(lasterr));
|
||||
hr = HRESULT_FROM_WIN32(lasterr);
|
||||
return uiprivInitReturnHRESULT(err, errICCFailed, hr);
|
||||
}
|
||||
|
||||
/* hr = CoInitialize(NULL);
|
||||
|
@ -70,13 +112,37 @@ int uiInit(void *options, uiInitError *err)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifndef uiStatic
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpvReserved)
|
||||
void uiMain(void)
|
||||
{
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
uipriv_hInstance = hInstance;
|
||||
return TRUE;
|
||||
MSG msg;
|
||||
BOOL ret;
|
||||
HRESULT hr;
|
||||
|
||||
for (;;) {
|
||||
hr = uiprivHrGetMessageW(&msg, NULL, 0, 0, &ret);
|
||||
if (hr != S_OK) {
|
||||
// TODO log error
|
||||
return;
|
||||
}
|
||||
if (ret == 0) // WM_QUIT
|
||||
return;
|
||||
// TODO IsDialogMessage()
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
void uiQuit(void)
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
void uiQueueMain(void (*f)(void *data), void *data)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
hr = uiprivHrPostMessageW(uiprivUtilWindow, uiprivUtilWindowMsgQueueMain, (WPARAM) f, (LPARAM) data);
|
||||
if (hr != S_OK) {
|
||||
// TODO handle error
|
||||
}
|
||||
}
|
|
@ -3,7 +3,9 @@
|
|||
windows = import('windows')
|
||||
|
||||
libui_sources += [
|
||||
'windows/init.cpp',
|
||||
'windows/main.cpp',
|
||||
'windows/utilwin.cpp',
|
||||
'windows/winhresult.cpp',
|
||||
]
|
||||
|
||||
# resources.rc only contains the libui manifest.
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
// 21 april 2016
|
||||
#include "winapi.hpp"
|
||||
#include "winhresult.hpp"
|
||||
#include "../ui.h"
|
||||
#include "../ui_windows.h"
|
||||
#include "../common/uipriv.h"
|
||||
//TODO#include "compilerver.hpp"
|
||||
|
||||
// init.cpp
|
||||
// main.cpp
|
||||
extern HINSTANCE uipriv_hInstance;
|
||||
extern int uipriv_nCmdShow;
|
||||
//TODOextern HFONT hMessageFont;
|
||||
|
||||
// utilwin.cpp
|
||||
enum {
|
||||
uiprivUtilWindowMsgQueueMain = WM_USER + 40,
|
||||
};
|
||||
extern HWND uiprivUtilWindow;
|
||||
extern HRESULT uiprivInitUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// 14 may 2015
|
||||
#include "uipriv_windows.hpp"
|
||||
|
||||
// The utility window is a special window that performs certain tasks internal to libui.
|
||||
// TODO should it be message-only?
|
||||
|
||||
#define utilWindowClass L"libui_utilWindowClass"
|
||||
|
||||
HWND uiprivUtilWindow = NULL;
|
||||
|
||||
static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
void (*qf)(void *);
|
||||
|
||||
switch (uMsg) {
|
||||
case uiprivUtilWindowMsgQueueMain:
|
||||
qf = (void (*)(void *)) wParam;
|
||||
(*qf)((void *) lParam);
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
HRESULT uiprivInitUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
HRESULT hr;
|
||||
|
||||
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
||||
wc.lpszClassName = utilWindowClass;
|
||||
wc.lpfnWndProc = utilWindowWndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = hDefaultIcon;
|
||||
wc.hCursor = hDefaultCursor;
|
||||
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
|
||||
hr = uiprivHrRegisterClassW(&wc);
|
||||
if (hr != S_OK)
|
||||
return hr;
|
||||
return uiprivHrCreateWindowExW(0,
|
||||
utilWindowClass, L"libui utility window",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
0, 0, 100, 100,
|
||||
NULL, NULL, hInstance, NULL,
|
||||
&uiprivUtilWindow);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// 28 april 2019
|
||||
|
||||
extern HRESULT WINAPI uiprivHrRegisterClassW(const WNDCLASSW *wc);
|
||||
extern HRESULT WINAPI uiprivHrCreateWindowExW(DWORD exStyle, LPCWSTR className, LPCWSTR windowName, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE hInstance, LPVOID lpParam, HWND *hwnd);
|
||||
extern HRESULT WINAPI uiprivHrGetMessageW(LPMSG msg, HWND hwnd, UINT filterMin, UINT filterMax, BOOL *ret);
|
||||
extern HRESULT WINAPI uiprivHrPostMessageW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
extern HRESULT WINAPI uiprivHrLoadIconW(HINSTANCE hInstance, LPCWSTR name, HICON *hIcon);
|
||||
extern HRESULT WINAPI uiprivHrLoadCursorW(HINSTANCE hInstance, LPCWSTR name, HCURSOR *hCursor);
|
|
@ -0,0 +1,81 @@
|
|||
// 28 april 2019
|
||||
#include "winapi.h"
|
||||
#include "winhresult.h"
|
||||
|
||||
// This file wraps standard Windows API functions that don't use HRESULTs to return HRESULTs.
|
||||
// It also calls SetLastError(0) before each such call.
|
||||
|
||||
static inline HRESULT lastErrorCodeToHRESULT(DWORD lastError)
|
||||
{
|
||||
if (lastError == 0)
|
||||
return E_FAIL;
|
||||
return HRESULT_FROM_WIN32(lastError);
|
||||
}
|
||||
|
||||
static inline HRESULT lastErrorToHRESULT(void)
|
||||
{
|
||||
return lastErrorCodeToHRESULT(GetLastError());
|
||||
}
|
||||
|
||||
HRESULT WINAPI uiprivHrRegisterClassW(const WNDCLASSW *wc)
|
||||
{
|
||||
ATOM a;
|
||||
|
||||
SetLastError(0);
|
||||
a = RegisterClassW(wc);
|
||||
if (a == 0)
|
||||
return lastErrorToHRESULT();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI uiprivHrCreateWindowExW(DWORD exStyle, LPCWSTR className, LPCWSTR windowName, DWORD style, int x, int y, int width, int height, HWND parent, HMENU menu, HINSTANCE hInstance, LPVOID lpParam, HWND *hwnd)
|
||||
{
|
||||
SetLastError(0);
|
||||
*hwnd = CreateWindowExW(exStyle,
|
||||
className, windowName,
|
||||
style,
|
||||
x, y, width, height,
|
||||
parent, menu, hInstance, lpParam);
|
||||
if (*hwnd == NULL)
|
||||
return lastErrorToHRESULT();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// TODO turn ret into S_OK/S_FALSE?
|
||||
HRESULT WINAPI uiprivHrGetMessageW(LPMSG msg, HWND hwnd, UINT filterMin, UINT filterMax, BOOL *ret)
|
||||
{
|
||||
SetLastError(0);
|
||||
*ret = GetMessageW(msg, hwnd, filterMin, filterMax);
|
||||
if (*ret < 0)
|
||||
return lastErrorToHRESULT();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI uiprivHrPostMessageW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
BOOL ret;
|
||||
|
||||
SetLastError(0);
|
||||
ret = PostMessageW(hwnd, uMsg, wParam, lParam);
|
||||
if (ret == 0)
|
||||
return lastErrorToHRESULT();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI uiprivHrLoadIconW(HINSTANCE hInstance, LPCWSTR name, HICON *hIcon)
|
||||
{
|
||||
SetLastError(0);
|
||||
*hIcon = LoadIconW(hInstance, name);
|
||||
if (*hIcon == NULL)
|
||||
return lastErrorToHRESULT();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT WINAPI uiprivHrLoadCursorW(HINSTANCE hInstance, LPCWSTR name, HCURSOR *hCursor)
|
||||
{
|
||||
SetLastError(0);
|
||||
*hCursor = LoadCursorW(hInstance, name);
|
||||
if (*hCursor == NULL)
|
||||
return lastErrorToHRESULT();
|
||||
return S_OK;
|
||||
}
|
|
@ -73,17 +73,6 @@ const char *uiInit(uiInitOptions *o)
|
|||
|
||||
// LONGTERM set DPI awareness
|
||||
|
||||
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 initerr(ce, L"GetLastError() ==", GetLastError());
|
||||
|
||||
if (registerWindowClass(hDefaultIcon, hDefaultCursor) == 0)
|
||||
return ieLastErr("registering uiWindow window class");
|
||||
|
||||
|
|
|
@ -59,24 +59,6 @@ static void processMessage(MSG *msg)
|
|||
DispatchMessageW(msg);
|
||||
}
|
||||
|
||||
static int waitMessage(MSG *msg)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = GetMessageW(msg, NULL, 0, 0);
|
||||
if (res < 0) {
|
||||
logLastError(L"error calling GetMessage()");
|
||||
return 0; // bail out on error
|
||||
}
|
||||
return res != 0; // returns false on WM_QUIT
|
||||
}
|
||||
|
||||
void uiMain(void)
|
||||
{
|
||||
while (uiMainStep(1))
|
||||
;
|
||||
}
|
||||
|
||||
void uiMainSteps(void)
|
||||
{
|
||||
// don't need to do anything here
|
||||
|
@ -98,12 +80,7 @@ int uiMainStep(int wait)
|
|||
{
|
||||
MSG msg;
|
||||
|
||||
if (wait) {
|
||||
if (!waitMessage(&msg))
|
||||
return 0;
|
||||
processMessage(&msg);
|
||||
return 1;
|
||||
}
|
||||
if (wait) { /* deleted */ }
|
||||
|
||||
// don't wait for a message
|
||||
switch (peekMessage(&msg)) {
|
||||
|
@ -117,18 +94,6 @@ int uiMainStep(int wait)
|
|||
return 1; // no message
|
||||
}
|
||||
|
||||
void uiQuit(void)
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
void uiQueueMain(void (*f)(void *data), void *data)
|
||||
{
|
||||
if (PostMessageW(utilWindow, msgQueued, (WPARAM) f, (LPARAM) data) == 0)
|
||||
// LONGTERM this is likely not safe to call across threads (allocates memory)
|
||||
logLastError(L"error queueing function to run on main thread");
|
||||
}
|
||||
|
||||
static std::map<uiprivTimer *, bool> timers;
|
||||
|
||||
void uiTimer(int milliseconds, int (*f)(void *data), void *data)
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
// - It handles executing functions queued to run by uiQueueMain().
|
||||
// TODO explain why it isn't message-only
|
||||
|
||||
#define utilWindowClass L"libui_utilWindowClass"
|
||||
|
||||
HWND utilWindow;
|
||||
|
||||
static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
void (*qf)(void *);
|
||||
|
@ -33,10 +29,6 @@ static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, L
|
|||
case WM_WININICHANGE:
|
||||
issueWM_WININICHANGE(wParam, lParam);
|
||||
return 0;
|
||||
case msgQueued:
|
||||
qf = (void (*)(void *)) wParam;
|
||||
(*qf)((void *) lParam);
|
||||
return 0;
|
||||
case WM_TIMER:
|
||||
timer = (uiprivTimer *) wParam;
|
||||
if (!(*(timer->f))(timer->data)) {
|
||||
|
@ -49,34 +41,6 @@ static LRESULT CALLBACK utilWindowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, L
|
|||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
const char *initUtilWindow(HICON hDefaultIcon, HCURSOR hDefaultCursor)
|
||||
{
|
||||
WNDCLASSW wc;
|
||||
|
||||
ZeroMemory(&wc, sizeof (WNDCLASSW));
|
||||
wc.lpszClassName = utilWindowClass;
|
||||
wc.lpfnWndProc = utilWindowWndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = hDefaultIcon;
|
||||
wc.hCursor = hDefaultCursor;
|
||||
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
|
||||
if (RegisterClass(&wc) == 0)
|
||||
// see init.cpp for an explanation of the =s
|
||||
return "=registering utility window class";
|
||||
|
||||
utilWindow = CreateWindowExW(0,
|
||||
utilWindowClass, L"libui utility window",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
0, 0, 100, 100,
|
||||
NULL, NULL, hInstance, NULL);
|
||||
if (utilWindow == NULL)
|
||||
return "=creating utility window";
|
||||
// and just to be safe
|
||||
EnableWindow(utilWindow, FALSE);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uninitUtilWindow(void)
|
||||
{
|
||||
if (DestroyWindow(utilWindow) == 0)
|
||||
|
|
Loading…
Reference in New Issue