static LRESULT CALLBACK cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam) { if (!g_wm_seamless_focus) goto end; if (code < 0) goto end; switch (code) { case HCBT_MINMAX: { int show, state, blocked; HWND hwnd, blocked_hwnd; unsigned int serial; LONG style; WaitForSingleObject(g_mutex, INFINITE); blocked_hwnd = long_to_hwnd(g_shdata->blocked_state_hwnd); serial = g_shdata->blocked_state_serial; blocked = g_shdata->blocked_state; ReleaseMutex(g_mutex); hwnd = (HWND) wparam; style = GetWindowLong(hwnd, GWL_STYLE); if (!(style & WS_VISIBLE)) break; show = LOWORD(lparam); if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL) || (show == SW_RESTORE)) state = 0; else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED)) state = 1; else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED)) state = 2; else { debug("Unexpected show: %d", show); break; } if ((blocked_hwnd == hwnd) && (blocked == state)) vchannel_write("ACK", "%u", serial); else vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd, state, 0); break; } default: break; } end: return CallNextHookEx(g_cbt_hook, code, wparam, lparam); }
DLL_EXPORT void SafeMoveWindow(unsigned int serial, HWND hwnd, int x, int y, int width, int height) { RECT rect; if (IsZoomed(hwnd)) return; WaitForSingleObject(g_mutex, INFINITE); g_block_move_hwnd = hwnd; g_block_move_serial = serial; g_block_move.left = x; g_block_move.top = y; g_block_move.right = x + width; g_block_move.bottom = y + height; ReleaseMutex(g_mutex); SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER); vchannel_write("ACK", "%u", serial); if (!GetWindowRect(hwnd, &rect)) debug("GetWindowRect failed!\n"); else if ((rect.left != x) || (rect.top != y) || (rect.right != x + width) || (rect.bottom != y + height)) update_position(hwnd); else if (! IsIconic(hwnd)) vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x", hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0); WaitForSingleObject(g_mutex, INFINITE); g_block_move_hwnd = NULL; memset(&g_block_move, 0, sizeof(RECT)); ReleaseMutex(g_mutex); }
static void do_sync(void) { vchannel_write("SYNCBEGIN", "0x0"); EnumWindows(enum_cb, 0); vchannel_write("SYNCEND", "0x0"); }
static void destroy_window(HWND hwnd) { if (! removeHWNDFromHistory(hwnd)) return; vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0); }
static void update_position(HWND hwnd) { RECT rect, blocked; HWND blocked_hwnd; unsigned int serial; WaitForSingleObject(g_mutex, INFINITE); blocked_hwnd = long_to_hwnd(g_shdata->block_move_hwnd); serial = g_shdata->block_move_serial; memcpy(&blocked, &g_shdata->block_move, sizeof(RECT)); ReleaseMutex(g_mutex); vchannel_block(); if (!GetWindowRect(hwnd, &rect)) { debug("GetWindowRect failed!"); goto end; } if ((hwnd == blocked_hwnd) && (rect.left == blocked.left) && (rect.top == blocked.top) && (rect.right == blocked.right) && (rect.bottom == blocked.bottom)) goto end; vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x", hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0); end: vchannel_unblock(); }
static void update_icon(HWND hwnd, HICON icon, int large) { int i, j, size, chunks; char buf[32 * 32 * 4]; char asciibuf[ICON_CHUNK * 2 + 1]; size = extract_icon(icon, buf, sizeof(buf)); if (size <= 0) return; if ((!large && size != 16 * 16 * 4) || (large && size != 32 * 32 * 4)) { debug("Unexpected icon size."); return; } chunks = (size + ICON_CHUNK - 1) / ICON_CHUNK; for (i = 0; i < chunks; i++) { for (j = 0; j < ICON_CHUNK; j++) { if (i * ICON_CHUNK + j >= size) break; sprintf(asciibuf + j * 2, "%02x", (int) (unsigned char) buf[i * ICON_CHUNK + j]); } vchannel_write("SETICON", "0x%08lx,%d,RGBA,%d,%d,%s", hwnd, i, large ? 32 : 16, large ? 32 : 16, asciibuf); } }
EXTERN void SafeMoveWindow(unsigned int serial, HWND hwnd, int x, int y, int width, int height) { RECT rect; if (!g_wm_seamless_focus) return; WaitForSingleObject(g_mutex, INFINITE); g_shdata->block_move_hwnd = hwnd_to_long(hwnd); g_shdata->block_move_serial = serial; g_shdata->block_move.left = x; g_shdata->block_move.top = y; g_shdata->block_move.right = x + width; g_shdata->block_move.bottom = y + height; ReleaseMutex(g_mutex); SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER); vchannel_write("ACK", "%u", serial); if (!GetWindowRect(hwnd, &rect)) debug("GetWindowRect failed!"); else if ((rect.left != x) || (rect.top != y) || (rect.right != x + width) || (rect.bottom != y + height)) update_position(hwnd); WaitForSingleObject(g_mutex, INFINITE); g_shdata->block_move_hwnd = 0; memset(&g_shdata->block_move, 0, sizeof(RECT)); ReleaseMutex(g_mutex); }
static void update_zorder(HWND hwnd) { HWND behind; HWND block_hwnd, block_behind; unsigned int serial; WaitForSingleObject(g_mutex, INFINITE); serial = g_blocked_zchange_serial; block_hwnd = g_blocked_zchange[0]; block_behind = g_blocked_zchange[1]; ReleaseMutex(g_mutex); vchannel_block(); behind = GetNextWindow(hwnd, GW_HWNDPREV); while (behind) { LONG style; style = GetWindowLong(behind, GWL_STYLE); if ((!(style & WS_CHILD) || (style & WS_POPUP)) && (style & WS_VISIBLE)) break; behind = GetNextWindow(behind, GW_HWNDPREV); } if ((hwnd == block_hwnd) && (behind == block_behind)) vchannel_write("ACK", "%u", serial); else { int flags = 0; LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); // handle always on top if (exstyle & WS_EX_TOPMOST) flags |= SEAMLESS_CREATE_TOPMOST; vchannel_write("ZCHANGE", "0x%08lx,0x%08lx,0x%08x", hwnd, behind, flags); } vchannel_unblock(); }
static void SeamlessChannel_process_start_app(char *cmdline, unsigned int token) { PROCESS_INFORMATION proc_info; STARTUPINFO startup_info; BOOL pid; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.cb = sizeof(STARTUPINFO); pid = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &proc_info); if (! pid) { vchannel_write("APP_ID", "0x%08x,0x%08x", token, -1); return; } vchannel_write("APP_ID", "0x%08x,0x%08x", token, proc_info.dwProcessId); // Release handles CloseHandle(proc_info.hProcess); CloseHandle(proc_info.hThread); }
static void update_position(HWND hwnd) { RECT rect, blocked; HWND blocked_hwnd; unsigned int serial; WaitForSingleObject(g_mutex, INFINITE); blocked_hwnd = g_block_move_hwnd; serial = g_block_move_serial; memcpy(&blocked, &g_block_move, sizeof(RECT)); ReleaseMutex(g_mutex); vchannel_block(); if (IsZoomed(hwnd) || IsIconic(hwnd)) { goto end; } else { if (!GetWindowRect(hwnd, &rect)) { debug("GetWindowRect failed!\n"); goto end; } } if ((hwnd == blocked_hwnd) && (rect.left == blocked.left) && (rect.top == blocked.top) && (rect.right == blocked.right) && (rect.bottom == blocked.bottom)) goto end; if ((! IsZoomed(hwnd)) && (rect.left < 0 || rect.top < 0 || rect.bottom > g_screen_height || rect.right > g_screen_width)) { int w = rect.right - rect.left; int h = rect.bottom - rect.top; int x = ((g_screen_width - rect.left) < w) ? (g_screen_width - w) : rect.left; int y = ((g_screen_height - rect.top) < h) ? (g_screen_height - h) : rect.top; x = (rect.left < 0) ? 0 : x; y = (rect.top < 0) ? 0 : y; SetWindowPos(hwnd, NULL, x, y, w, h, SWP_NOACTIVATE | SWP_NOZORDER); goto end; } vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x", hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0); end: vchannel_unblock(); }
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // remember our instance handle g_instance = hinstDLL; g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL"); if (!g_mutex) return FALSE; WaitForSingleObject(g_mutex, INFINITE); ++g_instance_count; ReleaseMutex(g_mutex); g_wm_seamless_focus_request = RegisterWindowMessage(FOCUS_REQUEST_MSG_NAME); g_wm_seamless_focus_release = RegisterWindowMessage(FOCUS_RELEASE_MSG_NAME); g_internal_window = get_internal_window(); vchannel_open(); getScreenSize(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: vchannel_write("DESTROYGRP", "0x%08lx, 0x%08lx", GetCurrentProcessId(), 0); WaitForSingleObject(g_mutex, INFINITE); --g_instance_count; ReleaseMutex(g_mutex); vchannel_close(); CloseHandle(g_mutex); break; } return TRUE; }
EXTERN void SafeSetState(unsigned int serial, HWND hwnd, int state) { LONG style; int curstate; if (!g_wm_seamless_focus) return; vchannel_block(); style = GetWindowLong(hwnd, GWL_STYLE); if (style & WS_MAXIMIZE) curstate = 2; else if (style & WS_MINIMIZE) curstate = 1; else curstate = 0; if (state == curstate) { vchannel_write("ACK", "%u", serial); vchannel_unblock(); return; } WaitForSingleObject(g_mutex, INFINITE); g_shdata->blocked_state_hwnd = hwnd_to_long(hwnd); g_shdata->blocked_state_serial = serial; g_shdata->blocked_state = state; ReleaseMutex(g_mutex); vchannel_unblock(); 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); WaitForSingleObject(g_mutex, INFINITE); g_shdata->blocked_state_hwnd = 0; g_shdata->blocked_state = -1; ReleaseMutex(g_mutex); }
static LRESULT CALLBACK wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details) { HWND hwnd; UINT msg; WPARAM wparam; LPARAM lparam; LONG style; if (!g_wm_seamless_focus) goto end; if (code < 0) goto end; hwnd = ((CWPRETSTRUCT *) details)->hwnd; msg = ((CWPRETSTRUCT *) details)->message; wparam = ((CWPRETSTRUCT *) details)->wParam; lparam = ((CWPRETSTRUCT *) details)->lParam; if (!is_toplevel(hwnd)) { goto end; } style = GetWindowLong(hwnd, GWL_STYLE); switch (msg) { case WM_WINDOWPOSCHANGED: { WINDOWPOS *wp = (WINDOWPOS *) lparam; if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; if (!(wp->flags & SWP_NOZORDER)) update_zorder(hwnd); break; } case WM_SETTEXT: { unsigned short title[150]; if (!(style & WS_VISIBLE)) break; /* We cannot use the string in lparam because we need unicode. */ GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title)); vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd, vchannel_strfilter_unicode(title), 0); break; } case WM_SETICON: { HICON icon; if (!(style & WS_VISIBLE)) break; /* * Somehow, we never get WM_SETICON for the small icon. * So trigger a read of it every time the large one is * changed. */ icon = get_icon(hwnd, 0); if (icon) { update_icon(hwnd, icon, 0); DeleteObject(icon); } } default: break; } if (msg == g_wm_seamless_focus) { /* For some reason, SetForegroundWindow() on menus closes them. Ignore focus requests for menu windows. */ if ((GetForegroundWindow() != hwnd) && !is_menu(hwnd)) SetForegroundWindow(hwnd); vchannel_write("ACK", "%u", g_shdata->blocked_focus_serial); } end: return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details); }
static LRESULT CALLBACK wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details) { HWND hwnd; UINT msg; WPARAM wparam; LPARAM lparam; LONG style; if (!g_wm_seamless_focus) goto end; if (code < 0) goto end; hwnd = ((CWPSTRUCT *) details)->hwnd; msg = ((CWPSTRUCT *) details)->message; wparam = ((CWPSTRUCT *) details)->wParam; lparam = ((CWPSTRUCT *) details)->lParam; if (!is_toplevel(hwnd)) { goto end; } style = GetWindowLong(hwnd, GWL_STYLE); switch (msg) { case WM_WINDOWPOSCHANGED: { WINDOWPOS *wp = (WINDOWPOS *) lparam; if (wp->flags & SWP_SHOWWINDOW) { unsigned short title[150]; int state; DWORD pid; int flags; HICON icon; LONG exstyle; exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); GetWindowThreadProcessId(hwnd, &pid); flags = 0; if (style & DS_MODALFRAME) flags |= SEAMLESS_CREATE_MODAL; // handle always on top if (exstyle & WS_EX_TOPMOST) flags |= SEAMLESS_CREATE_TOPMOST; vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x", hwnd_to_long(hwnd), (long) pid, hwnd_to_long(get_parent(hwnd)), flags); GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title)); vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd, vchannel_strfilter_unicode(title), 0); icon = get_icon(hwnd, 1); if (icon) { update_icon(hwnd, icon, 1); DeleteObject(icon); } icon = get_icon(hwnd, 0); if (icon) { update_icon(hwnd, icon, 0); DeleteObject(icon); } if (style & WS_MAXIMIZE) state = 2; else if (style & WS_MINIMIZE) state = 1; else state = 0; update_position(hwnd); vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd, state, 0); } if (wp->flags & SWP_HIDEWINDOW) vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0); if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE)) update_position(hwnd); break; } case WM_SETICON: if (!(style & WS_VISIBLE)) break; switch (wparam) { case ICON_BIG: if (lparam) update_icon(hwnd, (HICON) lparam, 1); else vchannel_write("DELICON", "0x%08lx,RGBA,32,32", hwnd); break; case ICON_SMALL: case 2: if (lparam) update_icon(hwnd, (HICON) lparam, 0); else vchannel_write("DELICON", "0x%08lx,RGBA,16,16", hwnd); break; default: debug("Weird icon size %d", (int) wparam); } break; case WM_SIZE: if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; update_position(hwnd); break; case WM_MOVE: if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; update_position(hwnd); break; case WM_DESTROY: if (!(style & WS_VISIBLE)) break; vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0); break; default: break; } end: return CallNextHookEx(g_wndproc_hook, code, cur_thread, details); }
void SeamlessChannel_sendDelIcon(HWND hwnd, unsigned int width, unsigned int height) { vchannel_write("DELICON", "0x%08lx,RGBA,%u,%u", hwnd, width, height); }
void SeamlessChannel_sendDestroy(HWND hwnd, int flags) { vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, flags); }
void SeamlessChannel_sendHello(int flags) { vchannel_write("HELLO", "0x%08x", flags); }
int WINAPI WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmdline, int cmdshow) { int success = 0; HANDLE helper = NULL; HMODULE hookdll = NULL; SYSTEM_INFO si; set_hooks_proc_t set_hooks_fn; remove_hooks_proc_t remove_hooks_fn; get_instance_count_proc_t instance_count_fn; int check_counter; if (strlen(cmdline) == 0) { message("No command line specified."); return -1; } if (vchannel_open()) { message("Unable to set up the virtual channel."); return -1; } GetSystemInfo(&si); switch (si.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: hookdll = LoadLibrary("seamlessrdp32.dll"); break; case PROCESSOR_ARCHITECTURE_AMD64: hookdll = LoadLibrary("seamlessrdp64.dll"); break; default: message("Unsupported processor architecture."); break; } if (!hookdll) { message("Could not load hook DLL. Unable to continue."); goto close_vchannel; } 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"); g_zchange_fn = (zchange_proc_t) GetProcAddress(hookdll, "SafeZChange"); g_focus_fn = (focus_proc_t) GetProcAddress(hookdll, "SafeFocus"); g_set_state_fn = (set_state_proc_t) GetProcAddress(hookdll, "SafeSetState"); if (!set_hooks_fn || !remove_hooks_fn || !instance_count_fn || !g_move_window_fn || !g_zchange_fn || !g_focus_fn || !g_set_state_fn) { message ("Hook DLL doesn't contain the correct functions. Unable to continue."); goto close_hookdll; } /* Check if the DLL is already loaded */ switch (instance_count_fn()) { case 0: message("Hook DLL failed to initialize."); goto close_hookdll; break; case 1: break; default: message("Another running instance of Seamless RDP detected."); goto close_hookdll; } helper = launch_helper(); ProcessIdToSessionId(GetCurrentProcessId(), &g_session_id); build_startup_procs(); g_connected = is_connected(); g_desktop_hidden = is_desktop_hidden(); vchannel_write("HELLO", "0x%08x", g_desktop_hidden ? SEAMLESS_HELLO_HIDDEN : 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); /* We don't want windows denying requests to activate windows. */ SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0); if (!launch_app(cmdline)) { // CreateProcess failed. char msg[256]; _snprintf(msg, sizeof(msg), "Unable to launch the requested application:\n%s", cmdline); message(msg); goto unhook; } check_counter = 5; while (check_counter-- || !should_terminate()) { BOOL connected; MSG msg; connected = is_connected(); if (connected && !g_connected) { int flags; /* These get reset on each reconnect */ SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0); flags = SEAMLESS_HELLO_RECONNECT; if (g_desktop_hidden) flags |= SEAMLESS_HELLO_HIDDEN; vchannel_write("HELLO", "0x%08x", flags); } g_connected = connected; if (check_counter < 0) { BOOL hidden; hidden = is_desktop_hidden(); if (hidden && !g_desktop_hidden) vchannel_write("HIDE", "0x%08x", 0); else if (!hidden && g_desktop_hidden) vchannel_write("UNHIDE", "0x%08x", 0); g_desktop_hidden = hidden; check_counter = 5; } while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } process_cmds(); Sleep(100); } success = 1; unhook: remove_hooks_fn(); free_startup_procs(); if (helper) { // Terminate seamlessrdphook32.exe kill_15_9(helper, "SeamlessRDPHook", HELPER_TIMEOUT); } close_hookdll: FreeLibrary(hookdll); close_vchannel: vchannel_close(); // Logoff the user. This is necessary because the session may // have started processes that are not included in Microsofts // list of processes to ignore. Typically ieuser.exe. // FIXME: Only do this if WTSQuerySessionInformation indicates // that we are the initial program. ExitWindows(0, 0); if (success) return 1; else return -1; }
static void create_window(HWND hwnd){ unsigned short *title; DWORD pid; int flags; HICON icon; LONG exstyle; LONG style; HWND parent; node* window; TCHAR classname[256]; window = getWindowFromHistory(hwnd); if (window != NULL) { if (window->is_shown) return; } else { window = addHWDNToHistory(hwnd); if (window == NULL) return; } window->is_shown = TRUE; style = GetWindowLong(hwnd, GWL_STYLE); vchannel_write("DEBUG","NEW WINDOWS"); exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); GetWindowThreadProcessId(hwnd, &pid); parent = get_parent(hwnd); if (getWindowFromHistory(parent) == NULL) parent = 0; flags = 0; if (style & DS_MODALFRAME || exstyle & WS_EX_DLGMODALFRAME) flags |= SEAMLESS_CREATE_MODAL; if (((style & WS_POPUP) || (exstyle & WS_EX_TOOLWINDOW)) && (style & WS_MINIMIZEBOX) == 0 && (style & WS_MAXIMIZEBOX) == 0) { flags |= SEAMLESS_CREATE_POPUP; if (! parent) parent = 0xffffffffL; if (GetClassName(hwnd, classname, 256)) { if ((strcmp(classname, TOOLTIPS_CLASS) == 0) || (strcmp(classname, "Net UI Tool Window") == 0) || (strcmp(classname, "OfficeTooltip") == 0) || (strcmp(classname, "DUIListViewHost") == 0)) { debug("%s", classname); flags |= SEAMLESS_CREATE_TOOLTIP; parent = 0xffffffffL; } else debug("Unknown classname: %s style: 0x%08lx exstyle: 0x%08lx", classname, style, exstyle); } } if (! (style & WS_SIZEBOX)) flags |= SEAMLESS_CREATE_FIXEDSIZE; // handle always on top if (exstyle & WS_EX_TOPMOST) flags |= SEAMLESS_CREATE_TOPMOST; vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x", (long) hwnd, (long) pid, (long) parent, flags); title = malloc(sizeof(unsigned short) * TITLE_SIZE); if (title != NULL) { GetWindowTextW(hwnd, title, TITLE_SIZE); vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd, vchannel_strfilter_unicode(title), 0); } if (window->title) { free(window->title); window->title = NULL; } window->title = title; icon = get_icon(hwnd, 1); if (icon) { update_icon(hwnd, icon, 1); DeleteObject(icon); } icon = get_icon(hwnd, 0); if (icon) { update_icon(hwnd, icon, 0); DeleteObject(icon); } if (style & WS_MAXIMIZE) window->state = 2; else if (style & WS_MINIMIZE) window->state = 1; else window->state = 0; update_position(hwnd); vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd, window->state, 0); if (window->focus) vchannel_write("FOCUS", "0x%08lx", hwnd); }
void SeamlessChannel_sendSyncBegin() { vchannel_write("SYNCBEGIN", "0x0"); }
void SeamlessChannel_sendAppId(unsigned int token, int pid) { vchannel_write("APP_ID", "0x%08x,0x%08x", token, pid); }
void SeamlessChannel_sendUnhide(int flags) { vchannel_write("UNHIDE", "0x%08x", flags); }
void SeamlessChannel_sendSetIcon(HWND hwnd, int chunk, unsigned int width, unsigned int height, char *buf) { vchannel_write("SETICON", "0x%08lx,%d,RGBA,%d,%d,%s", hwnd, chunk, width, height, buf); }
void SeamlessChannel_sendDestroyGrp(unsigned long pid, int flags) { vchannel_write("DESTROYGRP", "0x%08lx, 0x%08lx", pid, flags); }
void SeamlessChannel_sendPosition(HWND hwnd, int x, int y, unsigned int width, unsigned int height, int flags) { vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x", hwnd, x, y, width, height, flags); }
static LRESULT CALLBACK wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details) { HWND hwnd; UINT msg; WPARAM wparam; LPARAM lparam; LONG style; if (code < 0) goto end; hwnd = ((CWPSTRUCT *) details)->hwnd; msg = ((CWPSTRUCT *) details)->message; wparam = ((CWPSTRUCT *) details)->wParam; lparam = ((CWPSTRUCT *) details)->lParam; if (!is_toplevel(hwnd) || is_seamless_internal_windows(hwnd)) { goto end; } style = GetWindowLong(hwnd, GWL_STYLE); switch (msg) { case WM_SHOWWINDOW: { create_window(hwnd); break; } case WM_WINDOWPOSCHANGED: { WINDOWPOS *wp = (WINDOWPOS *) lparam; if (wp->flags & SWP_SHOWWINDOW) { create_window(hwnd); } if (wp->flags & SWP_HIDEWINDOW) destroy_window(hwnd); if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE)) update_position(hwnd); break; } case WM_SETICON: if (!(style & WS_VISIBLE)) break; switch (wparam) { case ICON_BIG: if (lparam) update_icon(hwnd, (HICON) lparam, 1); else vchannel_write("DELICON", "0x%08lx,RGBA,32,32", hwnd); break; case ICON_SMALL: case 2: if (lparam) update_icon(hwnd, (HICON) lparam, 0); else vchannel_write("DELICON", "0x%08lx,RGBA,16,16", hwnd); break; default: debug("Weird icon size %d", (int) wparam); } break; case WM_SIZE: { HWND blocked_hwnd; int blocked; unsigned int serial; node* sw; int state; sw = getWindowFromHistory(hwnd); if (! sw) break; WaitForSingleObject(g_mutex, INFINITE); blocked_hwnd = g_blocked_state_hwnd; serial = g_blocked_state_serial; blocked = g_blocked_state; ReleaseMutex(g_mutex); switch (wparam) { case SIZE_MAXIMIZED: state = 2; break; case SIZE_MINIMIZED: state = 1; break; case SIZE_RESTORED: state = 0; break; } if (sw->state == state) { break; } sw->state = state; if ((blocked_hwnd == hwnd) && (blocked == state)) { vchannel_write("ACK", "%u", serial); } else { vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd, sw->state, 0); } } if (wparam == SIZE_MAXIMIZED || !(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; update_position(hwnd); break; case WM_MOVE: if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; update_position(hwnd); break; case WM_DESTROY: if (!(style & WS_VISIBLE)) break; destroy_window(hwnd); break; default: break; } end: return CallNextHookEx(g_wndproc_hook, code, cur_thread, details); }
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved) { HANDLE filemapping = NULL; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // remember our instance handle g_instance = hinstDLL; g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL"); filemapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shared_variables), "Local\\SeamlessRDPData"); if (filemapping) { /* From MSDN: The initial contents of the pages in a file mapping object backed by the paging file are 0 (zero)." */ g_shdata = MapViewOfFile(filemapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); } if (g_mutex && filemapping && g_shdata && vchannel_open() == 0) { WaitForSingleObject(g_mutex, INFINITE); ++g_shdata->instance_count; ReleaseMutex(g_mutex); g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME); } break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: if (vchannel_is_open()) { vchannel_write("DESTROYGRP", "0x%08lx, 0x%08lx", GetCurrentProcessId(), 0); vchannel_close(); } if (g_mutex) { WaitForSingleObject(g_mutex, INFINITE); if (g_shdata) { --g_shdata->instance_count; UnmapViewOfFile(g_shdata); } ReleaseMutex(g_mutex); CloseHandle(g_mutex); } if (filemapping) { CloseHandle(filemapping); } break; } return TRUE; }
static LRESULT CALLBACK wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details) { HWND hwnd; UINT msg; WPARAM wparam; LPARAM lparam; LONG style; if (code < 0) goto end; hwnd = ((CWPRETSTRUCT *) details)->hwnd; msg = ((CWPRETSTRUCT *) details)->message; wparam = ((CWPRETSTRUCT *) details)->wParam; lparam = ((CWPRETSTRUCT *) details)->lParam; if (!is_toplevel(hwnd) || is_seamless_internal_windows(hwnd)) { goto end; } style = GetWindowLong(hwnd, GWL_STYLE); switch (msg) { case WM_WINDOWPOSCHANGED: { WINDOWPOS *wp = (WINDOWPOS *) lparam; if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; if (!(wp->flags & SWP_NOZORDER)) //update_zorder(hwnd) --> WinDev applications bring if we do that; break; break; } case WM_SETTEXT: { if (!(style & WS_VISIBLE)) break; /* We cannot use the string in lparam because we need unicode. */ if (getWindowFromHistory(hwnd) == NULL){ create_window(hwnd); } else{ BOOLEAN titleIsTheSame = TRUE; int i = 0; unsigned short *title; node* window = getWindowFromHistory(hwnd); if (window == NULL) { break; } title = malloc(sizeof(unsigned short) * TITLE_SIZE); if (title == NULL) break; GetWindowTextW(hwnd, title, TITLE_SIZE); if (window->title != NULL) { for (i = 0; i < TITLE_SIZE; i++) { if (title[i] != window->title[i]) { titleIsTheSame = FALSE; break; } } } else { titleIsTheSame = FALSE; } if (titleIsTheSame) { free(title); break; } vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd, vchannel_strfilter_unicode(title), 0); if (window->title) { free(window->title); window->title; } window->title = title; } break; } case WM_SETICON: { HICON icon; /* * Somehow, we never get WM_SETICON for the small icon. * So trigger a read of it every time the large one is * changed. */ icon = get_icon(hwnd, 0); if (icon) { update_icon(hwnd, icon, 0); DeleteObject(icon); } break; } case WM_ACTIVATE: // http://msdn.microsoft.com/en-us/library/ms646274(VS.85).aspx if (wparam == 0) // WA_INACTIVE break; case WM_SETFOCUS: // Focus gained if (hwnd == g_last_focused_window) break; WaitForSingleObject(g_mutex, INFINITE); g_last_focused_window = hwnd; ReleaseMutex(g_mutex); { node* window; window = getWindowFromHistory(hwnd); if (window == NULL) { window = addHWDNToHistory(hwnd); if (window == NULL) goto end; window->focus = TRUE; goto end; } } vchannel_block(); vchannel_write("FOCUS", "0x%08lx", hwnd); vchannel_unblock(); break; default: break; } end: return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details); }
static BOOL CALLBACK enum_cb(HWND hwnd, LPARAM lparam) { RECT rect; unsigned short title[150]; LONG styles; int state; HWND parent; DWORD pid; int flags; char classname[32]; styles = GetWindowLong(hwnd, GWL_STYLE); if (!(styles & WS_VISIBLE)) return TRUE; /* Since WH_CALLWNDPROC is not effective on cmd.exe, make sure we ignore it during enumeration as well. Make sure to remove this when cmd.exe support has been added, though. */ if (GetClassName(hwnd, classname, sizeof(classname)) && !strcmp(classname, "ConsoleWindowClass")) return TRUE; if (styles & WS_POPUP) parent = (HWND) GetWindowLongPtr(hwnd, GWLP_HWNDPARENT); else parent = NULL; GetWindowThreadProcessId(hwnd, &pid); flags = 0; if (styles & DS_MODALFRAME) flags |= SEAMLESS_CREATE_MODAL; vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x", hwnd_to_long(hwnd), (long) pid, hwnd_to_long(parent), flags); if (!GetWindowRect(hwnd, &rect)) { debug("GetWindowRect failed!"); return TRUE; } vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x", hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0); GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title)); vchannel_write("TITLE", "0x%x,%s,0x%x", hwnd, vchannel_strfilter_unicode(title), 0); if (styles & WS_MAXIMIZE) state = 2; else if (styles & WS_MINIMIZE) state = 1; else state = 0; vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd, state, 0); return TRUE; }
void SeamlessChannel_sendSyncEnd() { vchannel_write("SYNCEND", "0x0"); }