/[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 1177 - (show annotations)
Tue Mar 21 14:42:25 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 12784 byte(s)
Support for window groups and modal windows.

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 unsigned int g_block_move_serial SHARED = 0;
50 RECT g_block_move SHARED = { 0, 0, 0, 0 };
51
52 unsigned int g_blocked_zchange_serial SHARED = 0;
53 HWND g_blocked_zchange[2] SHARED = { NULL, NULL };
54
55 unsigned int g_blocked_focus_serial SHARED = 0;
56 HWND g_blocked_focus SHARED = NULL;
57
58 unsigned int g_blocked_state_serial SHARED = 0;
59 HWND g_blocked_state_hwnd SHARED = NULL;
60 int g_blocked_state SHARED = -1;
61
62 #pragma data_seg ()
63
64 #pragma comment(linker, "/section:SHAREDDATA,rws")
65
66 #define FOCUS_MSG_NAME "WM_SEAMLESS_FOCUS"
67 static UINT g_wm_seamless_focus;
68
69 static HHOOK g_cbt_hook = NULL;
70 static HHOOK g_wndproc_hook = NULL;
71 static HHOOK g_wndprocret_hook = NULL;
72
73 static HINSTANCE g_instance = NULL;
74
75 static HANDLE g_mutex = NULL;
76
77 static void
78 update_position(HWND hwnd)
79 {
80 RECT rect, blocked;
81 HWND blocked_hwnd;
82 unsigned int serial;
83
84 WaitForSingleObject(g_mutex, INFINITE);
85 blocked_hwnd = g_block_move_hwnd;
86 serial = g_block_move_serial;
87 memcpy(&blocked, &g_block_move, sizeof(RECT));
88 ReleaseMutex(g_mutex);
89
90 vchannel_block();
91
92 if (!GetWindowRect(hwnd, &rect))
93 {
94 debug("GetWindowRect failed!\n");
95 goto end;
96 }
97
98 if ((hwnd == blocked_hwnd) && (rect.left == blocked.left) && (rect.top == blocked.top)
99 && (rect.right == blocked.right) && (rect.bottom == blocked.bottom))
100 goto end;
101
102 vchannel_write("POSITION", "0x%p,%d,%d,%d,%d,0x%x",
103 hwnd,
104 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
105
106 end:
107 vchannel_unblock();
108 }
109
110 static void
111 update_zorder(HWND hwnd)
112 {
113 HWND behind;
114 HWND block_hwnd, block_behind;
115 unsigned int serial;
116
117 WaitForSingleObject(g_mutex, INFINITE);
118 serial = g_blocked_zchange_serial;
119 block_hwnd = g_blocked_zchange[0];
120 block_behind = g_blocked_zchange[1];
121 ReleaseMutex(g_mutex);
122
123 vchannel_block();
124
125 behind = GetNextWindow(hwnd, GW_HWNDPREV);
126 while (behind)
127 {
128 LONG style;
129
130 style = GetWindowLong(behind, GWL_STYLE);
131
132 if ((!(style & WS_CHILD) || (style & WS_POPUP)) && (style & WS_VISIBLE))
133 break;
134
135 behind = GetNextWindow(behind, GW_HWNDPREV);
136 }
137
138 if ((hwnd == block_hwnd) && (behind == block_behind))
139 vchannel_write("ACK", "%u", serial);
140 else
141 vchannel_write("ZCHANGE", "0x%p,0x%p,0x%x", hwnd, behind, 0);
142
143 vchannel_unblock();
144 }
145
146 static LRESULT CALLBACK
147 wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
148 {
149 HWND hwnd, parent;
150 UINT msg;
151 WPARAM wparam;
152 LPARAM lparam;
153
154 LONG style;
155
156 if (code < 0)
157 goto end;
158
159 hwnd = ((CWPSTRUCT *) details)->hwnd;
160 msg = ((CWPSTRUCT *) details)->message;
161 wparam = ((CWPSTRUCT *) details)->wParam;
162 lparam = ((CWPSTRUCT *) details)->lParam;
163
164 style = GetWindowLong(hwnd, GWL_STYLE);
165
166 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
167 but they exist nonetheless. */
168 if ((style & WS_CHILD) && !(style & WS_POPUP))
169 goto end;
170
171 if (style & WS_POPUP)
172 {
173 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
174 if (!parent)
175 parent = (HWND) - 1;
176 }
177 else
178 parent = NULL;
179
180 switch (msg)
181 {
182 case WM_WINDOWPOSCHANGED:
183 {
184 WINDOWPOS *wp = (WINDOWPOS *) lparam;
185
186 if (wp->flags & SWP_SHOWWINDOW)
187 {
188 unsigned short title[150];
189 int state;
190 DWORD pid;
191 int flags;
192
193 GetWindowThreadProcessId(hwnd, &pid);
194
195 flags = 0;
196 if (style & DS_MODALFRAME)
197 flags |= SEAMLESS_CREATE_MODAL;
198
199 vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x",
200 (long) hwnd, (long) pid, (long) parent,
201 flags);
202
203 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
204
205 vchannel_write("TITLE", "0x%x,%s,0x%x", hwnd,
206 vchannel_strfilter_unicode(title), 0);
207
208 if (style & WS_MAXIMIZE)
209 state = 2;
210 else if (style & WS_MINIMIZE)
211 state = 1;
212 else
213 state = 0;
214
215 update_position(hwnd);
216
217 vchannel_write("STATE", "0x%p,0x%x,0x%x", hwnd, state, 0);
218 }
219
220 if (wp->flags & SWP_HIDEWINDOW)
221 vchannel_write("DESTROY", "0x%p,0x%x", hwnd, 0);
222
223 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
224 break;
225
226 if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
227 update_position(hwnd);
228
229 break;
230 }
231
232 case WM_SIZE:
233 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
234 break;
235 update_position(hwnd);
236 break;
237
238 case WM_MOVE:
239 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
240 break;
241 update_position(hwnd);
242 break;
243
244 case WM_DESTROY:
245 if (!(style & WS_VISIBLE))
246 break;
247 vchannel_write("DESTROY", "0x%p,0x%x", hwnd, 0);
248 break;
249
250 default:
251 break;
252 }
253
254 end:
255 return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
256 }
257
258 static LRESULT CALLBACK
259 wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)
260 {
261 HWND hwnd, parent;
262 UINT msg;
263 WPARAM wparam;
264 LPARAM lparam;
265
266 LONG style;
267
268 if (code < 0)
269 goto end;
270
271 hwnd = ((CWPRETSTRUCT *) details)->hwnd;
272 msg = ((CWPRETSTRUCT *) details)->message;
273 wparam = ((CWPRETSTRUCT *) details)->wParam;
274 lparam = ((CWPRETSTRUCT *) details)->lParam;
275
276 style = GetWindowLong(hwnd, GWL_STYLE);
277
278 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
279 but they exist nonetheless. */
280 if ((style & WS_CHILD) && !(style & WS_POPUP))
281 goto end;
282
283 if (style & WS_POPUP)
284 {
285 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
286 if (!parent)
287 parent = (HWND) - 1;
288 }
289 else
290 parent = NULL;
291
292 switch (msg)
293 {
294 case WM_WINDOWPOSCHANGED:
295 {
296 WINDOWPOS *wp = (WINDOWPOS *) lparam;
297
298 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
299 break;
300
301 if (!(wp->flags & SWP_NOZORDER))
302 update_zorder(hwnd);
303
304 break;
305 }
306
307
308 case WM_SETTEXT:
309 {
310 unsigned short title[150];
311 if (!(style & WS_VISIBLE))
312 break;
313 /* We cannot use the string in lparam because
314 we need unicode. */
315 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
316 vchannel_write("TITLE", "0x%p,%s,0x%x", hwnd,
317 vchannel_strfilter_unicode(title), 0);
318 break;
319 }
320
321 default:
322 break;
323 }
324
325 if (msg == g_wm_seamless_focus)
326 {
327 /* FIXME: SetActiveWindow() kills menus. Need to find a clean
328 way to solve this. */
329 if ((GetActiveWindow() != hwnd) && !parent)
330 SetActiveWindow(hwnd);
331
332 vchannel_write("ACK", "%u", g_blocked_focus_serial);
333 }
334
335 end:
336 return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details);
337 }
338
339 static LRESULT CALLBACK
340 cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
341 {
342 if (code < 0)
343 goto end;
344
345 switch (code)
346 {
347 case HCBT_MINMAX:
348 {
349 int show, state, blocked;
350 HWND blocked_hwnd;
351 unsigned int serial;
352
353 WaitForSingleObject(g_mutex, INFINITE);
354 blocked_hwnd = g_blocked_state_hwnd;
355 serial = g_blocked_state_serial;
356 blocked = g_blocked_state;
357 ReleaseMutex(g_mutex);
358
359 show = LOWORD(lparam);
360
361 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
362 || (show == SW_RESTORE))
363 state = 0;
364 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
365 state = 1;
366 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
367 state = 2;
368 else
369 {
370 debug("Unexpected show: %d", show);
371 break;
372 }
373
374 if ((blocked_hwnd == (HWND) wparam) && (blocked == state))
375 vchannel_write("ACK", "%u", serial);
376 else
377 vchannel_write("STATE", "0x%p,0x%x,0x%x", (HWND) wparam,
378 state, 0);
379
380 break;
381 }
382
383 default:
384 break;
385 }
386
387 end:
388 return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
389 }
390
391 DLL_EXPORT void
392 SetHooks(void)
393 {
394 if (!g_cbt_hook)
395 g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
396
397 if (!g_wndproc_hook)
398 g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
399
400 if (!g_wndprocret_hook)
401 g_wndprocret_hook =
402 SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
403 }
404
405 DLL_EXPORT void
406 RemoveHooks(void)
407 {
408 if (g_cbt_hook)
409 UnhookWindowsHookEx(g_cbt_hook);
410
411 if (g_wndproc_hook)
412 UnhookWindowsHookEx(g_wndproc_hook);
413
414 if (g_wndprocret_hook)
415 UnhookWindowsHookEx(g_wndprocret_hook);
416 }
417
418 DLL_EXPORT void
419 SafeMoveWindow(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
420 {
421 RECT rect;
422
423 WaitForSingleObject(g_mutex, INFINITE);
424 g_block_move_hwnd = hwnd;
425 g_block_move_serial = serial;
426 g_block_move.left = x;
427 g_block_move.top = y;
428 g_block_move.right = x + width;
429 g_block_move.bottom = y + height;
430 ReleaseMutex(g_mutex);
431
432 SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER);
433
434 vchannel_write("ACK", "%u", serial);
435
436 if (!GetWindowRect(hwnd, &rect))
437 debug("GetWindowRect failed!\n");
438 else if ((rect.left != x) || (rect.top != y) || (rect.right != x + width)
439 || (rect.bottom != y + height))
440 update_position(hwnd);
441
442 WaitForSingleObject(g_mutex, INFINITE);
443 g_block_move_hwnd = NULL;
444 memset(&g_block_move, 0, sizeof(RECT));
445 ReleaseMutex(g_mutex);
446 }
447
448 DLL_EXPORT void
449 SafeZChange(unsigned int serial, HWND hwnd, HWND behind)
450 {
451 WaitForSingleObject(g_mutex, INFINITE);
452 g_blocked_zchange_serial = serial;
453 g_blocked_zchange[0] = hwnd;
454 g_blocked_zchange[1] = behind;
455 ReleaseMutex(g_mutex);
456
457 if (behind == NULL)
458 behind = HWND_TOP;
459
460 SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
461
462 WaitForSingleObject(g_mutex, INFINITE);
463 g_blocked_zchange[0] = NULL;
464 g_blocked_zchange[1] = NULL;
465 ReleaseMutex(g_mutex);
466 }
467
468 DLL_EXPORT void
469 SafeFocus(unsigned int serial, HWND hwnd)
470 {
471 WaitForSingleObject(g_mutex, INFINITE);
472 g_blocked_focus_serial = serial;
473 g_blocked_focus = hwnd;
474 ReleaseMutex(g_mutex);
475
476 SendMessage(hwnd, g_wm_seamless_focus, 0, 0);
477
478 WaitForSingleObject(g_mutex, INFINITE);
479 g_blocked_focus = NULL;
480 ReleaseMutex(g_mutex);
481 }
482
483 DLL_EXPORT void
484 SafeSetState(unsigned int serial, HWND hwnd, int state)
485 {
486 LONG style;
487 int curstate;
488
489 vchannel_block();
490
491 style = GetWindowLong(hwnd, GWL_STYLE);
492
493 if (style & WS_MAXIMIZE)
494 curstate = 2;
495 else if (style & WS_MINIMIZE)
496 curstate = 1;
497 else
498 curstate = 0;
499
500 if (state == curstate)
501 {
502 vchannel_write("ACK", "%u", serial);
503 vchannel_unblock();
504 return;
505 }
506
507 WaitForSingleObject(g_mutex, INFINITE);
508 g_blocked_state_hwnd = hwnd;
509 g_blocked_state_serial = serial;
510 g_blocked_state = state;
511 ReleaseMutex(g_mutex);
512
513 vchannel_unblock();
514
515 if (state == 0)
516 ShowWindow(hwnd, SW_RESTORE);
517 else if (state == 1)
518 ShowWindow(hwnd, SW_MINIMIZE);
519 else if (state == 2)
520 ShowWindow(hwnd, SW_MAXIMIZE);
521 else
522 debug("Invalid state %d sent.", state);
523
524 WaitForSingleObject(g_mutex, INFINITE);
525 g_blocked_state_hwnd = NULL;
526 g_blocked_state = -1;
527 ReleaseMutex(g_mutex);
528 }
529
530 DLL_EXPORT int
531 GetInstanceCount()
532 {
533 return g_instance_count;
534 }
535
536 BOOL APIENTRY
537 DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
538 {
539 switch (ul_reason_for_call)
540 {
541 case DLL_PROCESS_ATTACH:
542 // remember our instance handle
543 g_instance = hinstDLL;
544
545 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
546 if (!g_mutex)
547 return FALSE;
548
549 WaitForSingleObject(g_mutex, INFINITE);
550 ++g_instance_count;
551 ReleaseMutex(g_mutex);
552
553 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
554
555 vchannel_open();
556
557 break;
558
559 case DLL_THREAD_ATTACH:
560 break;
561
562 case DLL_THREAD_DETACH:
563 break;
564
565 case DLL_PROCESS_DETACH:
566 WaitForSingleObject(g_mutex, INFINITE);
567 --g_instance_count;
568 ReleaseMutex(g_mutex);
569
570 vchannel_close();
571
572 CloseHandle(g_mutex);
573
574 break;
575 }
576
577 return TRUE;
578 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26