More WPF foundations/boilerplate work.
This commit is contained in:
parent
896beb036d
commit
f93d9a4c91
|
@ -8,10 +8,7 @@ HFONT hMessageFont;
|
||||||
|
|
||||||
HBRUSH hollowBrush;
|
HBRUSH hollowBrush;
|
||||||
|
|
||||||
struct uiInitError {
|
// TODO this won't work if initAlloc() failed
|
||||||
char *msg;
|
|
||||||
char failbuf[256];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define initErrorFormat L"error %s: %s%s%s %I32u (0x%I32X)%s"
|
#define initErrorFormat L"error %s: %s%s%s %I32u (0x%I32X)%s"
|
||||||
#define initErrorArgs wmessage, sysmsg, beforele, label, value, value, afterle
|
#define initErrorArgs wmessage, sysmsg, beforele, label, value, value, afterle
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
// 4 december 2014
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#error msbuild is being dumb and making this a C++ file
|
||||||
|
#endif
|
||||||
|
#include "unmanaged.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// wrappers for allocator of choice
|
||||||
|
// panics on memory exhausted, undefined on heap corruption or other unreliably-detected malady (see http://stackoverflow.com/questions/28761680/is-there-a-windows-api-memory-allocator-deallocator-i-can-use-that-will-just-giv)
|
||||||
|
// new memory is set to zero
|
||||||
|
// passing NULL to tableRealloc() acts like tableAlloc()
|
||||||
|
// passing NULL to tableFree() is a no-op
|
||||||
|
|
||||||
|
static HANDLE heap;
|
||||||
|
|
||||||
|
int initAlloc(void)
|
||||||
|
{
|
||||||
|
heap = HeapCreate(0, 0, 0);
|
||||||
|
return heap != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UINT8(p) ((uint8_t *) (p))
|
||||||
|
#define PVOID(p) ((void *) (p))
|
||||||
|
#define EXTRA (sizeof (const char **))
|
||||||
|
#define DATA(p) PVOID(UINT8(p) + EXTRA)
|
||||||
|
#define BASE(p) PVOID(UINT8(p) - EXTRA)
|
||||||
|
#define CCHAR(p) ((const char **) (p))
|
||||||
|
#define TYPE(p) CCHAR(UINT8(p))
|
||||||
|
|
||||||
|
void uninitAlloc(void)
|
||||||
|
{
|
||||||
|
BOOL hasEntry;
|
||||||
|
PROCESS_HEAP_ENTRY phe;
|
||||||
|
DWORD le;
|
||||||
|
|
||||||
|
hasEntry = FALSE;
|
||||||
|
ZeroMemory(&phe, sizeof (PROCESS_HEAP_ENTRY));
|
||||||
|
while (HeapWalk(heap, &phe) != 0) {
|
||||||
|
// skip non-allocations
|
||||||
|
if ((phe.wFlags & PROCESS_HEAP_ENTRY_BUSY) == 0)
|
||||||
|
continue;
|
||||||
|
if (!hasEntry) {
|
||||||
|
fprintf(stderr, "[libui] leaked allocations:\n");
|
||||||
|
hasEntry = TRUE;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "[libui] %p %s\n", phe.lpData, *TYPE(phe.lpData));
|
||||||
|
}
|
||||||
|
le = GetLastError();
|
||||||
|
SetLastError(le); // just in case
|
||||||
|
if (le != ERROR_NO_MORE_ITEMS)
|
||||||
|
logLastError("error walking heap in uninitAlloc()");
|
||||||
|
if (hasEntry)
|
||||||
|
complain("either you left something around or there's a bug in libui");
|
||||||
|
if (HeapDestroy(heap) == 0)
|
||||||
|
logLastError("error destroying heap in uninitAlloc()");
|
||||||
|
}
|
||||||
|
|
||||||
|
void *uiAlloc(size_t size, const char *type)
|
||||||
|
{
|
||||||
|
void *out;
|
||||||
|
|
||||||
|
out = HeapAlloc(heap, HEAP_ZERO_MEMORY, EXTRA + size);
|
||||||
|
if (out == NULL) {
|
||||||
|
fprintf(stderr, "memory exhausted in uiAlloc()\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
*TYPE(out) = type;
|
||||||
|
return DATA(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *uiRealloc(void *p, size_t size, const char *type)
|
||||||
|
{
|
||||||
|
void *out;
|
||||||
|
|
||||||
|
if (p == NULL)
|
||||||
|
return uiAlloc(size, type);
|
||||||
|
p = BASE(p);
|
||||||
|
out = HeapReAlloc(heap, HEAP_ZERO_MEMORY, p, EXTRA + size);
|
||||||
|
if (out == NULL) {
|
||||||
|
fprintf(stderr, "memory exhausted in uiRealloc()\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return DATA(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiFree(void *p)
|
||||||
|
{
|
||||||
|
if (p == NULL)
|
||||||
|
complain("attempt to uiFree(NULL); there's a bug somewhere");
|
||||||
|
p = BASE(p);
|
||||||
|
if (HeapFree(heap, 0, p) == 0)
|
||||||
|
logLastError("error freeing memory in uiFree()");
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
// 25 february 2015
|
||||||
|
#include "unmanaged.h"
|
||||||
|
|
||||||
|
// uncomment the following line to enable debug messages
|
||||||
|
#define tableDebug
|
||||||
|
// uncomment the following line to halt on a debug message
|
||||||
|
#define tableDebugStop
|
||||||
|
|
||||||
|
#ifdef tableDebug
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
HRESULT logLastError(const char *context)
|
||||||
|
{
|
||||||
|
DWORD le;
|
||||||
|
WCHAR *msg;
|
||||||
|
BOOL parenthesize = FALSE;
|
||||||
|
BOOL localFreeFailed = FALSE;
|
||||||
|
DWORD localFreeLastError;
|
||||||
|
|
||||||
|
le = GetLastError();
|
||||||
|
fprintf(stderr, "%s: ", context);
|
||||||
|
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, le, 0, (LPWSTR) (&msg), 0, NULL) != 0) {
|
||||||
|
fprintf(stderr, "%S (", msg);
|
||||||
|
if (LocalFree(msg) != NULL) {
|
||||||
|
localFreeFailed = TRUE;
|
||||||
|
localFreeLastError = GetLastError();
|
||||||
|
}
|
||||||
|
parenthesize = TRUE;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "GetLastError() == %I32u", le);
|
||||||
|
if (parenthesize)
|
||||||
|
fprintf(stderr, ")");
|
||||||
|
if (localFreeFailed)
|
||||||
|
fprintf(stderr, "; local free of system message failed with last error %I32u", localFreeLastError);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#ifdef tableDebugStop
|
||||||
|
DebugBreak();
|
||||||
|
#endif
|
||||||
|
SetLastError(le);
|
||||||
|
// a function does not have to set a last error
|
||||||
|
// if the last error we get is actually 0, then HRESULT_FROM_WIN32(0) will return S_OK (0 cast to an HRESULT, since 0 <= 0), which we don't want
|
||||||
|
// prevent this by returning E_FAIL, so the rest of the Table code doesn't barge onward
|
||||||
|
if (le == 0)
|
||||||
|
return E_FAIL;
|
||||||
|
return HRESULT_FROM_WIN32(le);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT logHRESULT(const char *context, HRESULT hr)
|
||||||
|
{
|
||||||
|
WCHAR *msg;
|
||||||
|
BOOL parenthesize = FALSE;
|
||||||
|
BOOL localFreeFailed = FALSE;
|
||||||
|
DWORD localFreeLastError;
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: ", context);
|
||||||
|
// this isn't technically documented, but everyone does it, including Microsoft (see the implementation of _com_error::ErrorMessage() in a copy of comdef.h that comes with the Windows DDK)
|
||||||
|
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) hr, 0, (LPWSTR) (&msg), 0, NULL) != 0) {
|
||||||
|
fprintf(stderr, "%S (", msg);
|
||||||
|
if (LocalFree(msg) != NULL) {
|
||||||
|
localFreeFailed = TRUE;
|
||||||
|
localFreeLastError = GetLastError();
|
||||||
|
}
|
||||||
|
parenthesize = TRUE;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "HRESULT == 0x%I32X", hr);
|
||||||
|
if (parenthesize)
|
||||||
|
fprintf(stderr, ")");
|
||||||
|
if (localFreeFailed)
|
||||||
|
fprintf(stderr, "; local free of system message failed with last error %I32u", localFreeLastError);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#ifdef tableDebugStop
|
||||||
|
DebugBreak();
|
||||||
|
#endif
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT logMemoryExhausted(const char *reason)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "memory exhausted %s\n", reason);
|
||||||
|
#ifdef tableDebugStop
|
||||||
|
DebugBreak();
|
||||||
|
#endif
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
HRESULT logLastError(const char *reason)
|
||||||
|
{
|
||||||
|
DWORD le;
|
||||||
|
|
||||||
|
le = GetLastError();
|
||||||
|
// we shouldn't need to do this, but let's do this anyway just to be safe
|
||||||
|
SetLastError(le);
|
||||||
|
if (le == 0)
|
||||||
|
return E_FAIL;
|
||||||
|
return HRESULT_FROM_WIN32(le);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT logHRESULT(const char *reason, HRESULT hr)
|
||||||
|
{
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT logMemoryExhausted(const char *reason)
|
||||||
|
{
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
77
wpf/init.c
77
wpf/init.c
|
@ -2,11 +2,58 @@
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#error msbuild is being dumb and making this a C++ file
|
#error msbuild is being dumb and making this a C++ file
|
||||||
#endif
|
#endif
|
||||||
#include "winapi.h"
|
#include "unmanaged.h"
|
||||||
#include "../ui.h"
|
|
||||||
// TODO to make sure wpfInit() is exported properly
|
|
||||||
#include "wpf.h"
|
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// On the subject of CoInitialize(), or why this isn't in main.cpp:
|
||||||
// If we don't set up the current thread otherwise, the first time .net tries to call out to unmanaged code, it will automatically set up a MTA for COM.
|
// If we don't set up the current thread otherwise, the first time .net tries to call out to unmanaged code, it will automatically set up a MTA for COM.
|
||||||
// This is not what we want; we need a STA instead.
|
// This is not what we want; we need a STA instead.
|
||||||
// Since we're not in control of main(), we can't stick a [STAThread] on it, so we have to do it ourselves.
|
// Since we're not in control of main(), we can't stick a [STAThread] on it, so we have to do it ourselves.
|
||||||
|
@ -15,26 +62,36 @@
|
||||||
// 2) To avoid mixing Windows API headers with .net
|
// 2) To avoid mixing Windows API headers with .net
|
||||||
// See also http://stackoverflow.com/questions/24348205/how-do-i-solve-this-com-issue-in-c
|
// See also http://stackoverflow.com/questions/24348205/how-do-i-solve-this-com-issue-in-c
|
||||||
|
|
||||||
extern void initWPF(void);
|
uiInitOptions options;
|
||||||
//extern void uninitWPF(void);
|
|
||||||
|
|
||||||
void wpfInit(void)
|
const char *uiInit(uiInitOptions *o)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
options = *o;
|
||||||
|
|
||||||
|
if (initAlloc() == 0)
|
||||||
|
return loadLastError("error initializing memory allocations");
|
||||||
|
|
||||||
// TODO https://msdn.microsoft.com/en-us/library/5s8ee185%28v=vs.71%29.aspx use CoInitializeEx()?
|
// TODO https://msdn.microsoft.com/en-us/library/5s8ee185%28v=vs.71%29.aspx use CoInitializeEx()?
|
||||||
hr = CoInitialize(NULL);
|
hr = CoInitialize(NULL);
|
||||||
if (hr != S_OK && hr != S_FALSE)
|
if (hr != S_OK && hr != S_FALSE)
|
||||||
DebugBreak();
|
return loadHRESULT("initializing COM", hr);
|
||||||
|
|
||||||
// now do the rest of initialization on the managed side
|
// now do the rest of initialization on the managed side
|
||||||
initWPF();
|
initWPF();
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*TODO
|
|
||||||
void uiUninit(void)
|
void uiUninit(void)
|
||||||
{
|
{
|
||||||
uninitWPF();
|
uninitWPF();
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
|
uninitAlloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiFreeInitError(const char *err)
|
||||||
|
{
|
||||||
|
uiFree((void *) err);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
@ -70,13 +70,19 @@
|
||||||
<Reference Include="PresentationCore" />
|
<Reference Include="PresentationCore" />
|
||||||
<Reference Include="PresentationFramework" />
|
<Reference Include="PresentationFramework" />
|
||||||
|
|
||||||
|
<!-- TODO readd headers? -->
|
||||||
|
|
||||||
|
<ClCompile Include="alloc.c">
|
||||||
|
<CompileAsManaged>false</CompileAsManaged>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="debug.c">
|
||||||
|
<CompileAsManaged>false</CompileAsManaged>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="init.c">
|
<ClCompile Include="init.c">
|
||||||
<CompileAsManaged>false</CompileAsManaged>
|
<CompileAsManaged>false</CompileAsManaged>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="winapi.h" />
|
<ClCompile Include="text.cpp" />
|
||||||
|
|
||||||
<ClCompile Include="..\ui.h" />
|
|
||||||
|
|
||||||
<ClCompile Include="..\common\areaevents.c">
|
<ClCompile Include="..\common\areaevents.c">
|
||||||
<CompileAsManaged>false</CompileAsManaged>
|
<CompileAsManaged>false</CompileAsManaged>
|
||||||
|
@ -99,8 +105,6 @@
|
||||||
<ClCompile Include="..\common\types.c">
|
<ClCompile Include="..\common\types.c">
|
||||||
<CompileAsManaged>false</CompileAsManaged>
|
<CompileAsManaged>false</CompileAsManaged>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
||||||
<ClCompile Include="..\common\uipriv.h" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
// 25 november 2015
|
||||||
|
#include "uipriv_wpf.hpp"
|
||||||
|
|
||||||
|
static gcroot<Application ^> *app;
|
||||||
|
|
||||||
|
void initWPF(void)
|
||||||
|
{
|
||||||
|
app = new gcroot<Application ^>();
|
||||||
|
*app = gcnew Application();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninitWPF(void)
|
||||||
|
{
|
||||||
|
delete app;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiMain(void)
|
||||||
|
{
|
||||||
|
(*app)->Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiQuit(void)
|
||||||
|
{
|
||||||
|
(*app)->Shutdown();
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
// 25 november 2015
|
||||||
|
#include "uipriv_wpf.hpp"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
using namespace System::Text;
|
||||||
|
using namespace System::Runtime::InteropServices;
|
||||||
|
|
||||||
|
// TODO export?
|
||||||
|
String ^fromUTF8(const char *str)
|
||||||
|
{
|
||||||
|
array<Byte> ^bytes;
|
||||||
|
|
||||||
|
// TODO avoid the cast
|
||||||
|
Marshal::Copy(IntPtr((char *) str), bytes, 0, strlen(str));
|
||||||
|
return Encoding::UTF8->GetString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see http://stackoverflow.com/questions/27526093/convert-systemstring-to-stdstring-in-utf8-which-later-converted-to-char-as
|
||||||
|
char *uiWindowsCLRStringToText(gcroot<System::String ^> str)
|
||||||
|
{
|
||||||
|
array<Byte> ^bytes;
|
||||||
|
char *cstr;
|
||||||
|
|
||||||
|
bytes = Encoding::UTF8->GetBytes(str);
|
||||||
|
cstr = (char *) uiAlloc((bytes->Length + 1) * sizeof (char), "char[]");
|
||||||
|
Marshal::Copy(bytes, 0, IntPtr(cstr), bytes->Length);
|
||||||
|
cstr[bytes->Length] = '\0';
|
||||||
|
return cstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiFreeText(char *c)
|
||||||
|
{
|
||||||
|
uiFree(c);
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
// 7 april 2015
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file assumes that you have included <vccrt.h> and "ui.h" beforehand, as well as #using <System.dll> (but not necessarily beforehand). It provides API-specific functions for interfacing with foreign controls in Windows.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBUI_UI_WINDOWS_H__
|
||||||
|
#define __LIBUI_UI_WINDOWS_H__
|
||||||
|
|
||||||
|
#ifndef __cplusplus_cli
|
||||||
|
#error Sorry; ui_wpf.hpp can currently only be used from C++/CLI code.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
typedef struct uiWindowsSizing uiWindowsSizing;
|
||||||
|
|
||||||
|
typedef struct uiWindowsControl uiWindowsControl;
|
||||||
|
struct uiWindowsControl {
|
||||||
|
uiControl c;
|
||||||
|
};
|
||||||
|
_UI_EXTERN uintmax_t uiWindowsControlType(void);
|
||||||
|
#define uiWindowsControl(this) ((uiWindowsControl *) uiIsA((this), uiWindowsControlType(), 1))
|
||||||
|
|
||||||
|
// TODO document
|
||||||
|
#define uiWindowsDefineControlWithOnDestroy(type, typefn, handle, onDestroy) \
|
||||||
|
static uintmax_t _ ## type ## Type = 0; \
|
||||||
|
uintmax_t typefn(void) \
|
||||||
|
{ \
|
||||||
|
if (_ ## type ## Type == 0) \
|
||||||
|
_ ## type ## Type = uiRegisterType(#type, uiWindowsControlType(), sizeof (type)); \
|
||||||
|
return _ ## type ## Type; \
|
||||||
|
} \
|
||||||
|
static void _ ## type ## CommitDestroy(uiControl *c) \
|
||||||
|
{ \
|
||||||
|
type *hthis = type(c); \
|
||||||
|
onDestroy; \
|
||||||
|
delete hthis->handle; \
|
||||||
|
} \
|
||||||
|
static uintptr_t _ ## type ## Handle(uiControl *c) \
|
||||||
|
{ \
|
||||||
|
return (uintptr_t) (type(c)->handle); \
|
||||||
|
} \
|
||||||
|
static void _ ## type ## ContainerUpdateState(uiControl *c) \
|
||||||
|
{ \
|
||||||
|
/* do nothing */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define uiWindowsDefineControl(type, typefn, handle) \
|
||||||
|
uiWindowsDefineControlWithOnDestroy(type, typefn, handle, (void) hthis;)
|
||||||
|
|
||||||
|
#define uiWindowsFinishNewControl(variable, type) \
|
||||||
|
uiControl(variable)->CommitDestroy = _ ## type ## CommitDestroy; \
|
||||||
|
uiControl(variable)->Handle = _ ## type ## Handle; \
|
||||||
|
uiControl(variable)->ContainerUpdateState = _ ## type ## ContainerUpdateState; \
|
||||||
|
uiWindowsFinishControl(uiControl(variable));
|
||||||
|
|
||||||
|
// This is a function used to set up a control.
|
||||||
|
// Don't call it directly; use uiWindowsFinishNewControl() instead.
|
||||||
|
_UI_EXTERN void uiWindowsFinishControl(uiControl *c);
|
||||||
|
|
||||||
|
// TODO document
|
||||||
|
_UI_EXTERN char *uiWindowsCLRStringToText(gcroot<System::String ^> str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,17 @@
|
||||||
|
// 25 november 2015
|
||||||
|
#include <vcclr.h>
|
||||||
|
#include "../ui.h"
|
||||||
|
#include "ui_wpf.hpp"
|
||||||
|
#include "../common/uipriv.h"
|
||||||
|
#include "unmanaged.h"
|
||||||
|
|
||||||
|
#using <System.dll>
|
||||||
|
#using <WindowsBase.dll>
|
||||||
|
#using <PresentationCore.dll>
|
||||||
|
#using <PresentationFramework.dll>
|
||||||
|
using namespace System;
|
||||||
|
using namespace System::ComponentModel;
|
||||||
|
using namespace System::Windows;
|
||||||
|
|
||||||
|
// text.cpp
|
||||||
|
String ^fromUTF8(const char *);
|
|
@ -0,0 +1,23 @@
|
||||||
|
// 25 november 2015
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#else
|
||||||
|
#include "winapi.h"
|
||||||
|
#include "../ui.h"
|
||||||
|
#include "../common/uipriv.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// main.cpp
|
||||||
|
extern void initWPF(void);
|
||||||
|
extern void uninitWPF(void);
|
||||||
|
|
||||||
|
// alloc.c
|
||||||
|
extern int initAlloc(void);
|
||||||
|
extern void uninitAlloc(void);
|
||||||
|
|
||||||
|
// init.c
|
||||||
|
extern uiInitOptions options;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
18
wpf/wpf.cpp
18
wpf/wpf.cpp
|
@ -55,21 +55,3 @@ void wpfWindowOnClosing(wpfWindow *w, void (*f)(wpfWindow *w, void *data), void
|
||||||
w->onClosing = f;
|
w->onClosing = f;
|
||||||
w->onClosingData = data;
|
w->onClosingData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gcroot<Application ^> app;
|
|
||||||
|
|
||||||
// wpfInit() is in sta.c; see that or details.
|
|
||||||
extern "C" void initWPF(void)
|
|
||||||
{
|
|
||||||
app = gcnew Application();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wpfRun(void)
|
|
||||||
{
|
|
||||||
app->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wpfQuit(void)
|
|
||||||
{
|
|
||||||
app->Shutdown();
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue