/[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 1161 - (show annotations)
Fri Mar 17 16:34:46 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 10746 byte(s)
Also store hwnd when doing blocking to make things a bit more fool proof.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26