/[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 1186 - (show annotations)
Wed Mar 22 11:56:46 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 13294 byte(s)
Avoid %p since it's implementation defined.

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 blocked_hwnd;
376 unsigned int serial;
377
378 WaitForSingleObject(g_mutex, INFINITE);
379 blocked_hwnd = g_blocked_state_hwnd;
380 serial = g_blocked_state_serial;
381 blocked = g_blocked_state;
382 ReleaseMutex(g_mutex);
383
384 show = LOWORD(lparam);
385
386 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
387 || (show == SW_RESTORE))
388 state = 0;
389 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
390 state = 1;
391 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
392 state = 2;
393 else
394 {
395 debug("Unexpected show: %d", show);
396 break;
397 }
398
399 if ((blocked_hwnd == (HWND) wparam) && (blocked == state))
400 vchannel_write("ACK", "%u", serial);
401 else
402 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x",
403 (HWND) wparam, state, 0);
404
405 break;
406 }
407
408 default:
409 break;
410 }
411
412 end:
413 return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
414 }
415
416 DLL_EXPORT void
417 SetHooks(void)
418 {
419 if (!g_cbt_hook)
420 g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
421
422 if (!g_wndproc_hook)
423 g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
424
425 if (!g_wndprocret_hook)
426 g_wndprocret_hook =
427 SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
428 }
429
430 DLL_EXPORT void
431 RemoveHooks(void)
432 {
433 if (g_cbt_hook)
434 UnhookWindowsHookEx(g_cbt_hook);
435
436 if (g_wndproc_hook)
437 UnhookWindowsHookEx(g_wndproc_hook);
438
439 if (g_wndprocret_hook)
440 UnhookWindowsHookEx(g_wndprocret_hook);
441 }
442
443 DLL_EXPORT void
444 SafeMoveWindow(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
445 {
446 RECT rect;
447
448 WaitForSingleObject(g_mutex, INFINITE);
449 g_block_move_hwnd = hwnd;
450 g_block_move_serial = serial;
451 g_block_move.left = x;
452 g_block_move.top = y;
453 g_block_move.right = x + width;
454 g_block_move.bottom = y + height;
455 ReleaseMutex(g_mutex);
456
457 SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER);
458
459 vchannel_write("ACK", "%u", serial);
460
461 if (!GetWindowRect(hwnd, &rect))
462 debug("GetWindowRect failed!\n");
463 else if ((rect.left != x) || (rect.top != y) || (rect.right != x + width)
464 || (rect.bottom != y + height))
465 update_position(hwnd);
466
467 WaitForSingleObject(g_mutex, INFINITE);
468 g_block_move_hwnd = NULL;
469 memset(&g_block_move, 0, sizeof(RECT));
470 ReleaseMutex(g_mutex);
471 }
472
473 DLL_EXPORT void
474 SafeZChange(unsigned int serial, HWND hwnd, HWND behind)
475 {
476 WaitForSingleObject(g_mutex, INFINITE);
477 g_blocked_zchange_serial = serial;
478 g_blocked_zchange[0] = hwnd;
479 g_blocked_zchange[1] = behind;
480 ReleaseMutex(g_mutex);
481
482 if (behind == NULL)
483 behind = HWND_TOP;
484
485 SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
486
487 WaitForSingleObject(g_mutex, INFINITE);
488 g_blocked_zchange[0] = NULL;
489 g_blocked_zchange[1] = NULL;
490 ReleaseMutex(g_mutex);
491 }
492
493 DLL_EXPORT void
494 SafeFocus(unsigned int serial, HWND hwnd)
495 {
496 WaitForSingleObject(g_mutex, INFINITE);
497 g_blocked_focus_serial = serial;
498 g_blocked_focus = hwnd;
499 ReleaseMutex(g_mutex);
500
501 SendMessage(hwnd, g_wm_seamless_focus, 0, 0);
502
503 WaitForSingleObject(g_mutex, INFINITE);
504 g_blocked_focus = NULL;
505 ReleaseMutex(g_mutex);
506 }
507
508 DLL_EXPORT void
509 SafeSetState(unsigned int serial, HWND hwnd, int state)
510 {
511 LONG style;
512 int curstate;
513
514 vchannel_block();
515
516 style = GetWindowLong(hwnd, GWL_STYLE);
517
518 if (style & WS_MAXIMIZE)
519 curstate = 2;
520 else if (style & WS_MINIMIZE)
521 curstate = 1;
522 else
523 curstate = 0;
524
525 if (state == curstate)
526 {
527 vchannel_write("ACK", "%u", serial);
528 vchannel_unblock();
529 return;
530 }
531
532 WaitForSingleObject(g_mutex, INFINITE);
533 g_blocked_state_hwnd = hwnd;
534 g_blocked_state_serial = serial;
535 g_blocked_state = state;
536 ReleaseMutex(g_mutex);
537
538 vchannel_unblock();
539
540 if (state == 0)
541 ShowWindow(hwnd, SW_RESTORE);
542 else if (state == 1)
543 ShowWindow(hwnd, SW_MINIMIZE);
544 else if (state == 2)
545 ShowWindow(hwnd, SW_MAXIMIZE);
546 else
547 debug("Invalid state %d sent.", state);
548
549 WaitForSingleObject(g_mutex, INFINITE);
550 g_blocked_state_hwnd = NULL;
551 g_blocked_state = -1;
552 ReleaseMutex(g_mutex);
553 }
554
555 DLL_EXPORT int
556 GetInstanceCount()
557 {
558 return g_instance_count;
559 }
560
561 BOOL APIENTRY
562 DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
563 {
564 switch (ul_reason_for_call)
565 {
566 case DLL_PROCESS_ATTACH:
567 // remember our instance handle
568 g_instance = hinstDLL;
569
570 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
571 if (!g_mutex)
572 return FALSE;
573
574 WaitForSingleObject(g_mutex, INFINITE);
575 ++g_instance_count;
576 ReleaseMutex(g_mutex);
577
578 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
579
580 vchannel_open();
581
582 break;
583
584 case DLL_THREAD_ATTACH:
585 break;
586
587 case DLL_THREAD_DETACH:
588 break;
589
590 case DLL_PROCESS_DETACH:
591 WaitForSingleObject(g_mutex, INFINITE);
592 --g_instance_count;
593 ReleaseMutex(g_mutex);
594
595 vchannel_close();
596
597 CloseHandle(g_mutex);
598
599 break;
600 }
601
602 return TRUE;
603 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26