/[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

Annotation of /sourceforge.net/trunk/seamlessrdp/ServerExe/HookDll/hookdll.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1158 - (hide 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 ossman_ 1071 /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.
3     Seamless windows - Remote server hook DLL
4 ossman_ 1069
5 ossman_ 1071 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 ossman_ 1069 #include <stdio.h>
26     #include <stdarg.h>
27    
28 ossman_ 1071 #include <windows.h>
29     #include <winuser.h>
30 ossman_ 1069
31 ossman_ 1073 #include "../vchannel.h"
32 ossman_ 1071
33 ossman_ 1069 #define DLL_EXPORT __declspec(dllexport)
34    
35 ossman_ 1145 #ifdef __GNUC__
36     #define SHARED __attribute__((section ("SHAREDDATA"), shared))
37     #else
38     #define SHARED
39     #endif
40    
41 ossman_ 1069 // Shared DATA
42     #pragma data_seg ( "SHAREDDATA" )
43    
44     // this is the total number of processes this dll is currently attached to
45 ossman_ 1145 int g_instance_count SHARED = 0;
46 ossman_ 1069
47 ossman_ 1145 // blocks for locally generated events
48     RECT g_block_move SHARED = { 0, 0, 0, 0 };
49 ossman_ 1158 HWND g_blocked_zchange[2] SHARED = { NULL, NULL };
50     HWND g_blocked_focus SHARED = NULL;
51 ossman_ 1145
52 ossman_ 1069 #pragma data_seg ()
53    
54     #pragma comment(linker, "/section:SHAREDDATA,rws")
55    
56 ossman_ 1153 #define FOCUS_MSG_NAME "WM_SEAMLESS_FOCUS"
57     static UINT g_wm_seamless_focus;
58    
59 ossman_ 1071 static HHOOK g_cbt_hook = NULL;
60     static HHOOK g_wndproc_hook = NULL;
61 ossman_ 1134 static HHOOK g_wndprocret_hook = NULL;
62 ossman_ 1069
63 ossman_ 1071 static HINSTANCE g_instance = NULL;
64 ossman_ 1069
65 ossman_ 1071 static HANDLE g_mutex = NULL;
66 ossman_ 1069
67 ossman_ 1081 static void
68     update_position(HWND hwnd)
69     {
70 ossman_ 1145 RECT rect, blocked;
71 ossman_ 1081
72     if (!GetWindowRect(hwnd, &rect))
73     {
74     debug("GetWindowRect failed!\n");
75     return;
76     }
77    
78 ossman_ 1145 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 astrand 1091 vchannel_write("POSITION,0x%p,%d,%d,%d,%d,0x%x",
87 ossman_ 1081 hwnd,
88     rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
89     }
90    
91 ossman_ 1071 static LRESULT CALLBACK
92     wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
93 ossman_ 1069 {
94 ossman_ 1097 HWND hwnd, parent;
95 ossman_ 1079 UINT msg;
96     WPARAM wparam;
97     LPARAM lparam;
98 ossman_ 1069
99 ossman_ 1079 LONG style;
100 ossman_ 1069
101 ossman_ 1071 if (code < 0)
102     goto end;
103 ossman_ 1069
104 ossman_ 1079 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 ossman_ 1082 /* 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 ossman_ 1079 goto end;
115    
116 ossman_ 1097 if (style & WS_POPUP)
117 ossman_ 1109 {
118 ossman_ 1097 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
119 ossman_ 1109 if (!parent)
120     parent = (HWND) - 1;
121     }
122 ossman_ 1097 else
123     parent = NULL;
124    
125 ossman_ 1071 switch (msg)
126     {
127 ossman_ 1069
128 ossman_ 1071 case WM_WINDOWPOSCHANGED:
129 ossman_ 1079 {
130     WINDOWPOS *wp = (WINDOWPOS *) lparam;
131 ossman_ 1069
132 ossman_ 1079 if (wp->flags & SWP_SHOWWINDOW)
133     {
134 ossman_ 1134 unsigned short title[150];
135 ossman_ 1099 int state;
136    
137 ossman_ 1097 vchannel_write("CREATE,0x%p,0x%p,0x%x", hwnd, parent, 0);
138 ossman_ 1069
139 ossman_ 1134 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
140 ossman_ 1069
141 ossman_ 1113 vchannel_write("TITLE,0x%x,%s,0x%x", hwnd,
142 ossman_ 1134 vchannel_strfilter_unicode(title), 0);
143 ossman_ 1099
144     if (style & WS_MAXIMIZE)
145     state = 2;
146     else if (style & WS_MINIMIZE)
147     state = 1;
148     else
149     state = 0;
150    
151 ossman_ 1081 update_position(hwnd);
152 ossman_ 1099
153 ossman_ 1131 vchannel_write("STATE,0x%p,0x%x,0x%x", hwnd, state, 0);
154 ossman_ 1079 }
155 ossman_ 1069
156 ossman_ 1079 if (wp->flags & SWP_HIDEWINDOW)
157 astrand 1091 vchannel_write("DESTROY,0x%p,0x%x", hwnd, 0);
158 ossman_ 1079
159 ossman_ 1108 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
160 ossman_ 1079 break;
161    
162 ossman_ 1080 if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
163 ossman_ 1081 update_position(hwnd);
164 ossman_ 1079
165     if (!(wp->flags & SWP_NOZORDER))
166 ossman_ 1080 {
167 ossman_ 1158 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 ossman_ 1080 }
182 ossman_ 1069
183 ossman_ 1071 break;
184 ossman_ 1079 }
185 ossman_ 1069
186 ossman_ 1081 case WM_SIZE:
187 ossman_ 1108 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
188 ossman_ 1083 break;
189 ossman_ 1081 update_position(hwnd);
190     break;
191    
192     case WM_MOVE:
193 ossman_ 1108 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
194 ossman_ 1083 break;
195 ossman_ 1081 update_position(hwnd);
196     break;
197    
198 ossman_ 1134 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 ossman_ 1158 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 ossman_ 1134 switch (msg)
247     {
248 ossman_ 1102 case WM_SETTEXT:
249 ossman_ 1113 {
250 ossman_ 1134 unsigned short title[150];
251 ossman_ 1113 if (!(style & WS_VISIBLE))
252     break;
253 ossman_ 1134 /* We cannot use the string in lparam because
254     we need unicode. */
255     GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
256 ossman_ 1113 vchannel_write("TITLE,0x%p,%s,0x%x", hwnd,
257 ossman_ 1134 vchannel_strfilter_unicode(title), 0);
258 ossman_ 1102 break;
259 ossman_ 1113 }
260 ossman_ 1102
261 ossman_ 1071 default:
262     break;
263     }
264    
265 ossman_ 1153 if (msg == g_wm_seamless_focus)
266 ossman_ 1158 {
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 ossman_ 1153
273 ossman_ 1071 end:
274 ossman_ 1134 return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details);
275 ossman_ 1069 }
276    
277 ossman_ 1071 static LRESULT CALLBACK
278     cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
279 ossman_ 1069 {
280 ossman_ 1071 if (code < 0)
281     goto end;
282 ossman_ 1069
283 ossman_ 1071 switch (code)
284     {
285     case HCBT_MINMAX:
286     {
287 ossman_ 1079 int show, state;
288 ossman_ 1069
289 ossman_ 1071 show = LOWORD(lparam);
290 ossman_ 1069
291 ossman_ 1128 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
292     || (show == SW_RESTORE))
293 ossman_ 1079 state = 0;
294 ossman_ 1106 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
295 ossman_ 1079 state = 1;
296 ossman_ 1106 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
297 ossman_ 1079 state = 2;
298 ossman_ 1100 else
299 ossman_ 1106 {
300     debug("Unexpected show: %d", show);
301 ossman_ 1100 break;
302 ossman_ 1106 }
303 ossman_ 1096 vchannel_write("STATE,0x%p,0x%x,0x%x", (HWND) wparam, state, 0);
304 ossman_ 1071 break;
305     }
306 ossman_ 1069
307 ossman_ 1071 default:
308     break;
309     }
310 ossman_ 1069
311 ossman_ 1071 end:
312     return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
313 ossman_ 1069 }
314    
315 ossman_ 1071 DLL_EXPORT void
316     SetHooks(void)
317 ossman_ 1069 {
318 ossman_ 1071 if (!g_cbt_hook)
319     g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
320 ossman_ 1069
321 ossman_ 1071 if (!g_wndproc_hook)
322     g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
323 ossman_ 1134
324     if (!g_wndprocret_hook)
325     g_wndprocret_hook =
326     SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
327 ossman_ 1069 }
328    
329 ossman_ 1071 DLL_EXPORT void
330     RemoveHooks(void)
331 ossman_ 1069 {
332 ossman_ 1071 if (g_cbt_hook)
333     UnhookWindowsHookEx(g_cbt_hook);
334 ossman_ 1069
335 ossman_ 1071 if (g_wndproc_hook)
336     UnhookWindowsHookEx(g_wndproc_hook);
337 ossman_ 1134
338     if (g_wndprocret_hook)
339     UnhookWindowsHookEx(g_wndprocret_hook);
340 ossman_ 1069 }
341    
342 ossman_ 1145 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 ossman_ 1158 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 ossman_ 1071 DLL_EXPORT int
393     GetInstanceCount()
394 ossman_ 1069 {
395 ossman_ 1071 return g_instance_count;
396 ossman_ 1069 }
397    
398 ossman_ 1071 BOOL APIENTRY
399     DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
400 ossman_ 1069 {
401 ossman_ 1071 switch (ul_reason_for_call)
402     {
403     case DLL_PROCESS_ATTACH:
404     // remember our instance handle
405     g_instance = hinstDLL;
406 ossman_ 1069
407 ossman_ 1073 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
408 ossman_ 1071 if (!g_mutex)
409     return FALSE;
410 ossman_ 1069
411 ossman_ 1071 WaitForSingleObject(g_mutex, INFINITE);
412     ++g_instance_count;
413     ReleaseMutex(g_mutex);
414 ossman_ 1069
415 ossman_ 1153 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
416    
417 ossman_ 1071 vchannel_open();
418 ossman_ 1069
419 ossman_ 1071 break;
420 ossman_ 1069
421 ossman_ 1071 case DLL_THREAD_ATTACH:
422     break;
423 ossman_ 1069
424 ossman_ 1071 case DLL_THREAD_DETACH:
425     break;
426 ossman_ 1069
427 ossman_ 1071 case DLL_PROCESS_DETACH:
428     WaitForSingleObject(g_mutex, INFINITE);
429     --g_instance_count;
430     ReleaseMutex(g_mutex);
431 ossman_ 1069
432 ossman_ 1071 vchannel_close();
433 ossman_ 1069
434 ossman_ 1071 CloseHandle(g_mutex);
435 ossman_ 1069
436 ossman_ 1071 break;
437     }
438 ossman_ 1069
439 ossman_ 1071 return TRUE;
440 ossman_ 1069 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26