/[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 1185 - (show annotations)
Wed Mar 22 11:52:07 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 13234 byte(s)
SetActiveWindow() only does what we want when the window is owned by the
same process as the currently active. SetForegroundWindow() does what we want
under all circumstances.

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 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%x,%s,0x%x", 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%p,0x%x,0x%x", hwnd, state, 0);
249 }
250
251 if (wp->flags & SWP_HIDEWINDOW)
252 vchannel_write("DESTROY", "0x%p,0x%x", hwnd, 0);
253
254 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
255 break;
256
257 if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
258 update_position(hwnd);
259
260 break;
261 }
262
263 case WM_SIZE:
264 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
265 break;
266 update_position(hwnd);
267 break;
268
269 case WM_MOVE:
270 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
271 break;
272 update_position(hwnd);
273 break;
274
275 case WM_DESTROY:
276 if (!(style & WS_VISIBLE))
277 break;
278 vchannel_write("DESTROY", "0x%p,0x%x", hwnd, 0);
279 break;
280
281 default:
282 break;
283 }
284
285 end:
286 return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
287 }
288
289 static LRESULT CALLBACK
290 wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)
291 {
292 HWND hwnd, parent;
293 UINT msg;
294 WPARAM wparam;
295 LPARAM lparam;
296
297 LONG style;
298
299 if (code < 0)
300 goto end;
301
302 hwnd = ((CWPRETSTRUCT *) details)->hwnd;
303 msg = ((CWPRETSTRUCT *) details)->message;
304 wparam = ((CWPRETSTRUCT *) details)->wParam;
305 lparam = ((CWPRETSTRUCT *) details)->lParam;
306
307 style = GetWindowLong(hwnd, GWL_STYLE);
308
309 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
310 but they exist nonetheless. */
311 if ((style & WS_CHILD) && !(style & WS_POPUP))
312 goto end;
313
314 parent = get_parent(hwnd);
315
316 switch (msg)
317 {
318 case WM_WINDOWPOSCHANGED:
319 {
320 WINDOWPOS *wp = (WINDOWPOS *) lparam;
321
322 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
323 break;
324
325 if (!(wp->flags & SWP_NOZORDER))
326 update_zorder(hwnd);
327
328 break;
329 }
330
331
332 case WM_SETTEXT:
333 {
334 unsigned short title[150];
335 if (!(style & WS_VISIBLE))
336 break;
337 /* We cannot use the string in lparam because
338 we need unicode. */
339 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
340 vchannel_write("TITLE", "0x%p,%s,0x%x", hwnd,
341 vchannel_strfilter_unicode(title), 0);
342 break;
343 }
344
345 default:
346 break;
347 }
348
349 if (msg == g_wm_seamless_focus)
350 {
351 /* FIXME: SetForegroundWindow() kills menus. Need to find a
352 clean way to solve this. */
353 if ((GetForegroundWindow() != hwnd) && !parent)
354 SetForegroundWindow(hwnd);
355
356 vchannel_write("ACK", "%u", g_blocked_focus_serial);
357 }
358
359 end:
360 return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details);
361 }
362
363 static LRESULT CALLBACK
364 cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
365 {
366 if (code < 0)
367 goto end;
368
369 switch (code)
370 {
371 case HCBT_MINMAX:
372 {
373 int show, state, blocked;
374 HWND blocked_hwnd;
375 unsigned int serial;
376
377 WaitForSingleObject(g_mutex, INFINITE);
378 blocked_hwnd = g_blocked_state_hwnd;
379 serial = g_blocked_state_serial;
380 blocked = g_blocked_state;
381 ReleaseMutex(g_mutex);
382
383 show = LOWORD(lparam);
384
385 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
386 || (show == SW_RESTORE))
387 state = 0;
388 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
389 state = 1;
390 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
391 state = 2;
392 else
393 {
394 debug("Unexpected show: %d", show);
395 break;
396 }
397
398 if ((blocked_hwnd == (HWND) wparam) && (blocked == state))
399 vchannel_write("ACK", "%u", serial);
400 else
401 vchannel_write("STATE", "0x%p,0x%x,0x%x", (HWND) wparam,
402 state, 0);
403
404 break;
405 }
406
407 default:
408 break;
409 }
410
411 end:
412 return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
413 }
414
415 DLL_EXPORT void
416 SetHooks(void)
417 {
418 if (!g_cbt_hook)
419 g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
420
421 if (!g_wndproc_hook)
422 g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
423
424 if (!g_wndprocret_hook)
425 g_wndprocret_hook =
426 SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
427 }
428
429 DLL_EXPORT void
430 RemoveHooks(void)
431 {
432 if (g_cbt_hook)
433 UnhookWindowsHookEx(g_cbt_hook);
434
435 if (g_wndproc_hook)
436 UnhookWindowsHookEx(g_wndproc_hook);
437
438 if (g_wndprocret_hook)
439 UnhookWindowsHookEx(g_wndprocret_hook);
440 }
441
442 DLL_EXPORT void
443 SafeMoveWindow(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
444 {
445 RECT rect;
446
447 WaitForSingleObject(g_mutex, INFINITE);
448 g_block_move_hwnd = hwnd;
449 g_block_move_serial = serial;
450 g_block_move.left = x;
451 g_block_move.top = y;
452 g_block_move.right = x + width;
453 g_block_move.bottom = y + height;
454 ReleaseMutex(g_mutex);
455
456 SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER);
457
458 vchannel_write("ACK", "%u", serial);
459
460 if (!GetWindowRect(hwnd, &rect))
461 debug("GetWindowRect failed!\n");
462 else if ((rect.left != x) || (rect.top != y) || (rect.right != x + width)
463 || (rect.bottom != y + height))
464 update_position(hwnd);
465
466 WaitForSingleObject(g_mutex, INFINITE);
467 g_block_move_hwnd = NULL;
468 memset(&g_block_move, 0, sizeof(RECT));
469 ReleaseMutex(g_mutex);
470 }
471
472 DLL_EXPORT void
473 SafeZChange(unsigned int serial, HWND hwnd, HWND behind)
474 {
475 WaitForSingleObject(g_mutex, INFINITE);
476 g_blocked_zchange_serial = serial;
477 g_blocked_zchange[0] = hwnd;
478 g_blocked_zchange[1] = behind;
479 ReleaseMutex(g_mutex);
480
481 if (behind == NULL)
482 behind = HWND_TOP;
483
484 SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
485
486 WaitForSingleObject(g_mutex, INFINITE);
487 g_blocked_zchange[0] = NULL;
488 g_blocked_zchange[1] = NULL;
489 ReleaseMutex(g_mutex);
490 }
491
492 DLL_EXPORT void
493 SafeFocus(unsigned int serial, HWND hwnd)
494 {
495 WaitForSingleObject(g_mutex, INFINITE);
496 g_blocked_focus_serial = serial;
497 g_blocked_focus = hwnd;
498 ReleaseMutex(g_mutex);
499
500 SendMessage(hwnd, g_wm_seamless_focus, 0, 0);
501
502 WaitForSingleObject(g_mutex, INFINITE);
503 g_blocked_focus = NULL;
504 ReleaseMutex(g_mutex);
505 }
506
507 DLL_EXPORT void
508 SafeSetState(unsigned int serial, HWND hwnd, int state)
509 {
510 LONG style;
511 int curstate;
512
513 vchannel_block();
514
515 style = GetWindowLong(hwnd, GWL_STYLE);
516
517 if (style & WS_MAXIMIZE)
518 curstate = 2;
519 else if (style & WS_MINIMIZE)
520 curstate = 1;
521 else
522 curstate = 0;
523
524 if (state == curstate)
525 {
526 vchannel_write("ACK", "%u", serial);
527 vchannel_unblock();
528 return;
529 }
530
531 WaitForSingleObject(g_mutex, INFINITE);
532 g_blocked_state_hwnd = hwnd;
533 g_blocked_state_serial = serial;
534 g_blocked_state = state;
535 ReleaseMutex(g_mutex);
536
537 vchannel_unblock();
538
539 if (state == 0)
540 ShowWindow(hwnd, SW_RESTORE);
541 else if (state == 1)
542 ShowWindow(hwnd, SW_MINIMIZE);
543 else if (state == 2)
544 ShowWindow(hwnd, SW_MAXIMIZE);
545 else
546 debug("Invalid state %d sent.", state);
547
548 WaitForSingleObject(g_mutex, INFINITE);
549 g_blocked_state_hwnd = NULL;
550 g_blocked_state = -1;
551 ReleaseMutex(g_mutex);
552 }
553
554 DLL_EXPORT int
555 GetInstanceCount()
556 {
557 return g_instance_count;
558 }
559
560 BOOL APIENTRY
561 DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
562 {
563 switch (ul_reason_for_call)
564 {
565 case DLL_PROCESS_ATTACH:
566 // remember our instance handle
567 g_instance = hinstDLL;
568
569 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
570 if (!g_mutex)
571 return FALSE;
572
573 WaitForSingleObject(g_mutex, INFINITE);
574 ++g_instance_count;
575 ReleaseMutex(g_mutex);
576
577 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
578
579 vchannel_open();
580
581 break;
582
583 case DLL_THREAD_ATTACH:
584 break;
585
586 case DLL_THREAD_DETACH:
587 break;
588
589 case DLL_PROCESS_DETACH:
590 WaitForSingleObject(g_mutex, INFINITE);
591 --g_instance_count;
592 ReleaseMutex(g_mutex);
593
594 vchannel_close();
595
596 CloseHandle(g_mutex);
597
598 break;
599 }
600
601 return TRUE;
602 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26