/[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 1167 - (show annotations)
Mon Mar 20 14:35:02 2006 UTC (18 years, 3 months ago) by ossman_
File MIME type: text/plain
File size: 12549 byte(s)
Restructure ACK:s of POSITION a bit since Windows can ignore some requests.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26