From 9a6b598438668e1a2febe53cad90934ef7134062 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Tue, 11 Aug 2020 12:22:22 +1000 Subject: [PATCH] [host] Windows: Implemented service to launch LG as the SYSTEM user Experimental, use at your own peril! This commit adds the ability for the LG host to install and launch with Windows as a system service. To install simply run `looking-glass-host.exe InstallService` or conversely to uninstall `looking-glass-host.exe UninstallService`. --- host/platform/Windows/CMakeLists.txt | 4 ++ host/platform/Windows/src/platform.c | 83 +++++++++++++++++----------- 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/host/platform/Windows/CMakeLists.txt b/host/platform/Windows/CMakeLists.txt index 42b8cb2c..b5162bb4 100644 --- a/host/platform/Windows/CMakeLists.txt +++ b/host/platform/Windows/CMakeLists.txt @@ -7,6 +7,7 @@ include_directories( add_library(platform_Windows STATIC src/platform.c + src/service.c src/mousehook.c ) @@ -23,6 +24,9 @@ target_link_libraries(platform_Windows "${PROJECT_BINARY_DIR}/resource.o" lg_common capture + + userenv + wtsapi32 ) target_include_directories(platform_Windows diff --git a/host/platform/Windows/src/platform.c b/host/platform/Windows/src/platform.c index f63e9f0e..3f7a870a 100644 --- a/host/platform/Windows/src/platform.c +++ b/host/platform/Windows/src/platform.c @@ -18,6 +18,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA */ #include "platform.h" +#include "service.h" #include "windows/mousehook.h" #include @@ -42,9 +43,11 @@ struct AppState int argc; char ** argv; - char executable[MAX_PATH + 1]; - HWND messageWnd; - HMENU trayMenu; + char executable[MAX_PATH + 1]; + HWND messageWnd; + NOTIFYICONDATA iconData; + UINT trayRestartMsg; + HMENU trayMenu; }; static struct AppState app = {0}; @@ -54,6 +57,21 @@ HWND MessageHWND; typedef NTSTATUS (__stdcall *ZwSetTimerResolution_t)(ULONG RequestedResolution, BOOLEAN Set, PULONG ActualResolution); static ZwSetTimerResolution_t ZwSetTimerResolution = NULL; +static void RegisterTrayIcon() +{ + // register our TrayIcon + if (!app.iconData.cbSize) + { + app.iconData.cbSize = sizeof(NOTIFYICONDATA); + app.iconData.hWnd = app.messageWnd; + app.iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + app.iconData.uCallbackMessage = WM_TRAYICON; + strncpy(app.iconData.szTip, "Looking Glass (host)", sizeof(app.iconData.szTip)); + app.iconData.hIcon = LoadIcon(app.hInst, IDI_APPLICATION); + } + Shell_NotifyIcon(NIM_ADD, &app.iconData); +} + LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) @@ -99,28 +117,20 @@ LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } default: - return DefWindowProc(hwnd, msg, wParam, lParam); + if (msg == app.trayRestartMsg) + RegisterTrayIcon(); + break; } - return 0; + + return DefWindowProc(hwnd, msg, wParam, lParam); } static int appThread(void * opaque) { - // register our TrayIcon - NOTIFYICONDATA iconData = - { - .cbSize = sizeof(NOTIFYICONDATA), - .hWnd = app.messageWnd, - .uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP, - .uCallbackMessage = WM_TRAYICON, - .szTip = "Looking Glass (host)" - }; - iconData.hIcon = LoadIcon(app.hInst, IDI_APPLICATION); - Shell_NotifyIcon(NIM_ADD, &iconData); - + RegisterTrayIcon(); int result = app_main(app.argc, app.argv); - Shell_NotifyIcon(NIM_DELETE, &iconData); + Shell_NotifyIcon(NIM_DELETE, &app.iconData); mouseHook_remove(); SendMessage(app.messageWnd, WM_DESTROY, 0, 0); return result; @@ -144,6 +154,21 @@ static BOOL WINAPI CtrlHandler(DWORD dwCtrlType) int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + // convert the command line to the standard argc and argv + LPWSTR * wargv = CommandLineToArgvW(GetCommandLineW(), &app.argc); + app.argv = malloc(sizeof(char *) * app.argc); + for(int i = 0; i < app.argc; ++i) + { + const size_t s = (wcslen(wargv[i])+1) * 2; + app.argv[i] = malloc(s); + wcstombs(app.argv[i], wargv[i], s); + } + LocalFree(wargv); + + GetModuleFileName(NULL, app.executable, sizeof(app.executable)); + if (HandleService(app.argc, app.argv)) + return 0; + /* this is a bit of a hack but without this --help will produce no output in a windows command prompt */ if (!IsDebuggerPresent() && AttachConsole(ATTACH_PARENT_PROCESS)) { @@ -183,19 +208,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine option_register(options); free(logFilePath); - // convert the command line to the standard argc and argv - LPWSTR * wargv = CommandLineToArgvW(GetCommandLineW(), &app.argc); - app.argv = malloc(sizeof(char *) * app.argc); - for(int i = 0; i < app.argc; ++i) - { - const size_t s = (wcslen(wargv[i])+1) * 2; - app.argv[i] = malloc(s); - wcstombs(app.argv[i], wargv[i], s); - } - LocalFree(wargv); - - GetModuleFileName(NULL, app.executable, sizeof(app.executable)); - // setup a handler for ctrl+c SetConsoleCtrlHandler(CtrlHandler, TRUE); @@ -209,13 +221,18 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine wx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wx.hCursor = LoadCursor(NULL, IDC_ARROW); wx.hbrBackground = (HBRUSH)COLOR_APPWORKSPACE; - if (!RegisterClassEx(&wx)) + ATOM class; + if (!(class = RegisterClassEx(&wx))) { DEBUG_ERROR("Failed to register message window class"); result = -1; goto finish; } - app.messageWnd = CreateWindowEx(0, "DUMMY_CLASS", "DUMMY_NAME", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); + + app.trayRestartMsg = RegisterWindowMessage("TaskbarCreated"); + + app.messageWnd = CreateWindowEx(0, MAKEINTATOM(class), NULL, 0, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); + ChangeWindowMessageFilterEx(app.messageWnd, app.trayRestartMsg, MSGFLT_ALLOW, NULL); // set the global MessageHWND = app.messageWnd;