/[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 1158 - (show annotations)
Fri Mar 17 13:11:20 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 9754 byte(s)
Encapsulate ZCHANGE and FOCUS requests into safe wrappers to avoid loops.
Setting focus also needed a hack because it killed off menus.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26