diff --git a/VERSION b/VERSION
index 5f4d0e5a..e28124f0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-a12-135-gd6805cfa0f+1
\ No newline at end of file
+a12-142-g3f13485ced+1
\ No newline at end of file
diff --git a/c-host/include/interface/capture.h b/c-host/include/interface/capture.h
index 69bc9768..9a48892e 100644
--- a/c-host/include/interface/capture.h
+++ b/c-host/include/interface/capture.h
@@ -76,6 +76,7 @@ typedef struct CaptureInterface
const char * (*getName )();
bool (*create )();
bool (*init )(void * pointerShape, const unsigned int pointerSize);
+ void (*stop )();
bool (*deinit )();
void (*free )();
unsigned int (*getMaxFrameSize)();
diff --git a/c-host/include/interface/platform.h b/c-host/include/interface/platform.h
index 6064f344..ec65349c 100644
--- a/c-host/include/interface/platform.h
+++ b/c-host/include/interface/platform.h
@@ -47,5 +47,6 @@ typedef struct osEventHandle osEventHandle;
osEventHandle * os_createEvent(bool autoReset);
void os_freeEvent (osEventHandle * handle);
bool os_waitEvent (osEventHandle * handle, unsigned int timeout);
+bool os_waitEvents (osEventHandle * handles[], int count, bool waitAll, unsigned int timeout);
bool os_signalEvent(osEventHandle * handle);
bool os_resetEvent (osEventHandle * handle);
\ No newline at end of file
diff --git a/c-host/looking-glass-host b/c-host/looking-glass-host
deleted file mode 100755
index e71e951f..00000000
Binary files a/c-host/looking-glass-host and /dev/null differ
diff --git a/c-host/platform/Windows/CMakeLists.txt b/c-host/platform/Windows/CMakeLists.txt
index e8dff3fe..aca29196 100644
--- a/c-host/platform/Windows/CMakeLists.txt
+++ b/c-host/platform/Windows/CMakeLists.txt
@@ -7,12 +7,21 @@ include_directories(
add_library(platform_Windows STATIC
src/platform.c
- src/windebug.c
+ src/windebug.c
+ src/mousehook.c
)
add_subdirectory("capture")
+FIND_PROGRAM(WINDRES_EXECUTABLE NAMES "windres.exe" DOC "windres executable")
+ADD_CUSTOM_COMMAND(TARGET platform_Windows POST_BUILD
+ WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
+ COMMAND ${WINDRES_EXECUTABLE} -i resource.rc -o "${PROJECT_BINARY_DIR}/resource.o"
+ VERBATIM
+)
+
target_link_libraries(platform_Windows
+ "${PROJECT_BINARY_DIR}/resource.o"
capture
setupapi
)
diff --git a/c-host/platform/Windows/app.manifest b/c-host/platform/Windows/app.manifest
new file mode 100644
index 00000000..b157af14
--- /dev/null
+++ b/c-host/platform/Windows/app.manifest
@@ -0,0 +1,12 @@
+
+
+
+ Hello World
+
+
+
+
+
+
+
+
diff --git a/c-host/platform/Windows/capture/DXGI/src/dxgi.c b/c-host/platform/Windows/capture/DXGI/src/dxgi.c
index 11d5a1f3..32be656f 100644
--- a/c-host/platform/Windows/capture/DXGI/src/dxgi.c
+++ b/c-host/platform/Windows/capture/DXGI/src/dxgi.c
@@ -55,7 +55,7 @@ Pointer;
struct iface
{
bool initialized;
- bool reinit;
+ bool stop;
IDXGIFactory1 * factory;
IDXGIAdapter1 * adapter;
IDXGIOutput * output;
@@ -158,7 +158,7 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
this->pointerSize = pointerSize;
this->pointerUsed = 0;
- this->reinit = false;
+ this->stop = false;
this->texRIndex = 0;
this->texWIndex = 0;
os_resetEvent(this->frameEvent);
@@ -402,6 +402,13 @@ fail:
return false;
}
+static void dxgi_stop()
+{
+ this->stop = true;
+ os_signalEvent(this->frameEvent );
+ os_signalEvent(this->pointerEvent);
+}
+
static bool dxgi_deinit()
{
assert(this);
@@ -497,7 +504,7 @@ static unsigned int dxgi_getMaxFrameSize()
return this->height * this->pitch;
}
-inline static CaptureResult dxgi_capture_int()
+static CaptureResult dxgi_capture()
{
assert(this);
assert(this->initialized);
@@ -641,36 +648,18 @@ inline static CaptureResult dxgi_capture_int()
return CAPTURE_RESULT_OK;
}
-static CaptureResult dxgi_capture(bool * hasFrameUpdate, bool * hasPointerUpdate)
-{
- CaptureResult result = dxgi_capture_int(hasFrameUpdate, hasPointerUpdate);
-
- // signal pending events if the result was any form of failure or reinit
- if (result != CAPTURE_RESULT_OK && result != CAPTURE_RESULT_TIMEOUT)
- {
- this->reinit = true;
- os_signalEvent(this->frameEvent );
- os_signalEvent(this->pointerEvent);
- }
-
- return result;
-}
-
static CaptureResult dxgi_getFrame(CaptureFrame * frame)
{
assert(this);
assert(this->initialized);
- if (this->reinit)
- return CAPTURE_RESULT_REINIT;
-
if (!os_waitEvent(this->frameEvent, TIMEOUT_INFINITE))
{
DEBUG_ERROR("Failed to wait on the frame event");
return CAPTURE_RESULT_ERROR;
}
- if (this->reinit)
+ if (this->stop)
return CAPTURE_RESULT_REINIT;
Texture * tex = &this->texture[this->texRIndex];
@@ -695,16 +684,13 @@ static CaptureResult dxgi_getPointer(CapturePointer * pointer)
assert(this);
assert(this->initialized);
- if (this->reinit)
- return CAPTURE_RESULT_REINIT;
-
if (!os_waitEvent(this->pointerEvent, TIMEOUT_INFINITE))
{
DEBUG_ERROR("Failed to wait on the pointer event");
return CAPTURE_RESULT_ERROR;
}
- if (this->reinit)
+ if (this->stop)
return CAPTURE_RESULT_REINIT;
Pointer p;
@@ -761,6 +747,7 @@ struct CaptureInterface Capture_DXGI =
.getName = dxgi_getName,
.create = dxgi_create,
.init = dxgi_init,
+ .stop = dxgi_stop,
.deinit = dxgi_deinit,
.free = dxgi_free,
.getMaxFrameSize = dxgi_getMaxFrameSize,
diff --git a/c-host/platform/Windows/capture/NVFBC/CMakeLists.txt b/c-host/platform/Windows/capture/NVFBC/CMakeLists.txt
index e3d0e607..7977ac60 100644
--- a/c-host/platform/Windows/capture/NVFBC/CMakeLists.txt
+++ b/c-host/platform/Windows/capture/NVFBC/CMakeLists.txt
@@ -12,3 +12,7 @@ target_include_directories(capture_NVFBC
PRIVATE
src
)
+
+target_link_libraries(capture_NVFBC
+ platform_Windows
+)
diff --git a/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c b/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c
index c4c0a356..2921699b 100644
--- a/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c
+++ b/c-host/platform/Windows/capture/NVFBC/src/nvfbc.c
@@ -19,8 +19,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "interface/capture.h"
#include "interface/platform.h"
-#include "debug.h"
+#include "windows/platform.h"
#include "windows/windebug.h"
+#include "windows/mousehook.h"
#include
#include
#include
@@ -30,7 +31,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
struct iface
{
- bool reinit;
+ bool stop;
NvFBCHandle nvfbc;
void * pointerShape;
@@ -43,7 +44,10 @@ struct iface
NvFBCFrameGrabInfo grabInfo;
osEventHandle * frameEvent;
- HANDLE cursorEvent;
+ osEventHandle * cursorEvents[2];
+
+ int mouseX, mouseY, mouseHotX, mouseHotY;
+ bool mouseVisible;
};
static struct iface * this = NULL;
@@ -64,6 +68,13 @@ static void getDesktopSize(unsigned int * width, unsigned int * height)
*height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
}
+static void on_mouseMove(int x, int y)
+{
+ this->mouseX = x;
+ this->mouseY = y;
+ os_signalEvent(this->cursorEvents[1]);
+}
+
static const char * nvfbc_getName()
{
return "NVFBC (NVidia Frame Buffer Capture)";
@@ -95,13 +106,14 @@ static bool nvfbc_create()
static bool nvfbc_init(void * pointerShape, const unsigned int pointerSize)
{
- this->reinit = false;
+ this->stop = false;
this->pointerShape = pointerShape;
this->pointerSize = pointerSize;
getDesktopSize(&this->width, &this->height);
os_resetEvent(this->frameEvent);
+ HANDLE event;
if (!NvFBCToSysSetup(
this->nvfbc,
BUFFER_FMT_ARGB10,
@@ -111,18 +123,30 @@ static bool nvfbc_init(void * pointerShape, const unsigned int pointerSize)
0,
(void **)&this->frameBuffer,
NULL,
- &this->cursorEvent
+ &event
))
{
return false;
}
+ this->cursorEvents[0] = os_wrapEvent(event);
+ this->cursorEvents[1] = os_createEvent(true);
+ mouseHook_install(on_mouseMove);
+
Sleep(100);
return true;
}
+static void nvfbc_stop()
+{
+ this->stop = true;
+ os_signalEvent(this->cursorEvents[1]);
+ os_signalEvent(this->frameEvent);
+}
+
static bool nvfbc_deinit()
{
+ mouseHook_remove();
return true;
}
@@ -172,7 +196,7 @@ static CaptureResult nvfbc_getFrame(CaptureFrame * frame)
return CAPTURE_RESULT_ERROR;
}
- if (this->reinit)
+ if (this->stop)
return CAPTURE_RESULT_REINIT;
frame->width = this->grabInfo.dwWidth;
@@ -195,37 +219,33 @@ static CaptureResult nvfbc_getFrame(CaptureFrame * frame)
static CaptureResult nvfbc_getPointer(CapturePointer * pointer)
{
- while(true)
+ osEventHandle * events[2];
+ memcpy(&events, &this->cursorEvents, sizeof(osEventHandle *) * 2);
+ if (!os_waitEvents(events, 2, false, TIMEOUT_INFINITE))
{
- bool sig = false;
- switch(WaitForSingleObject((HANDLE)this->cursorEvent, INFINITE))
- {
- case WAIT_OBJECT_0:
- sig = true;
- break;
-
- case WAIT_ABANDONED:
- continue;
-
- case WAIT_TIMEOUT:
- continue;
-
- case WAIT_FAILED:
- DEBUG_WINERROR("Wait for cursor event failed", GetLastError());
- return CAPTURE_RESULT_ERROR;
- }
-
- if (sig)
- break;
-
- DEBUG_ERROR("Unknown wait event return code");
+ DEBUG_ERROR("Failed to wait on the cursor events");
return CAPTURE_RESULT_ERROR;
}
- if (this->reinit)
+ if (this->stop)
return CAPTURE_RESULT_REINIT;
- return NvFBCToSysGetCursor(this->nvfbc, pointer, this->pointerShape, this->pointerSize);
+ CaptureResult result;
+ pointer->shapeUpdate = false;
+ if (events[0])
+ {
+ result = NvFBCToSysGetCursor(this->nvfbc, pointer, this->pointerShape, this->pointerSize);
+ this->mouseVisible = pointer->visible;
+ this->mouseHotX = pointer->x;
+ this->mouseHotY = pointer->y;
+ if (result != CAPTURE_RESULT_OK)
+ return result;
+ }
+
+ pointer->visible = this->mouseVisible;
+ pointer->x = this->mouseX - this->mouseHotX;
+ pointer->y = this->mouseY - this->mouseHotY;
+ return CAPTURE_RESULT_OK;
}
struct CaptureInterface Capture_NVFBC =
@@ -233,6 +253,7 @@ struct CaptureInterface Capture_NVFBC =
.getName = nvfbc_getName,
.create = nvfbc_create,
.init = nvfbc_init,
+ .stop = nvfbc_stop,
.deinit = nvfbc_deinit,
.free = nvfbc_free,
.getMaxFrameSize = nvfbc_getMaxFrameSize,
diff --git a/c-host/platform/Windows/include/windows/mousehook.h b/c-host/platform/Windows/include/windows/mousehook.h
new file mode 100644
index 00000000..ef71a3e1
--- /dev/null
+++ b/c-host/platform/Windows/include/windows/mousehook.h
@@ -0,0 +1,23 @@
+/*
+Looking Glass - KVM FrameRelay (KVMFR) Client
+Copyright (C) 2017-2019 Geoffrey McRae
+https://looking-glass.hostfission.com
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+typedef void (*MouseHookFn)(int x, int y);
+
+void mouseHook_install(MouseHookFn callback);
+void mouseHook_remove();
\ No newline at end of file
diff --git a/c-host/platform/Windows/include/windows/platform.h b/c-host/platform/Windows/include/windows/platform.h
new file mode 100644
index 00000000..1a098324
--- /dev/null
+++ b/c-host/platform/Windows/include/windows/platform.h
@@ -0,0 +1,23 @@
+/*
+Looking Glass - KVM FrameRelay (KVMFR) Client
+Copyright (C) 2017-2019 Geoffrey McRae
+https://looking-glass.hostfission.com
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "interface/platform.h"
+#include
+
+osEventHandle * os_wrapEvent(HANDLE event);
\ No newline at end of file
diff --git a/c-host/platform/Windows/resource.rc b/c-host/platform/Windows/resource.rc
new file mode 100644
index 00000000..8af0ed12
--- /dev/null
+++ b/c-host/platform/Windows/resource.rc
@@ -0,0 +1,3 @@
+#include "winuser.h"
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"
diff --git a/c-host/platform/Windows/src/mousehook.c b/c-host/platform/Windows/src/mousehook.c
new file mode 100644
index 00000000..a3da302a
--- /dev/null
+++ b/c-host/platform/Windows/src/mousehook.c
@@ -0,0 +1,98 @@
+/*
+Looking Glass - KVM FrameRelay (KVMFR) Client
+Copyright (C) 2017-2019 Geoffrey McRae
+https://looking-glass.hostfission.com
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "windows/mousehook.h"
+#include "windows/windebug.h"
+#include "platform.h"
+
+#include
+#include
+
+struct mouseHook
+{
+ bool installed;
+ HHOOK hook;
+ MouseHookFn callback;
+};
+
+static struct mouseHook mouseHook = { 0 };
+
+// forwards
+static LRESULT WINAPI mouseHook_hook(int nCode, WPARAM wParam, LPARAM lParam);
+static LRESULT msg_callback(WPARAM wParam, LPARAM lParam);
+
+void mouseHook_install(MouseHookFn callback)
+{
+ struct MSG_CALL_FUNCTION cf;
+ cf.fn = msg_callback;
+ cf.wParam = 1;
+ cf.lParam = (LPARAM)callback;
+ sendAppMessage(WM_CALL_FUNCTION, 0, (LPARAM)&cf);
+}
+
+void mouseHook_remove()
+{
+ struct MSG_CALL_FUNCTION cf;
+ cf.fn = msg_callback;
+ cf.wParam = 0;
+ cf.lParam = 0;
+ sendAppMessage(WM_CALL_FUNCTION, 0, (LPARAM)&cf);
+}
+
+static LRESULT msg_callback(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam)
+ {
+ if (mouseHook.installed)
+ {
+ DEBUG_WARN("Mouse hook already installed");
+ return 0;
+ }
+
+ mouseHook.hook = SetWindowsHookEx(WH_MOUSE_LL, mouseHook_hook, NULL, 0);
+ if (!mouseHook.hook)
+ {
+ DEBUG_WINERROR("Failed to install the mouse hook", GetLastError());
+ return 0;
+ }
+
+ mouseHook.installed = true;
+ mouseHook.callback = (MouseHookFn)lParam;
+ }
+ else
+ {
+ if (!mouseHook.installed)
+ return 0;
+
+ UnhookWindowsHookEx(mouseHook.hook);
+ mouseHook.installed = false;
+ }
+
+ return 0;
+}
+
+static LRESULT WINAPI mouseHook_hook(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ if (nCode == HC_ACTION && wParam == WM_MOUSEMOVE)
+ {
+ MSLLHOOKSTRUCT *msg = (MSLLHOOKSTRUCT *)lParam;
+ mouseHook.callback(msg->pt.x, msg->pt.y);
+ }
+ return CallNextHookEx(mouseHook.hook, nCode, wParam, lParam);
+}
\ No newline at end of file
diff --git a/c-host/platform/Windows/src/platform.c b/c-host/platform/Windows/src/platform.c
index 3a139fa4..bdaa736b 100644
--- a/c-host/platform/Windows/src/platform.c
+++ b/c-host/platform/Windows/src/platform.c
@@ -17,6 +17,9 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "platform.h"
+#include "windows/platform.h"
+#include "windows/mousehook.h"
#include
#include
@@ -37,6 +40,7 @@ struct osThreadHandle
void * opaque;
HANDLE handle;
DWORD threadID;
+
int resultCode;
};
@@ -45,6 +49,7 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
switch(msg)
{
case WM_CLOSE:
+ mouseHook_remove();
DestroyWindow(hwnd);
break;
@@ -52,6 +57,12 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
PostQuitMessage(0);
break;
+ case WM_CALL_FUNCTION:
+ {
+ struct MSG_CALL_FUNCTION * cf = (struct MSG_CALL_FUNCTION *)lParam;
+ return cf->fn(cf->wParam, cf->lParam);
+ }
+
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
@@ -65,6 +76,22 @@ static int appThread(void * opaque)
return result;
}
+LRESULT sendAppMessage(UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ return SendMessage(messageWnd, Msg, wParam, lParam);
+}
+
+static BOOL WINAPI CtrlHandler(DWORD dwCtrlType)
+{
+ if (dwCtrlType == CTRL_C_EVENT)
+ {
+ SendMessage(messageWnd, WM_CLOSE, 0, 0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int result = 0;
@@ -139,6 +166,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
free(infData);
SetupDiDestroyDeviceInfoList(deviceInfoSet);
+ // setup a handler for ctrl+c
+ SetConsoleCtrlHandler(CtrlHandler, TRUE);
+
// create a message window so that our message pump works
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
@@ -169,6 +199,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
{
TranslateMessage(&msg);
DispatchMessage(&msg);
+ continue;
}
else if (bRet < 0)
{
@@ -312,6 +343,11 @@ osEventHandle * os_createEvent(bool autoReset)
return (osEventHandle*)event;
}
+osEventHandle * os_wrapEvent(HANDLE event)
+{
+ return (osEventHandle*)event;
+}
+
void os_freeEvent(osEventHandle * handle)
{
CloseHandle((HANDLE)handle);
@@ -346,6 +382,42 @@ bool os_waitEvent(osEventHandle * handle, unsigned int timeout)
}
}
+bool os_waitEvents(osEventHandle * handles[], int count, bool waitAll, unsigned int timeout)
+{
+ const DWORD to = (timeout == TIMEOUT_INFINITE) ? INFINITE : (DWORD)timeout;
+ while(true)
+ {
+ DWORD result = WaitForMultipleObjects(count, (HANDLE*)handles, waitAll, to);
+ if (result >= WAIT_OBJECT_0 && result < count)
+ {
+ // null non signalled events from the handle list
+ for(int i = 0; i < count; ++i)
+ if (i != result && !os_waitEvent(handles[i], 0))
+ handles[i] = NULL;
+ return true;
+ }
+
+ if (result >= WAIT_ABANDONED_0 && result - WAIT_ABANDONED_0 < count)
+ continue;
+
+ switch(result)
+ {
+ case WAIT_TIMEOUT:
+ if (timeout == TIMEOUT_INFINITE)
+ continue;
+
+ return false;
+
+ case WAIT_FAILED:
+ DEBUG_WINERROR("Wait for event failed", GetLastError());
+ return false;
+ }
+
+ DEBUG_ERROR("Unknown wait event return code");
+ return false;
+ }
+}
+
bool os_signalEvent(osEventHandle * handle)
{
return SetEvent((HANDLE)handle);
diff --git a/c-host/platform/Windows/src/platform.h b/c-host/platform/Windows/src/platform.h
new file mode 100644
index 00000000..4d14b224
--- /dev/null
+++ b/c-host/platform/Windows/src/platform.h
@@ -0,0 +1,32 @@
+/*
+Looking Glass - KVM FrameRelay (KVMFR) Client
+Copyright (C) 2017-2019 Geoffrey McRae
+https://looking-glass.hostfission.com
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include
+
+#define WM_CALL_FUNCTION (WM_USER+1)
+
+typedef LRESULT (*CallFunction)(WPARAM wParam, LPARAM lParam);
+struct MSG_CALL_FUNCTION
+{
+ CallFunction fn;
+ WPARAM wParam;
+ LPARAM lParam;
+};
+
+LRESULT sendAppMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
\ No newline at end of file
diff --git a/c-host/src/app.c b/c-host/src/app.c
index 44759dbe..9ff2f632 100644
--- a/c-host/src/app.c
+++ b/c-host/src/app.c
@@ -368,6 +368,7 @@ int app_main()
}
finish:
+ iface->stop();
stopThreads();
exit: