--- sourceforge.net/trunk/seamlessrdp/ServerExe/main.c 2006/03/09 15:26:35 1077 +++ sourceforge.net/trunk/seamlessrdp/ServerExe/main.c 2006/03/16 15:42:32 1150 @@ -24,6 +24,8 @@ #include #include +#include +#include #include "vchannel.h" @@ -31,13 +33,25 @@ #define APP_NAME "SeamlessRDP Shell" +#ifndef WM_WTSSESSION_CHANGE +#define WM_WTSSESSION_CHANGE 0x02B1 +#endif +#ifndef WTS_REMOTE_CONNECT +#define WTS_REMOTE_CONNECT 0x3 +#endif + /* Global data */ static HINSTANCE g_instance; +static HWND g_hwnd; typedef void (*set_hooks_proc_t) (); typedef void (*remove_hooks_proc_t) (); typedef int (*get_instance_count_proc_t) (); +typedef void (*move_window_proc_t) (HWND hwnd, int x, int y, int width, int height); + +static move_window_proc_t g_move_window_fn = NULL; + static void message(const char *text) { @@ -67,35 +81,40 @@ return head; } -static BOOL CALLBACK enum_cb(HWND hwnd, LPARAM lparam) +static BOOL CALLBACK +enum_cb(HWND hwnd, LPARAM lparam) { RECT rect; - char title[150]; + unsigned short title[150]; LONG styles; int state; + HWND parent; styles = GetWindowLong(hwnd, GWL_STYLE); if (!(styles & WS_VISIBLE)) return TRUE; - vchannel_write("CREATE1,0x%p,0x%x", hwnd, 0); + if (styles & WS_POPUP) + parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT); + else + parent = NULL; - if (!GetWindowRect(hwnd, &rect)) { + vchannel_write("CREATE,0x%p,0x%p,0x%x", hwnd, parent, 0); + + if (!GetWindowRect(hwnd, &rect)) + { debug("GetWindowRect failed!"); return TRUE; } - vchannel_write("POSITION1,0x%p,%d,%d,%d,%d,0x%x", + vchannel_write("POSITION,0x%p,%d,%d,%d,%d,0x%x", hwnd, - rect.left, rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - 0); + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0); - GetWindowText(hwnd, title, sizeof(title)); + GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title)); - /* FIXME: Strip title of dangerous characters */ + vchannel_write("TITLE,0x%x,%s,0x%x", hwnd, vchannel_strfilter_unicode(title), 0); if (styles & WS_MAXIMIZE) state = 2; @@ -104,8 +123,7 @@ else state = 0; - vchannel_write("SETSTATE1,0x%p,%s,0x%x,0x%x", - hwnd, title, state, 0); + vchannel_write("STATE,0x%p,0x%x,0x%x", hwnd, state, 0); return TRUE; } @@ -125,6 +143,33 @@ } static void +do_state(HWND hwnd, int state) +{ + if (state == 0) + ShowWindow(hwnd, SW_RESTORE); + else if (state == 1) + ShowWindow(hwnd, SW_MINIMIZE); + else if (state == 2) + ShowWindow(hwnd, SW_MAXIMIZE); + else + debug("Invalid state %d sent.", state); +} + +static void +do_position(HWND hwnd, int x, int y, int width, int height) +{ + g_move_window_fn(hwnd, x, y, width, height); +} + +static void +do_zchange(HWND hwnd, HWND behind) +{ + if (behind == NULL) + behind = HWND_TOP; + SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +static void process_cmds(void) { char line[VCHANNEL_MAX_LINE]; @@ -132,9 +177,8 @@ char *p, *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8; - while ((size = vchannel_read(line, sizeof(line))) >= 0) { - debug("Got: %s", line); - + while ((size = vchannel_read(line, sizeof(line))) >= 0) + { p = line; tok1 = get_token(&p); @@ -148,9 +192,69 @@ if (strcmp(tok1, "SYNC") == 0) do_sync(); + else if (strcmp(tok1, "STATE") == 0) + do_state((HWND) strtoul(tok2, NULL, 0), strtol(tok3, NULL, 0)); + else if (strcmp(tok1, "POSITION") == 0) + do_position((HWND) strtoul(tok2, NULL, 0), strtol(tok3, NULL, 0), + strtol(tok4, NULL, 0), strtol(tok5, NULL, 0), strtol(tok6, NULL, + 0)); + else if (strcmp(tok1, "ZCHANGE") == 0) + do_zchange((HWND) strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0)); } } +static LRESULT CALLBACK +wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (message == WM_WTSSESSION_CHANGE) + { + if (wparam == WTS_REMOTE_CONNECT) + { + /* These get reset on each reconnect */ + SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0); + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0); + vchannel_write("HELLO,0x%08x", 1); + } + } + + return DefWindowProc(hwnd, message, wparam, lparam); +} + +static BOOL +register_class(void) +{ + WNDCLASSEX wcx; + + memset(&wcx, 0, sizeof(wcx)); + + wcx.cbSize = sizeof(wcx); + wcx.lpfnWndProc = wndproc; + wcx.hInstance = g_instance; + wcx.lpszClassName = "SeamlessClass"; + + return RegisterClassEx(&wcx); +} + +static BOOL +create_wnd(void) +{ + if (!register_class()) + return FALSE; + + g_hwnd = CreateWindow("SeamlessClass", + "Seamless Window", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, g_instance, (LPVOID) NULL); + + if (!g_hwnd) + return FALSE; + + return TRUE; +} + int WINAPI WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmdline, int cmdshow) { @@ -162,7 +266,7 @@ g_instance = instance; - hookdll = LoadLibrary("hookdll.dll"); + hookdll = LoadLibrary("seamlessrdp.dll"); if (!hookdll) { message("Could not load hook DLL. Unable to continue."); @@ -172,8 +276,9 @@ set_hooks_fn = (set_hooks_proc_t) GetProcAddress(hookdll, "SetHooks"); remove_hooks_fn = (remove_hooks_proc_t) GetProcAddress(hookdll, "RemoveHooks"); instance_count_fn = (get_instance_count_proc_t) GetProcAddress(hookdll, "GetInstanceCount"); + g_move_window_fn = (move_window_proc_t) GetProcAddress(hookdll, "SafeMoveWindow"); - if (!set_hooks_fn || !remove_hooks_fn || !instance_count_fn) + if (!set_hooks_fn || !remove_hooks_fn || !instance_count_fn || !g_move_window_fn) { FreeLibrary(hookdll); message("Hook DLL doesn't contain the correct functions. Unable to continue."); @@ -188,14 +293,28 @@ return -1; } + if (!create_wnd()) + { + FreeLibrary(hookdll); + message("Couldn't create a window to catch events."); + return -1; + } + + WTSRegisterSessionNotification(g_hwnd, NOTIFY_FOR_THIS_SESSION); + vchannel_open(); + vchannel_write("HELLO,0x%08x", 0); + set_hooks_fn(); /* Since we don't see the entire desktop we must resize windows immediatly. */ SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0); + /* Disable screen saver since we cannot catch its windows. */ + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0); + if (strlen(cmdline) == 0) { message("No command line specified."); @@ -207,6 +326,7 @@ DWORD exitcode; PROCESS_INFORMATION proc_info; STARTUPINFO startup_info; + MSG msg; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.cb = sizeof(STARTUPINFO); @@ -218,6 +338,11 @@ { do { + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } process_cmds(); Sleep(100); GetExitCodeProcess(proc_info.hProcess, &exitcode); @@ -238,6 +363,8 @@ } } + WTSUnRegisterSessionNotification(g_hwnd); + remove_hooks_fn(); FreeLibrary(hookdll);