/[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 1165 - (show annotations)
Mon Mar 20 12:28:03 2006 UTC (18 years, 3 months ago) by ossman_
File MIME type: text/plain
File size: 12568 byte(s)
Send an ACK for all client commands.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26