/[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 1160 - (show annotations)
Fri Mar 17 16:23:08 2006 UTC (18 years, 2 months ago) by ossman_
File MIME type: text/plain
File size: 10384 byte(s)
Break loops caused by STATE.

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 int g_blocked_state SHARED = -1;
52
53 #pragma data_seg ()
54
55 #pragma comment(linker, "/section:SHAREDDATA,rws")
56
57 #define FOCUS_MSG_NAME "WM_SEAMLESS_FOCUS"
58 static UINT g_wm_seamless_focus;
59
60 static HHOOK g_cbt_hook = NULL;
61 static HHOOK g_wndproc_hook = NULL;
62 static HHOOK g_wndprocret_hook = NULL;
63
64 static HINSTANCE g_instance = NULL;
65
66 static HANDLE g_mutex = NULL;
67
68 static void
69 update_position(HWND hwnd)
70 {
71 RECT rect, blocked;
72
73 if (!GetWindowRect(hwnd, &rect))
74 {
75 debug("GetWindowRect failed!\n");
76 return;
77 }
78
79 WaitForSingleObject(g_mutex, INFINITE);
80 memcpy(&blocked, &g_block_move, sizeof(RECT));
81 ReleaseMutex(g_mutex);
82
83 if ((rect.left == blocked.left) && (rect.top == blocked.top)
84 && (rect.right == blocked.right) && (rect.bottom == blocked.bottom))
85 return;
86
87 vchannel_write("POSITION,0x%p,%d,%d,%d,%d,0x%x",
88 hwnd,
89 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
90 }
91
92 static LRESULT CALLBACK
93 wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
94 {
95 HWND hwnd, parent;
96 UINT msg;
97 WPARAM wparam;
98 LPARAM lparam;
99
100 LONG style;
101
102 if (code < 0)
103 goto end;
104
105 hwnd = ((CWPSTRUCT *) details)->hwnd;
106 msg = ((CWPSTRUCT *) details)->message;
107 wparam = ((CWPSTRUCT *) details)->wParam;
108 lparam = ((CWPSTRUCT *) details)->lParam;
109
110 style = GetWindowLong(hwnd, GWL_STYLE);
111
112 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
113 but they exist nonetheless. */
114 if ((style & WS_CHILD) && !(style & WS_POPUP))
115 goto end;
116
117 if (style & WS_POPUP)
118 {
119 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
120 if (!parent)
121 parent = (HWND) - 1;
122 }
123 else
124 parent = NULL;
125
126 switch (msg)
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, blocked;
288
289 WaitForSingleObject(g_mutex, INFINITE);
290 blocked = g_blocked_state;
291 ReleaseMutex(g_mutex);
292
293 show = LOWORD(lparam);
294
295 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
296 || (show == SW_RESTORE))
297 state = 0;
298 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
299 state = 1;
300 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
301 state = 2;
302 else
303 {
304 debug("Unexpected show: %d", show);
305 break;
306 }
307
308 if (blocked != state)
309 vchannel_write("STATE,0x%p,0x%x,0x%x", (HWND) wparam, state,
310 0);
311
312 break;
313 }
314
315 default:
316 break;
317 }
318
319 end:
320 return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
321 }
322
323 DLL_EXPORT void
324 SetHooks(void)
325 {
326 if (!g_cbt_hook)
327 g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
328
329 if (!g_wndproc_hook)
330 g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
331
332 if (!g_wndprocret_hook)
333 g_wndprocret_hook =
334 SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
335 }
336
337 DLL_EXPORT void
338 RemoveHooks(void)
339 {
340 if (g_cbt_hook)
341 UnhookWindowsHookEx(g_cbt_hook);
342
343 if (g_wndproc_hook)
344 UnhookWindowsHookEx(g_wndproc_hook);
345
346 if (g_wndprocret_hook)
347 UnhookWindowsHookEx(g_wndprocret_hook);
348 }
349
350 DLL_EXPORT void
351 SafeMoveWindow(HWND hwnd, int x, int y, int width, int height)
352 {
353 WaitForSingleObject(g_mutex, INFINITE);
354 g_block_move.left = x;
355 g_block_move.top = y;
356 g_block_move.right = x + width;
357 g_block_move.bottom = y + height;
358 ReleaseMutex(g_mutex);
359
360 SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER);
361
362 WaitForSingleObject(g_mutex, INFINITE);
363 memset(&g_block_move, 0, sizeof(RECT));
364 ReleaseMutex(g_mutex);
365 }
366
367 DLL_EXPORT void
368 SafeZChange(HWND hwnd, HWND behind)
369 {
370 if (behind == NULL)
371 behind = HWND_TOP;
372
373 WaitForSingleObject(g_mutex, INFINITE);
374 g_blocked_zchange[0] = hwnd;
375 g_blocked_zchange[1] = behind;
376 ReleaseMutex(g_mutex);
377
378 SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
379
380 WaitForSingleObject(g_mutex, INFINITE);
381 g_blocked_zchange[0] = NULL;
382 g_blocked_zchange[1] = NULL;
383 ReleaseMutex(g_mutex);
384 }
385
386 DLL_EXPORT void
387 SafeFocus(HWND hwnd)
388 {
389 WaitForSingleObject(g_mutex, INFINITE);
390 g_blocked_focus = hwnd;
391 ReleaseMutex(g_mutex);
392
393 SendMessage(hwnd, g_wm_seamless_focus, 0, 0);
394
395 WaitForSingleObject(g_mutex, INFINITE);
396 g_blocked_focus = NULL;
397 ReleaseMutex(g_mutex);
398 }
399
400 DLL_EXPORT void
401 SafeSetState(HWND hwnd, int state)
402 {
403 WaitForSingleObject(g_mutex, INFINITE);
404 g_blocked_state = state;
405 ReleaseMutex(g_mutex);
406
407 if (state == 0)
408 ShowWindow(hwnd, SW_RESTORE);
409 else if (state == 1)
410 ShowWindow(hwnd, SW_MINIMIZE);
411 else if (state == 2)
412 ShowWindow(hwnd, SW_MAXIMIZE);
413 else
414 debug("Invalid state %d sent.", state);
415
416 WaitForSingleObject(g_mutex, INFINITE);
417 g_blocked_state = -1;
418 ReleaseMutex(g_mutex);
419 }
420
421 DLL_EXPORT int
422 GetInstanceCount()
423 {
424 return g_instance_count;
425 }
426
427 BOOL APIENTRY
428 DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
429 {
430 switch (ul_reason_for_call)
431 {
432 case DLL_PROCESS_ATTACH:
433 // remember our instance handle
434 g_instance = hinstDLL;
435
436 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
437 if (!g_mutex)
438 return FALSE;
439
440 WaitForSingleObject(g_mutex, INFINITE);
441 ++g_instance_count;
442 ReleaseMutex(g_mutex);
443
444 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
445
446 vchannel_open();
447
448 break;
449
450 case DLL_THREAD_ATTACH:
451 break;
452
453 case DLL_THREAD_DETACH:
454 break;
455
456 case DLL_PROCESS_DETACH:
457 WaitForSingleObject(g_mutex, INFINITE);
458 --g_instance_count;
459 ReleaseMutex(g_mutex);
460
461 vchannel_close();
462
463 CloseHandle(g_mutex);
464
465 break;
466 }
467
468 return TRUE;
469 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26