/[rdesktop]/sourceforge.net/trunk/seamlessrdp/ServerExe/HookDll/hookdll.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/seamlessrdp/ServerExe/HookDll/hookdll.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1162 - (show annotations)
Mon Mar 20 09:36:23 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 11097 byte(s)
Handle z order changes properly by waiting until the reordering is complete
and then examining the result.

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Seamless windows - Remote server hook DLL
4
5 Based on code copyright (C) 2004-2005 Martin Wickett
6
7 Copyright (C) Peter Åstrand <astrand@cendio.se> 2005-2006
8 Copyright (C) Pierre Ossman <ossman@cendio.se> 2006
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include <stdio.h>
26 #include <stdarg.h>
27
28 #include <windows.h>
29 #include <winuser.h>
30
31 #include "../vchannel.h"
32
33 #define DLL_EXPORT __declspec(dllexport)
34
35 #ifdef __GNUC__
36 #define SHARED __attribute__((section ("SHAREDDATA"), shared))
37 #else
38 #define SHARED
39 #endif
40
41 // Shared DATA
42 #pragma data_seg ( "SHAREDDATA" )
43
44 // this is the total number of processes this dll is currently attached to
45 int g_instance_count SHARED = 0;
46
47 // blocks for locally generated events
48 HWND g_block_move_hwnd SHARED = NULL;
49 RECT g_block_move SHARED = { 0, 0, 0, 0 };
50 HWND g_blocked_zchange[2] SHARED = { NULL, NULL };
51 HWND g_blocked_focus SHARED = NULL;
52 HWND g_blocked_state_hwnd SHARED = NULL;
53 int g_blocked_state SHARED = -1;
54
55 #pragma data_seg ()
56
57 #pragma comment(linker, "/section:SHAREDDATA,rws")
58
59 #define FOCUS_MSG_NAME "WM_SEAMLESS_FOCUS"
60 static UINT g_wm_seamless_focus;
61
62 static HHOOK g_cbt_hook = NULL;
63 static HHOOK g_wndproc_hook = NULL;
64 static HHOOK g_wndprocret_hook = NULL;
65
66 static HINSTANCE g_instance = NULL;
67
68 static HANDLE g_mutex = NULL;
69
70 static void
71 update_position(HWND hwnd)
72 {
73 RECT rect, blocked;
74 HWND blocked_hwnd;
75
76 if (!GetWindowRect(hwnd, &rect))
77 {
78 debug("GetWindowRect failed!\n");
79 return;
80 }
81
82 WaitForSingleObject(g_mutex, INFINITE);
83 blocked_hwnd = hwnd;
84 memcpy(&blocked, &g_block_move, sizeof(RECT));
85 ReleaseMutex(g_mutex);
86
87 if ((hwnd == blocked_hwnd) && (rect.left == blocked.left) && (rect.top == blocked.top)
88 && (rect.right == blocked.right) && (rect.bottom == blocked.bottom))
89 return;
90
91 vchannel_write("POSITION,0x%p,%d,%d,%d,%d,0x%x",
92 hwnd,
93 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
94 }
95
96 static void
97 update_zorder(HWND hwnd)
98 {
99 HWND behind;
100 HWND block_hwnd, block_behind;
101
102 WaitForSingleObject(g_mutex, INFINITE);
103 block_hwnd = g_blocked_zchange[0];
104 block_behind = g_blocked_zchange[1];
105 ReleaseMutex(g_mutex);
106
107 behind = GetNextWindow(hwnd, GW_HWNDPREV);
108 while (behind)
109 {
110 LONG style;
111
112 style = GetWindowLong(behind, GWL_STYLE);
113
114 if ((!(style & WS_CHILD) || (style & WS_POPUP)) && (style & WS_VISIBLE))
115 break;
116
117 behind = GetNextWindow(behind, GW_HWNDPREV);
118 }
119
120 if ((hwnd == block_hwnd) && (behind == block_behind))
121 return;
122
123 vchannel_write("ZCHANGE,0x%p,0x%p,0x%x", hwnd, behind, 0);
124 }
125
126 static LRESULT CALLBACK
127 wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
128 {
129 HWND hwnd, parent;
130 UINT msg;
131 WPARAM wparam;
132 LPARAM lparam;
133
134 LONG style;
135
136 if (code < 0)
137 goto end;
138
139 hwnd = ((CWPSTRUCT *) details)->hwnd;
140 msg = ((CWPSTRUCT *) details)->message;
141 wparam = ((CWPSTRUCT *) details)->wParam;
142 lparam = ((CWPSTRUCT *) details)->lParam;
143
144 style = GetWindowLong(hwnd, GWL_STYLE);
145
146 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
147 but they exist nonetheless. */
148 if ((style & WS_CHILD) && !(style & WS_POPUP))
149 goto end;
150
151 if (style & WS_POPUP)
152 {
153 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
154 if (!parent)
155 parent = (HWND) - 1;
156 }
157 else
158 parent = NULL;
159
160 switch (msg)
161 {
162 case WM_WINDOWPOSCHANGED:
163 {
164 WINDOWPOS *wp = (WINDOWPOS *) lparam;
165
166 if (wp->flags & SWP_SHOWWINDOW)
167 {
168 unsigned short title[150];
169 int state;
170
171 vchannel_write("CREATE,0x%p,0x%p,0x%x", hwnd, parent, 0);
172
173 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
174
175 vchannel_write("TITLE,0x%x,%s,0x%x", hwnd,
176 vchannel_strfilter_unicode(title), 0);
177
178 if (style & WS_MAXIMIZE)
179 state = 2;
180 else if (style & WS_MINIMIZE)
181 state = 1;
182 else
183 state = 0;
184
185 update_position(hwnd);
186
187 vchannel_write("STATE,0x%p,0x%x,0x%x", hwnd, state, 0);
188 }
189
190 if (wp->flags & SWP_HIDEWINDOW)
191 vchannel_write("DESTROY,0x%p,0x%x", hwnd, 0);
192
193 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
194 break;
195
196 if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
197 update_position(hwnd);
198
199 break;
200 }
201
202 case WM_SIZE:
203 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
204 break;
205 update_position(hwnd);
206 break;
207
208 case WM_MOVE:
209 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
210 break;
211 update_position(hwnd);
212 break;
213
214 case WM_DESTROY:
215 if (!(style & WS_VISIBLE))
216 break;
217 vchannel_write("DESTROY,0x%p,0x%x", hwnd, 0);
218 break;
219
220 default:
221 break;
222 }
223
224 end:
225 return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
226 }
227
228 static LRESULT CALLBACK
229 wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)
230 {
231 HWND hwnd, parent;
232 UINT msg;
233 WPARAM wparam;
234 LPARAM lparam;
235
236 LONG style;
237
238 if (code < 0)
239 goto end;
240
241 hwnd = ((CWPRETSTRUCT *) details)->hwnd;
242 msg = ((CWPRETSTRUCT *) details)->message;
243 wparam = ((CWPRETSTRUCT *) details)->wParam;
244 lparam = ((CWPRETSTRUCT *) details)->lParam;
245
246 style = GetWindowLong(hwnd, GWL_STYLE);
247
248 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
249 but they exist nonetheless. */
250 if ((style & WS_CHILD) && !(style & WS_POPUP))
251 goto end;
252
253 if (style & WS_POPUP)
254 {
255 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
256 if (!parent)
257 parent = (HWND) - 1;
258 }
259 else
260 parent = NULL;
261
262 switch (msg)
263 {
264 case WM_WINDOWPOSCHANGED:
265 {
266 WINDOWPOS *wp = (WINDOWPOS *) lparam;
267
268 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
269 break;
270
271 if (!(wp->flags & SWP_NOZORDER))
272 update_zorder(hwnd);
273
274 break;
275 }
276
277
278 case WM_SETTEXT:
279 {
280 unsigned short title[150];
281 if (!(style & WS_VISIBLE))
282 break;
283 /* We cannot use the string in lparam because
284 we need unicode. */
285 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
286 vchannel_write("TITLE,0x%p,%s,0x%x", hwnd,
287 vchannel_strfilter_unicode(title), 0);
288 break;
289 }
290
291 default:
292 break;
293 }
294
295 if (msg == g_wm_seamless_focus)
296 {
297 /* FIXME: SetActiveWindow() kills menus. Need to find a clean
298 way to solve this. */
299 if ((GetActiveWindow() != hwnd) && !parent)
300 SetActiveWindow(hwnd);
301 }
302
303 end:
304 return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details);
305 }
306
307 static LRESULT CALLBACK
308 cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
309 {
310 if (code < 0)
311 goto end;
312
313 switch (code)
314 {
315 case HCBT_MINMAX:
316 {
317 int show, state, blocked;
318 HWND blocked_hwnd;
319
320 WaitForSingleObject(g_mutex, INFINITE);
321 blocked_hwnd = g_blocked_state_hwnd;
322 blocked = g_blocked_state;
323 ReleaseMutex(g_mutex);
324
325 show = LOWORD(lparam);
326
327 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
328 || (show == SW_RESTORE))
329 state = 0;
330 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
331 state = 1;
332 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
333 state = 2;
334 else
335 {
336 debug("Unexpected show: %d", show);
337 break;
338 }
339
340 if ((blocked_hwnd != (HWND) wparam) || (blocked != state))
341 vchannel_write("STATE,0x%p,0x%x,0x%x", (HWND) wparam, state,
342 0);
343
344 break;
345 }
346
347 default:
348 break;
349 }
350
351 end:
352 return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
353 }
354
355 DLL_EXPORT void
356 SetHooks(void)
357 {
358 if (!g_cbt_hook)
359 g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
360
361 if (!g_wndproc_hook)
362 g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
363
364 if (!g_wndprocret_hook)
365 g_wndprocret_hook =
366 SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
367 }
368
369 DLL_EXPORT void
370 RemoveHooks(void)
371 {
372 if (g_cbt_hook)
373 UnhookWindowsHookEx(g_cbt_hook);
374
375 if (g_wndproc_hook)
376 UnhookWindowsHookEx(g_wndproc_hook);
377
378 if (g_wndprocret_hook)
379 UnhookWindowsHookEx(g_wndprocret_hook);
380 }
381
382 DLL_EXPORT void
383 SafeMoveWindow(HWND hwnd, int x, int y, int width, int height)
384 {
385 WaitForSingleObject(g_mutex, INFINITE);
386 g_block_move_hwnd = hwnd;
387 g_block_move.left = x;
388 g_block_move.top = y;
389 g_block_move.right = x + width;
390 g_block_move.bottom = y + height;
391 ReleaseMutex(g_mutex);
392
393 SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER);
394
395 WaitForSingleObject(g_mutex, INFINITE);
396 g_block_move_hwnd = NULL;
397 memset(&g_block_move, 0, sizeof(RECT));
398 ReleaseMutex(g_mutex);
399 }
400
401 DLL_EXPORT void
402 SafeZChange(HWND hwnd, HWND behind)
403 {
404 WaitForSingleObject(g_mutex, INFINITE);
405 g_blocked_zchange[0] = hwnd;
406 g_blocked_zchange[1] = behind;
407 ReleaseMutex(g_mutex);
408
409 if (behind == NULL)
410 behind = HWND_TOP;
411
412 SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
413
414 WaitForSingleObject(g_mutex, INFINITE);
415 g_blocked_zchange[0] = NULL;
416 g_blocked_zchange[1] = NULL;
417 ReleaseMutex(g_mutex);
418 }
419
420 DLL_EXPORT void
421 SafeFocus(HWND hwnd)
422 {
423 WaitForSingleObject(g_mutex, INFINITE);
424 g_blocked_focus = hwnd;
425 ReleaseMutex(g_mutex);
426
427 SendMessage(hwnd, g_wm_seamless_focus, 0, 0);
428
429 WaitForSingleObject(g_mutex, INFINITE);
430 g_blocked_focus = NULL;
431 ReleaseMutex(g_mutex);
432 }
433
434 DLL_EXPORT void
435 SafeSetState(HWND hwnd, int state)
436 {
437 WaitForSingleObject(g_mutex, INFINITE);
438 g_blocked_state_hwnd = hwnd;
439 g_blocked_state = state;
440 ReleaseMutex(g_mutex);
441
442 if (state == 0)
443 ShowWindow(hwnd, SW_RESTORE);
444 else if (state == 1)
445 ShowWindow(hwnd, SW_MINIMIZE);
446 else if (state == 2)
447 ShowWindow(hwnd, SW_MAXIMIZE);
448 else
449 debug("Invalid state %d sent.", state);
450
451 WaitForSingleObject(g_mutex, INFINITE);
452 g_blocked_state_hwnd = NULL;
453 g_blocked_state = -1;
454 ReleaseMutex(g_mutex);
455 }
456
457 DLL_EXPORT int
458 GetInstanceCount()
459 {
460 return g_instance_count;
461 }
462
463 BOOL APIENTRY
464 DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
465 {
466 switch (ul_reason_for_call)
467 {
468 case DLL_PROCESS_ATTACH:
469 // remember our instance handle
470 g_instance = hinstDLL;
471
472 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
473 if (!g_mutex)
474 return FALSE;
475
476 WaitForSingleObject(g_mutex, INFINITE);
477 ++g_instance_count;
478 ReleaseMutex(g_mutex);
479
480 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
481
482 vchannel_open();
483
484 break;
485
486 case DLL_THREAD_ATTACH:
487 break;
488
489 case DLL_THREAD_DETACH:
490 break;
491
492 case DLL_PROCESS_DETACH:
493 WaitForSingleObject(g_mutex, INFINITE);
494 --g_instance_count;
495 ReleaseMutex(g_mutex);
496
497 vchannel_close();
498
499 CloseHandle(g_mutex);
500
501 break;
502 }
503
504 return TRUE;
505 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26