/[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 1230 - (show annotations)
Thu Apr 20 12:56:18 2006 UTC (18 years, 1 month ago) by ossman_
File MIME type: text/plain
File size: 13414 byte(s)
Don't send STATE for hidden 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%08lx,%d,%d,%d,%d,0x%08x",
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%08lx,0x%08lx,0x%08x", hwnd, behind, 0);
142
143 vchannel_unblock();
144 }
145
146 static HWND
147 get_parent(HWND hwnd)
148 {
149 LONG style;
150 HWND parent;
151
152 style = GetWindowLong(hwnd, GWL_STYLE);
153
154 if (style & (WS_POPUP | DS_MODALFRAME))
155 {
156 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
157
158 if (parent)
159 {
160 style = GetWindowLong(parent, GWL_STYLE);
161 if (((style & WS_CHILD) && !(style & WS_POPUP)) || !(style & WS_VISIBLE))
162 parent = NULL;
163 }
164
165 if (!parent)
166 parent = GetWindow(hwnd, GW_OWNER);
167
168 if (parent)
169 {
170 style = GetWindowLong(parent, GWL_STYLE);
171 if (((style & WS_CHILD) && !(style & WS_POPUP)) || !(style & WS_VISIBLE))
172 parent = NULL;
173 }
174
175 if (!parent)
176 parent = (HWND) - 1;
177 }
178 else
179 parent = NULL;
180
181 return parent;
182 }
183
184 static LRESULT CALLBACK
185 wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
186 {
187 HWND hwnd, parent;
188 UINT msg;
189 WPARAM wparam;
190 LPARAM lparam;
191
192 LONG style;
193
194 if (code < 0)
195 goto end;
196
197 hwnd = ((CWPSTRUCT *) details)->hwnd;
198 msg = ((CWPSTRUCT *) details)->message;
199 wparam = ((CWPSTRUCT *) details)->wParam;
200 lparam = ((CWPSTRUCT *) details)->lParam;
201
202 style = GetWindowLong(hwnd, GWL_STYLE);
203
204 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
205 but they exist nonetheless. */
206 if ((style & WS_CHILD) && !(style & WS_POPUP))
207 goto end;
208
209 parent = get_parent(hwnd);
210
211 switch (msg)
212 {
213 case WM_WINDOWPOSCHANGED:
214 {
215 WINDOWPOS *wp = (WINDOWPOS *) lparam;
216
217 if (wp->flags & SWP_SHOWWINDOW)
218 {
219 unsigned short title[150];
220 int state;
221 DWORD pid;
222 int flags;
223
224 GetWindowThreadProcessId(hwnd, &pid);
225
226 flags = 0;
227 if (style & DS_MODALFRAME)
228 flags |= SEAMLESS_CREATE_MODAL;
229
230 vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x",
231 (long) hwnd, (long) pid, (long) parent,
232 flags);
233
234 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
235
236 vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
237 vchannel_strfilter_unicode(title), 0);
238
239 if (style & WS_MAXIMIZE)
240 state = 2;
241 else if (style & WS_MINIMIZE)
242 state = 1;
243 else
244 state = 0;
245
246 update_position(hwnd);
247
248 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd,
249 state, 0);
250 }
251
252 if (wp->flags & SWP_HIDEWINDOW)
253 vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
254
255 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
256 break;
257
258 if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
259 update_position(hwnd);
260
261 break;
262 }
263
264 case WM_SIZE:
265 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
266 break;
267 update_position(hwnd);
268 break;
269
270 case WM_MOVE:
271 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
272 break;
273 update_position(hwnd);
274 break;
275
276 case WM_DESTROY:
277 if (!(style & WS_VISIBLE))
278 break;
279 vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
280 break;
281
282 default:
283 break;
284 }
285
286 end:
287 return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
288 }
289
290 static LRESULT CALLBACK
291 wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)
292 {
293 HWND hwnd, parent;
294 UINT msg;
295 WPARAM wparam;
296 LPARAM lparam;
297
298 LONG style;
299
300 if (code < 0)
301 goto end;
302
303 hwnd = ((CWPRETSTRUCT *) details)->hwnd;
304 msg = ((CWPRETSTRUCT *) details)->message;
305 wparam = ((CWPRETSTRUCT *) details)->wParam;
306 lparam = ((CWPRETSTRUCT *) details)->lParam;
307
308 style = GetWindowLong(hwnd, GWL_STYLE);
309
310 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
311 but they exist nonetheless. */
312 if ((style & WS_CHILD) && !(style & WS_POPUP))
313 goto end;
314
315 parent = get_parent(hwnd);
316
317 switch (msg)
318 {
319 case WM_WINDOWPOSCHANGED:
320 {
321 WINDOWPOS *wp = (WINDOWPOS *) lparam;
322
323 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
324 break;
325
326 if (!(wp->flags & SWP_NOZORDER))
327 update_zorder(hwnd);
328
329 break;
330 }
331
332
333 case WM_SETTEXT:
334 {
335 unsigned short title[150];
336 if (!(style & WS_VISIBLE))
337 break;
338 /* We cannot use the string in lparam because
339 we need unicode. */
340 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
341 vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
342 vchannel_strfilter_unicode(title), 0);
343 break;
344 }
345
346 default:
347 break;
348 }
349
350 if (msg == g_wm_seamless_focus)
351 {
352 /* FIXME: SetForegroundWindow() kills menus. Need to find a
353 clean way to solve this. */
354 if ((GetForegroundWindow() != hwnd) && !parent)
355 SetForegroundWindow(hwnd);
356
357 vchannel_write("ACK", "%u", g_blocked_focus_serial);
358 }
359
360 end:
361 return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details);
362 }
363
364 static LRESULT CALLBACK
365 cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
366 {
367 if (code < 0)
368 goto end;
369
370 switch (code)
371 {
372 case HCBT_MINMAX:
373 {
374 int show, state, blocked;
375 HWND hwnd, blocked_hwnd;
376 unsigned int serial;
377 LONG style;
378
379 WaitForSingleObject(g_mutex, INFINITE);
380 blocked_hwnd = g_blocked_state_hwnd;
381 serial = g_blocked_state_serial;
382 blocked = g_blocked_state;
383 ReleaseMutex(g_mutex);
384
385 hwnd = (HWND) wparam;
386
387 style = GetWindowLong(hwnd, GWL_STYLE);
388
389 if (!(style & WS_VISIBLE))
390 break;
391
392 show = LOWORD(lparam);
393
394 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
395 || (show == SW_RESTORE))
396 state = 0;
397 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
398 state = 1;
399 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
400 state = 2;
401 else
402 {
403 debug("Unexpected show: %d", show);
404 break;
405 }
406
407 if ((blocked_hwnd == hwnd) && (blocked == state))
408 vchannel_write("ACK", "%u", serial);
409 else
410 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x",
411 hwnd, state, 0);
412
413 break;
414 }
415
416 default:
417 break;
418 }
419
420 end:
421 return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
422 }
423
424 DLL_EXPORT void
425 SetHooks(void)
426 {
427 if (!g_cbt_hook)
428 g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
429
430 if (!g_wndproc_hook)
431 g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
432
433 if (!g_wndprocret_hook)
434 g_wndprocret_hook =
435 SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
436 }
437
438 DLL_EXPORT void
439 RemoveHooks(void)
440 {
441 if (g_cbt_hook)
442 UnhookWindowsHookEx(g_cbt_hook);
443
444 if (g_wndproc_hook)
445 UnhookWindowsHookEx(g_wndproc_hook);
446
447 if (g_wndprocret_hook)
448 UnhookWindowsHookEx(g_wndprocret_hook);
449 }
450
451 DLL_EXPORT void
452 SafeMoveWindow(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
453 {
454 RECT rect;
455
456 WaitForSingleObject(g_mutex, INFINITE);
457 g_block_move_hwnd = hwnd;
458 g_block_move_serial = serial;
459 g_block_move.left = x;
460 g_block_move.top = y;
461 g_block_move.right = x + width;
462 g_block_move.bottom = y + height;
463 ReleaseMutex(g_mutex);
464
465 SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER);
466
467 vchannel_write("ACK", "%u", serial);
468
469 if (!GetWindowRect(hwnd, &rect))
470 debug("GetWindowRect failed!\n");
471 else if ((rect.left != x) || (rect.top != y) || (rect.right != x + width)
472 || (rect.bottom != y + height))
473 update_position(hwnd);
474
475 WaitForSingleObject(g_mutex, INFINITE);
476 g_block_move_hwnd = NULL;
477 memset(&g_block_move, 0, sizeof(RECT));
478 ReleaseMutex(g_mutex);
479 }
480
481 DLL_EXPORT void
482 SafeZChange(unsigned int serial, HWND hwnd, HWND behind)
483 {
484 WaitForSingleObject(g_mutex, INFINITE);
485 g_blocked_zchange_serial = serial;
486 g_blocked_zchange[0] = hwnd;
487 g_blocked_zchange[1] = behind;
488 ReleaseMutex(g_mutex);
489
490 if (behind == NULL)
491 behind = HWND_TOP;
492
493 SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
494
495 WaitForSingleObject(g_mutex, INFINITE);
496 g_blocked_zchange[0] = NULL;
497 g_blocked_zchange[1] = NULL;
498 ReleaseMutex(g_mutex);
499 }
500
501 DLL_EXPORT void
502 SafeFocus(unsigned int serial, HWND hwnd)
503 {
504 WaitForSingleObject(g_mutex, INFINITE);
505 g_blocked_focus_serial = serial;
506 g_blocked_focus = hwnd;
507 ReleaseMutex(g_mutex);
508
509 SendMessage(hwnd, g_wm_seamless_focus, 0, 0);
510
511 WaitForSingleObject(g_mutex, INFINITE);
512 g_blocked_focus = NULL;
513 ReleaseMutex(g_mutex);
514 }
515
516 DLL_EXPORT void
517 SafeSetState(unsigned int serial, HWND hwnd, int state)
518 {
519 LONG style;
520 int curstate;
521
522 vchannel_block();
523
524 style = GetWindowLong(hwnd, GWL_STYLE);
525
526 if (style & WS_MAXIMIZE)
527 curstate = 2;
528 else if (style & WS_MINIMIZE)
529 curstate = 1;
530 else
531 curstate = 0;
532
533 if (state == curstate)
534 {
535 vchannel_write("ACK", "%u", serial);
536 vchannel_unblock();
537 return;
538 }
539
540 WaitForSingleObject(g_mutex, INFINITE);
541 g_blocked_state_hwnd = hwnd;
542 g_blocked_state_serial = serial;
543 g_blocked_state = state;
544 ReleaseMutex(g_mutex);
545
546 vchannel_unblock();
547
548 if (state == 0)
549 ShowWindow(hwnd, SW_RESTORE);
550 else if (state == 1)
551 ShowWindow(hwnd, SW_MINIMIZE);
552 else if (state == 2)
553 ShowWindow(hwnd, SW_MAXIMIZE);
554 else
555 debug("Invalid state %d sent.", state);
556
557 WaitForSingleObject(g_mutex, INFINITE);
558 g_blocked_state_hwnd = NULL;
559 g_blocked_state = -1;
560 ReleaseMutex(g_mutex);
561 }
562
563 DLL_EXPORT int
564 GetInstanceCount()
565 {
566 return g_instance_count;
567 }
568
569 BOOL APIENTRY
570 DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
571 {
572 switch (ul_reason_for_call)
573 {
574 case DLL_PROCESS_ATTACH:
575 // remember our instance handle
576 g_instance = hinstDLL;
577
578 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
579 if (!g_mutex)
580 return FALSE;
581
582 WaitForSingleObject(g_mutex, INFINITE);
583 ++g_instance_count;
584 ReleaseMutex(g_mutex);
585
586 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
587
588 vchannel_open();
589
590 break;
591
592 case DLL_THREAD_ATTACH:
593 break;
594
595 case DLL_THREAD_DETACH:
596 break;
597
598 case DLL_PROCESS_DETACH:
599 WaitForSingleObject(g_mutex, INFINITE);
600 --g_instance_count;
601 ReleaseMutex(g_mutex);
602
603 vchannel_close();
604
605 CloseHandle(g_mutex);
606
607 break;
608 }
609
610 return TRUE;
611 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26