From 29c51b6348eb554d5f759dabb66d843ebf1f11ad Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 21 Apr 2019 13:54:39 -0400 Subject: [PATCH] Started readding the Windows code; added the Windows version headers to the docs as well now since I'm cleaning up winapi.hpp as well. --- doc/using-libui.md | 21 +++++-- windows/init.cpp | 119 +++++++++++++++++++++++++++++++++++++ windows/meson.build | 30 ++++++++++ windows/uipriv_windows.hpp | 11 ++++ windows/winapi.hpp | 34 +++++++++++ 5 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 windows/init.cpp create mode 100644 windows/meson.build create mode 100644 windows/uipriv_windows.hpp create mode 100644 windows/winapi.hpp diff --git a/doc/using-libui.md b/doc/using-libui.md index 7c7de399..c0f22b5d 100644 --- a/doc/using-libui.md +++ b/doc/using-libui.md @@ -32,7 +32,7 @@ If you are using libui as a static library, you'll need to add the line #define uiStatic ``` -*before* including `ui.h`, as that informs `ui.h` to tell the compiler that the functions in `ui.h` are not dynamically loaded. +*before* including `ui.h`, as that informs `ui.h` to tell the compiler that the functions in `ui.h` are not dynamically loaded. (You may, of course, also do this on your compiler's command line.) ### OS-Specific Headers @@ -42,16 +42,25 @@ Each OS has a special OS-specific header that provides the necessary additional #### Windows -The OS-specific header is `ui_windows.h`. The only OS header that is necessary is ``: +The OS-specific header is `ui_windows.h`. The only OS header that is necessary is ``. You should also specify the Unicode, type-strictness, and minimum-version macros before including ``: ```c +#define UNICODE +#define _UNICODE +#define STRICT +#define STRICT_TYPED_ITEMIDS +// This sets the minimum Windows API version to the minimum for libui: Windows Vista. +// Feel free to make this higher if your code will not run on all versions libui supports. +#define WINVER 0x0600 +#define _WIN32_WINNT 0x0600 +#define _WIN32_WINDOWS 0x0600 +#define _WIN32_IE 0x0700 +#define NTDDI_VERSION 0x06000000 #include #include "ui.h" #include "ui_windows.h" ``` -TODO(andlabs): version constants - #### Unix The OS-specific header is `ui_unix.h`. Only `` needs to be included beforehand: @@ -101,6 +110,7 @@ libui needs to be linked against a set of standard Windows DLLs, preferably in t - user32.dll (MSVC: `user32.lib`, MinGW: `-luser32`) - kernel32.dll - gdi32.dll +- comctl32.dll - TODO **Furthermore**, because libui requires Common Controls v6, you will also need to provide a manifest file that specifies Common Controls v6, and ideally also speciifes the versions of Windows your executable runs on. For instance, the one used by libui.dll is a good place to start: @@ -112,7 +122,8 @@ TODO Ideally, you should provide this as a resource that's linked into your program: ```rc -#include +// Extra #defines above elided for brevity; these should be included too. +#include CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "manifest.xml" ``` diff --git a/windows/init.cpp b/windows/init.cpp new file mode 100644 index 00000000..4a49f326 --- /dev/null +++ b/windows/init.cpp @@ -0,0 +1,119 @@ +// 6 april 2015 +#include "uipriv_windows.hpp" +#include "attrstr.hpp" + +HINSTANCE uipriv_hInstance = NULL; +int uipriv_nCmdShow; + +//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) + +// see https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483 +EXTERN_C IMAGE_DOS_HEADER __ImageBase; + +int uiInit(void *options, uiInitError *err) +{ + STARTUPINFOW si; + const char *ce; + HICON hDefaultIcon; + HCURSOR hDefaultCursor; + NONCLIENTMETRICSW ncm; + INITCOMMONCONTROLSEX icc; + HRESULT hr; + + if (!uiprivInitCheckParams(options, err, NULL)) + return 0; + + if (uipriv_hInstance == NULL) + uipriv_hInstance = (HINSTANCE) (&__ImageBase); + uipriv_nCmdShow = SW_SHOWDEFAULT; + GetStartupInfoW(&si); + if ((si.dwFlags & STARTF_USESHOWWINDOW) != 0) + uipriv_nCmdShow = si.wShowWindow; + + // 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"); + + 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"); + + if (initContainer(hDefaultIcon, hDefaultCursor) == 0) + return ieLastErr("initializing uiWindowsMakeContainer() 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); + // LONGTERM initialize COM security + // LONGTERM (windows vista) turn off COM exception handling + + hr = initDraw(); + if (hr != S_OK) + return ieHRESULT("initializing Direct2D", hr); + + hr = uiprivInitDrawText(); + if (hr != S_OK) + return ieHRESULT("initializing DirectWrite", hr); + + if (registerAreaClass(hDefaultIcon, hDefaultCursor) == 0) + return ieLastErr("registering uiArea window class"); + + if (registerMessageFilter() == 0) + return ieLastErr("registering libui message filter"); + + if (registerD2DScratchClass(hDefaultIcon, hDefaultCursor) == 0) + return ieLastErr("initializing D2D scratch window class"); + + hr = uiprivInitImage(); + if (hr != S_OK) + return ieHRESULT("initializing WIC", hr); + + return NULL; +} + +void uiUninit(void) +{ +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + hInstance = hinstDLL; + return TRUE; +} diff --git a/windows/meson.build b/windows/meson.build new file mode 100644 index 00000000..952dad7b --- /dev/null +++ b/windows/meson.build @@ -0,0 +1,30 @@ +# 23 march 2019 + +windows = import('windows') + +libui_sources += [ + 'windows/init.cpp', +] + +# resources.rc only contains the libui manifest. +# For a DLL, we have to include this directly, so we do so. +# Windows won't link resources in static libraries, so including this would have no effect. +# In those cases, we just need them to include the manifest with the executable (or link it directly into the output executable themselves); they can also customize the manifest as they see fit (assuming nothing breaks in the process). +if libui_mode == 'shared' + libui_sources += [ + windows.compile_resources('resources.rc', + args: libui_manifest_args, + depend_files: ['libui.manifest']), + ] +endif + +foreach lib : ['user32', 'kernel32', 'gdi32', 'comctl32'] + libui_deps += [ + meson.get_compiler('cpp').find_library(lib, + required: true), + ] +endforeach + +if libui_OS == 'windows' and libui_mode == 'shared' and not libui_MSVC + error('Sorry, but libui for Windows can currently only be built as a static library with MinGW. You will need to either build as a static library or switch to MSVC.') +endif diff --git a/windows/uipriv_windows.hpp b/windows/uipriv_windows.hpp new file mode 100644 index 00000000..dcb58a3e --- /dev/null +++ b/windows/uipriv_windows.hpp @@ -0,0 +1,11 @@ +// 21 april 2016 +#include "winapi.hpp" +#include "../ui.h" +#include "../ui_windows.h" +#include "../common/uipriv.h" +//TODO#include "compilerver.hpp" + +// init.cpp +extern HINSTANCE uipriv_hInstance; +extern int uipriv_nCmdShow; +//TODOextern HFONT hMessageFont; diff --git a/windows/winapi.hpp b/windows/winapi.hpp new file mode 100644 index 00000000..ab6cdd19 --- /dev/null +++ b/windows/winapi.hpp @@ -0,0 +1,34 @@ +// 31 may 2015 +#define UNICODE +#define _UNICODE +#define STRICT +#define STRICT_TYPED_ITEMIDS + +// for the manifest +#ifndef uiStatic +#define ISOLATION_AWARE_ENABLED 1 +#endif + +// get Windows version right; right now Windows Vista +// unless otherwise stated, all values from Microsoft's sdkddkver.h +// TODO is all of this necessary? how is NTDDI_VERSION used? +#define WINVER 0x0600 /* from Microsoft's winnls.h */ +#define _WIN32_WINNT 0x0600 +#define _WIN32_WINDOWS 0x0600 /* from Microsoft's pdh.h */ +#define _WIN32_IE 0x0700 +#define NTDDI_VERSION 0x06000000 + +// The MinGW-w64 header has an unverified IDWriteTypography definition. +// TODO I can confirm this myself, but I don't know how long it will take for them to note my adjustments... Either way, I have to confirm this myself. +// TODO change the check from _MSC_VER to a MinGW-w64-specific check +// TODO keep track of what else is guarded by this +#ifndef _MSC_VER +#define __MINGW_USE_BROKEN_INTERFACE +#endif + +#include + +// Microsoft's resource compiler will segfault if we feed it headers it was not designed to handle +#ifndef RC_INVOKED +#include +#endif