--- sourceforge.net/trunk/seamlessrdp/ServerExe/HookDll/hookdll.c 2006/03/15 13:19:54 1134 +++ sourceforge.net/trunk/seamlessrdp/ServerExe/HookDll/hookdll.c 2006/03/20 10:31:58 1163 @@ -32,16 +32,33 @@ #define DLL_EXPORT __declspec(dllexport) +#ifdef __GNUC__ +#define SHARED __attribute__((section ("SHAREDDATA"), shared)) +#else +#define SHARED +#endif + // Shared DATA #pragma data_seg ( "SHAREDDATA" ) // this is the total number of processes this dll is currently attached to -int g_instance_count = 0; +int g_instance_count SHARED = 0; + +// blocks for locally generated events +HWND g_block_move_hwnd SHARED = NULL; +RECT g_block_move SHARED = { 0, 0, 0, 0 }; +HWND g_blocked_zchange[2] SHARED = { NULL, NULL }; +HWND g_blocked_focus SHARED = NULL; +HWND g_blocked_state_hwnd SHARED = NULL; +int g_blocked_state SHARED = -1; #pragma data_seg () #pragma comment(linker, "/section:SHAREDDATA,rws") +#define FOCUS_MSG_NAME "WM_SEAMLESS_FOCUS" +static UINT g_wm_seamless_focus; + static HHOOK g_cbt_hook = NULL; static HHOOK g_wndproc_hook = NULL; static HHOOK g_wndprocret_hook = NULL; @@ -53,7 +70,8 @@ static void update_position(HWND hwnd) { - RECT rect; + RECT rect, blocked; + HWND blocked_hwnd; if (!GetWindowRect(hwnd, &rect)) { @@ -61,11 +79,50 @@ return; } - vchannel_write("POSITION,0x%p,%d,%d,%d,%d,0x%x", + WaitForSingleObject(g_mutex, INFINITE); + blocked_hwnd = hwnd; + memcpy(&blocked, &g_block_move, sizeof(RECT)); + ReleaseMutex(g_mutex); + + if ((hwnd == blocked_hwnd) && (rect.left == blocked.left) && (rect.top == blocked.top) + && (rect.right == blocked.right) && (rect.bottom == blocked.bottom)) + return; + + 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); } +static void +update_zorder(HWND hwnd) +{ + HWND behind; + HWND block_hwnd, block_behind; + + WaitForSingleObject(g_mutex, INFINITE); + block_hwnd = g_blocked_zchange[0]; + block_behind = g_blocked_zchange[1]; + ReleaseMutex(g_mutex); + + 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)) + return; + + vchannel_write("ZCHANGE", "0x%p,0x%p,0x%x", hwnd, behind, 0); +} + static LRESULT CALLBACK wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details) { @@ -102,7 +159,6 @@ switch (msg) { - case WM_WINDOWPOSCHANGED: { WINDOWPOS *wp = (WINDOWPOS *) lparam; @@ -112,11 +168,11 @@ unsigned short title[150]; int state; - vchannel_write("CREATE,0x%p,0x%p,0x%x", hwnd, parent, 0); + vchannel_write("CREATE", "0x%p,0x%p,0x%x", hwnd, parent, 0); GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title)); - vchannel_write("TITLE,0x%x,%s,0x%x", hwnd, + vchannel_write("TITLE", "0x%x,%s,0x%x", hwnd, vchannel_strfilter_unicode(title), 0); if (style & WS_MAXIMIZE) @@ -128,11 +184,11 @@ update_position(hwnd); - vchannel_write("STATE,0x%p,0x%x,0x%x", hwnd, state, 0); + vchannel_write("STATE", "0x%p,0x%x,0x%x", hwnd, state, 0); } if (wp->flags & SWP_HIDEWINDOW) - vchannel_write("DESTROY,0x%p,0x%x", hwnd, 0); + vchannel_write("DESTROY", "0x%p,0x%x", hwnd, 0); if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE)) break; @@ -140,14 +196,6 @@ if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE)) update_position(hwnd); - if (!(wp->flags & SWP_NOZORDER)) - { - vchannel_write("ZCHANGE,0x%p,0x%p,0x%x", - hwnd, - wp->flags & SWP_NOACTIVATE ? wp-> - hwndInsertAfter : 0, 0); - } - break; } @@ -166,7 +214,7 @@ case WM_DESTROY: if (!(style & WS_VISIBLE)) break; - vchannel_write("DESTROY,0x%p,0x%x", hwnd, 0); + vchannel_write("DESTROY", "0x%p,0x%x", hwnd, 0); break; default: @@ -202,8 +250,31 @@ if ((style & WS_CHILD) && !(style & WS_POPUP)) goto end; + if (style & WS_POPUP) + { + parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT); + if (!parent) + parent = (HWND) - 1; + } + else + parent = NULL; + 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]; @@ -212,7 +283,7 @@ /* We cannot use the string in lparam because we need unicode. */ GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title)); - vchannel_write("TITLE,0x%p,%s,0x%x", hwnd, + vchannel_write("TITLE", "0x%p,%s,0x%x", hwnd, vchannel_strfilter_unicode(title), 0); break; } @@ -221,6 +292,14 @@ break; } + if (msg == g_wm_seamless_focus) + { + /* FIXME: SetActiveWindow() kills menus. Need to find a clean + way to solve this. */ + if ((GetActiveWindow() != hwnd) && !parent) + SetActiveWindow(hwnd); + } + end: return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details); } @@ -235,7 +314,13 @@ { case HCBT_MINMAX: { - int show, state; + int show, state, blocked; + HWND blocked_hwnd; + + WaitForSingleObject(g_mutex, INFINITE); + blocked_hwnd = g_blocked_state_hwnd; + blocked = g_blocked_state; + ReleaseMutex(g_mutex); show = LOWORD(lparam); @@ -251,7 +336,11 @@ debug("Unexpected show: %d", show); break; } - vchannel_write("STATE,0x%p,0x%x,0x%x", (HWND) wparam, state, 0); + + if ((blocked_hwnd != (HWND) wparam) || (blocked != state)) + vchannel_write("STATE", "0x%p,0x%x,0x%x", (HWND) wparam, + state, 0); + break; } @@ -290,6 +379,81 @@ UnhookWindowsHookEx(g_wndprocret_hook); } +DLL_EXPORT void +SafeMoveWindow(HWND hwnd, int x, int y, int width, int height) +{ + WaitForSingleObject(g_mutex, INFINITE); + g_block_move_hwnd = hwnd; + 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); + + WaitForSingleObject(g_mutex, INFINITE); + g_block_move_hwnd = NULL; + memset(&g_block_move, 0, sizeof(RECT)); + ReleaseMutex(g_mutex); +} + +DLL_EXPORT void +SafeZChange(HWND hwnd, HWND behind) +{ + WaitForSingleObject(g_mutex, INFINITE); + g_blocked_zchange[0] = hwnd; + g_blocked_zchange[1] = behind; + ReleaseMutex(g_mutex); + + if (behind == NULL) + behind = HWND_TOP; + + SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + + WaitForSingleObject(g_mutex, INFINITE); + g_blocked_zchange[0] = NULL; + g_blocked_zchange[1] = NULL; + ReleaseMutex(g_mutex); +} + +DLL_EXPORT void +SafeFocus(HWND hwnd) +{ + WaitForSingleObject(g_mutex, INFINITE); + g_blocked_focus = hwnd; + ReleaseMutex(g_mutex); + + SendMessage(hwnd, g_wm_seamless_focus, 0, 0); + + WaitForSingleObject(g_mutex, INFINITE); + g_blocked_focus = NULL; + ReleaseMutex(g_mutex); +} + +DLL_EXPORT void +SafeSetState(HWND hwnd, int state) +{ + WaitForSingleObject(g_mutex, INFINITE); + g_blocked_state_hwnd = hwnd; + g_blocked_state = state; + ReleaseMutex(g_mutex); + + 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_blocked_state_hwnd = NULL; + g_blocked_state = -1; + ReleaseMutex(g_mutex); +} + DLL_EXPORT int GetInstanceCount() { @@ -313,6 +477,8 @@ ++g_instance_count; ReleaseMutex(g_mutex); + g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME); + vchannel_open(); break;