/[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 1449 - (show annotations)
Tue Mar 11 08:21:33 2008 UTC (16 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 18596 byte(s)
Cleaner solution for the problem with menus disappearing on
SetForegroundWindow.

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 2005-2008 Peter Åstrand <astrand@cendio.se> for Cendio AB
8 Copyright 2006-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB
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 <assert.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28
29 #include <windows.h>
30 #include <winuser.h>
31
32 #include "../vchannel.h"
33
34 #define DLL_EXPORT __declspec(dllexport)
35
36 #ifdef __GNUC__
37 #define SHARED __attribute__((section ("SHAREDDATA"), shared))
38 #else
39 #define SHARED
40 #endif
41
42 // Shared DATA
43 #pragma data_seg ( "SHAREDDATA" )
44
45 // this is the total number of processes this dll is currently attached to
46 int g_instance_count SHARED = 0;
47
48 // blocks for locally generated events
49 HWND g_block_move_hwnd SHARED = NULL;
50 unsigned int g_block_move_serial SHARED = 0;
51 RECT g_block_move SHARED = { 0, 0, 0, 0 };
52
53 unsigned int g_blocked_zchange_serial SHARED = 0;
54 HWND g_blocked_zchange[2] SHARED = { NULL, NULL };
55
56 unsigned int g_blocked_focus_serial SHARED = 0;
57 HWND g_blocked_focus SHARED = NULL;
58
59 unsigned int g_blocked_state_serial SHARED = 0;
60 HWND g_blocked_state_hwnd SHARED = NULL;
61 int g_blocked_state SHARED = -1;
62
63 #pragma data_seg ()
64
65 #pragma comment(linker, "/section:SHAREDDATA,rws")
66
67 #define FOCUS_MSG_NAME "WM_SEAMLESS_FOCUS"
68 static UINT g_wm_seamless_focus;
69
70 static HHOOK g_cbt_hook = NULL;
71 static HHOOK g_wndproc_hook = NULL;
72 static HHOOK g_wndprocret_hook = NULL;
73
74 static HINSTANCE g_instance = NULL;
75
76 static HANDLE g_mutex = NULL;
77
78 static BOOL
79 is_toplevel(HWND hwnd)
80 {
81 BOOL toplevel;
82 HWND parent;
83 parent = GetAncestor(hwnd, GA_PARENT);
84
85 /* According to MS: "A window that has no parent, or whose
86 parent is the desktop window, is called a top-level
87 window." See http://msdn2.microsoft.com/en-us/library/ms632597(VS.85).aspx. */
88 toplevel = (!parent || parent == GetDesktopWindow());
89 return toplevel;
90 }
91
92 /* Returns true if a window is a menu window. */
93 static BOOL
94 is_menu(HWND hwnd)
95 {
96 HWND owner = GetWindow(hwnd, GW_OWNER);
97 LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
98 return (exstyle & (WS_EX_TOOLWINDOW | WS_EX_TOPMOST)) && owner;
99
100 }
101
102 /* Determine the "parent" field for the CREATE response. */
103 static HWND
104 get_parent(HWND hwnd)
105 {
106 HWND result;
107 HWND owner;
108 LONG exstyle;
109
110 /* Use the same logic to determine if the window should be
111 "transient" (ie have no task icon) as MS uses. This is documented at
112 http://msdn2.microsoft.com/en-us/library/bb776822.aspx */
113 owner = GetWindow(hwnd, GW_OWNER);
114 exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
115 if (!owner && !(exstyle & WS_EX_TOOLWINDOW))
116 {
117 /* display taskbar icon */
118 result = NULL;
119 }
120 else
121 {
122 /* no taskbar icon */
123 if (owner)
124 result = owner;
125 else
126 result = (HWND) - 1;
127 }
128
129 return result;
130 }
131
132 static void
133 update_position(HWND hwnd)
134 {
135 RECT rect, blocked;
136 HWND blocked_hwnd;
137 unsigned int serial;
138
139 WaitForSingleObject(g_mutex, INFINITE);
140 blocked_hwnd = g_block_move_hwnd;
141 serial = g_block_move_serial;
142 memcpy(&blocked, &g_block_move, sizeof(RECT));
143 ReleaseMutex(g_mutex);
144
145 vchannel_block();
146
147 if (!GetWindowRect(hwnd, &rect))
148 {
149 debug("GetWindowRect failed!\n");
150 goto end;
151 }
152
153 if ((hwnd == blocked_hwnd) && (rect.left == blocked.left) && (rect.top == blocked.top)
154 && (rect.right == blocked.right) && (rect.bottom == blocked.bottom))
155 goto end;
156
157 vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x",
158 hwnd,
159 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
160
161 end:
162 vchannel_unblock();
163 }
164
165 static void
166 update_zorder(HWND hwnd)
167 {
168 HWND behind;
169 HWND block_hwnd, block_behind;
170 unsigned int serial;
171
172 WaitForSingleObject(g_mutex, INFINITE);
173 serial = g_blocked_zchange_serial;
174 block_hwnd = g_blocked_zchange[0];
175 block_behind = g_blocked_zchange[1];
176 ReleaseMutex(g_mutex);
177
178 vchannel_block();
179
180 behind = GetNextWindow(hwnd, GW_HWNDPREV);
181 while (behind)
182 {
183 LONG style;
184
185 style = GetWindowLong(behind, GWL_STYLE);
186
187 if ((!(style & WS_CHILD) || (style & WS_POPUP)) && (style & WS_VISIBLE))
188 break;
189
190 behind = GetNextWindow(behind, GW_HWNDPREV);
191 }
192
193 if ((hwnd == block_hwnd) && (behind == block_behind))
194 vchannel_write("ACK", "%u", serial);
195 else
196 {
197 int flags = 0;
198 LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
199 // handle always on top
200 if (exstyle & WS_EX_TOPMOST)
201 flags |= SEAMLESS_CREATE_TOPMOST;
202 vchannel_write("ZCHANGE", "0x%08lx,0x%08lx,0x%08x", hwnd, behind, flags);
203 }
204
205 vchannel_unblock();
206 }
207
208 static HICON
209 get_icon(HWND hwnd, int large)
210 {
211 HICON icon;
212
213 if (!SendMessageTimeout(hwnd, WM_GETICON, large ? ICON_BIG : ICON_SMALL,
214 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) & icon))
215 return NULL;
216
217 if (icon)
218 return icon;
219
220 /*
221 * Modern versions of Windows uses the voodoo value of 2 instead of 0
222 * for the small icons.
223 */
224 if (!large)
225 {
226 if (!SendMessageTimeout(hwnd, WM_GETICON, 2,
227 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) & icon))
228 return NULL;
229 }
230
231 if (icon)
232 return icon;
233
234 icon = (HICON) GetClassLong(hwnd, large ? GCL_HICON : GCL_HICONSM);
235
236 if (icon)
237 return icon;
238
239 return NULL;
240 }
241
242 static int
243 extract_icon(HICON icon, char *buffer, int maxlen)
244 {
245 ICONINFO info;
246 HDC hdc;
247 BITMAP mask_bmp, color_bmp;
248 BITMAPINFO bmi;
249 int size, i;
250 char *mask_buf, *color_buf;
251 char *o, *m, *c;
252 int ret = -1;
253
254 assert(buffer);
255 assert(maxlen > 0);
256
257 if (!GetIconInfo(icon, &info))
258 goto fail;
259
260 if (!GetObject(info.hbmMask, sizeof(BITMAP), &mask_bmp))
261 goto free_bmps;
262 if (!GetObject(info.hbmColor, sizeof(BITMAP), &color_bmp))
263 goto free_bmps;
264
265 if (mask_bmp.bmWidth != color_bmp.bmWidth)
266 goto free_bmps;
267 if (mask_bmp.bmHeight != color_bmp.bmHeight)
268 goto free_bmps;
269
270 if ((mask_bmp.bmWidth * mask_bmp.bmHeight * 4) > maxlen)
271 goto free_bmps;
272
273 size = (mask_bmp.bmWidth + 3) / 4 * 4;
274 size *= mask_bmp.bmHeight;
275 size *= 4;
276
277 mask_buf = malloc(size);
278 if (!mask_buf)
279 goto free_bmps;
280 color_buf = malloc(size);
281 if (!color_buf)
282 goto free_mbuf;
283
284 memset(&bmi, 0, sizeof(BITMAPINFO));
285
286 bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
287 bmi.bmiHeader.biWidth = mask_bmp.bmWidth;
288 bmi.bmiHeader.biHeight = -mask_bmp.bmHeight;
289 bmi.bmiHeader.biPlanes = 1;
290 bmi.bmiHeader.biBitCount = 32;
291 bmi.bmiHeader.biCompression = BI_RGB;
292 bmi.bmiHeader.biSizeImage = size;
293
294 hdc = CreateCompatibleDC(NULL);
295 if (!hdc)
296 goto free_cbuf;
297
298 if (!GetDIBits(hdc, info.hbmMask, 0, mask_bmp.bmHeight, mask_buf, &bmi, DIB_RGB_COLORS))
299 goto del_dc;
300 if (!GetDIBits(hdc, info.hbmColor, 0, color_bmp.bmHeight, color_buf, &bmi, DIB_RGB_COLORS))
301 goto del_dc;
302
303 o = buffer;
304 m = mask_buf;
305 c = color_buf;
306 for (i = 0; i < size / 4; i++)
307 {
308 o[0] = c[2];
309 o[1] = c[1];
310 o[2] = c[0];
311
312 o[3] = ((int) (unsigned char) m[0] + (unsigned char) m[1] +
313 (unsigned char) m[2]) / 3;
314 o[3] = 0xff - o[3];
315
316 o += 4;
317 m += 4;
318 c += 4;
319 }
320
321 ret = size;
322
323 del_dc:
324 DeleteDC(hdc);
325
326 free_cbuf:
327 free(color_buf);
328 free_mbuf:
329 free(mask_buf);
330
331 free_bmps:
332 DeleteObject(info.hbmMask);
333 DeleteObject(info.hbmColor);
334
335 fail:
336 return ret;
337 }
338
339 #define ICON_CHUNK 400
340
341 static void
342 update_icon(HWND hwnd, HICON icon, int large)
343 {
344 int i, j, size, chunks;
345 char buf[32 * 32 * 4];
346 char asciibuf[ICON_CHUNK * 2 + 1];
347
348 size = extract_icon(icon, buf, sizeof(buf));
349 if (size <= 0)
350 return;
351
352 if ((!large && size != 16 * 16 * 4) || (large && size != 32 * 32 * 4))
353 {
354 debug("Unexpected icon size.");
355 return;
356 }
357
358 chunks = (size + ICON_CHUNK - 1) / ICON_CHUNK;
359 for (i = 0; i < chunks; i++)
360 {
361 for (j = 0; j < ICON_CHUNK; j++)
362 {
363 if (i * ICON_CHUNK + j >= size)
364 break;
365 sprintf(asciibuf + j * 2, "%02x",
366 (int) (unsigned char) buf[i * ICON_CHUNK + j]);
367 }
368
369 vchannel_write("SETICON", "0x%08lx,%d,RGBA,%d,%d,%s", hwnd, i,
370 large ? 32 : 16, large ? 32 : 16, asciibuf);
371 }
372 }
373
374 static LRESULT CALLBACK
375 wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
376 {
377 HWND hwnd;
378 UINT msg;
379 WPARAM wparam;
380 LPARAM lparam;
381
382 LONG style;
383
384 if (code < 0)
385 goto end;
386
387 hwnd = ((CWPSTRUCT *) details)->hwnd;
388 msg = ((CWPSTRUCT *) details)->message;
389 wparam = ((CWPSTRUCT *) details)->wParam;
390 lparam = ((CWPSTRUCT *) details)->lParam;
391
392 if (!is_toplevel(hwnd))
393 {
394 goto end;
395 }
396
397 style = GetWindowLong(hwnd, GWL_STYLE);
398
399 switch (msg)
400 {
401 case WM_WINDOWPOSCHANGED:
402 {
403 WINDOWPOS *wp = (WINDOWPOS *) lparam;
404
405 if (wp->flags & SWP_SHOWWINDOW)
406 {
407 unsigned short title[150];
408 int state;
409 DWORD pid;
410 int flags;
411 HICON icon;
412 LONG exstyle;
413
414 exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
415 GetWindowThreadProcessId(hwnd, &pid);
416
417 flags = 0;
418 if (style & DS_MODALFRAME)
419 flags |= SEAMLESS_CREATE_MODAL;
420 // handle always on top
421 if (exstyle & WS_EX_TOPMOST)
422 flags |= SEAMLESS_CREATE_TOPMOST;
423
424 vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x",
425 (long) hwnd, (long) pid,
426 (long) get_parent(hwnd), flags);
427
428 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
429
430 vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
431 vchannel_strfilter_unicode(title), 0);
432
433 icon = get_icon(hwnd, 1);
434 if (icon)
435 {
436 update_icon(hwnd, icon, 1);
437 DeleteObject(icon);
438 }
439
440 icon = get_icon(hwnd, 0);
441 if (icon)
442 {
443 update_icon(hwnd, icon, 0);
444 DeleteObject(icon);
445 }
446
447 if (style & WS_MAXIMIZE)
448 state = 2;
449 else if (style & WS_MINIMIZE)
450 state = 1;
451 else
452 state = 0;
453
454 update_position(hwnd);
455
456 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd,
457 state, 0);
458 }
459
460 if (wp->flags & SWP_HIDEWINDOW)
461 vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
462
463 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
464 break;
465
466 if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
467 update_position(hwnd);
468
469 break;
470 }
471
472 case WM_SETICON:
473 if (!(style & WS_VISIBLE))
474 break;
475
476 switch (wparam)
477 {
478 case ICON_BIG:
479 if (lparam)
480 update_icon(hwnd, (HICON) lparam, 1);
481 else
482 vchannel_write("DELICON", "0x%08lx,RGBA,32,32",
483 hwnd);
484 break;
485 case ICON_SMALL:
486 case 2:
487 if (lparam)
488 update_icon(hwnd, (HICON) lparam, 0);
489 else
490 vchannel_write("DELICON", "0x%08lx,RGBA,16,16",
491 hwnd);
492 break;
493 default:
494 debug("Weird icon size %d", (int) wparam);
495 }
496
497 break;
498
499 case WM_SIZE:
500 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
501 break;
502 update_position(hwnd);
503 break;
504
505 case WM_MOVE:
506 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
507 break;
508 update_position(hwnd);
509 break;
510
511 case WM_DESTROY:
512 if (!(style & WS_VISIBLE))
513 break;
514 vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
515 break;
516
517 default:
518 break;
519 }
520
521 end:
522 return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
523 }
524
525 static LRESULT CALLBACK
526 wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)
527 {
528 HWND hwnd;
529 UINT msg;
530 WPARAM wparam;
531 LPARAM lparam;
532
533 LONG style;
534
535 if (code < 0)
536 goto end;
537
538 hwnd = ((CWPRETSTRUCT *) details)->hwnd;
539 msg = ((CWPRETSTRUCT *) details)->message;
540 wparam = ((CWPRETSTRUCT *) details)->wParam;
541 lparam = ((CWPRETSTRUCT *) details)->lParam;
542
543 if (!is_toplevel(hwnd))
544 {
545 goto end;
546 }
547
548 style = GetWindowLong(hwnd, GWL_STYLE);
549
550 switch (msg)
551 {
552 case WM_WINDOWPOSCHANGED:
553 {
554 WINDOWPOS *wp = (WINDOWPOS *) lparam;
555
556 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
557 break;
558
559 if (!(wp->flags & SWP_NOZORDER))
560 update_zorder(hwnd);
561
562 break;
563 }
564
565
566 case WM_SETTEXT:
567 {
568 unsigned short title[150];
569 if (!(style & WS_VISIBLE))
570 break;
571 /* We cannot use the string in lparam because
572 we need unicode. */
573 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
574 vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
575 vchannel_strfilter_unicode(title), 0);
576 break;
577 }
578
579 case WM_SETICON:
580 {
581 HICON icon;
582
583 /*
584 * Somehow, we never get WM_SETICON for the small icon.
585 * So trigger a read of it every time the large one is
586 * changed.
587 */
588 icon = get_icon(hwnd, 0);
589 if (icon)
590 {
591 update_icon(hwnd, icon, 0);
592 DeleteObject(icon);
593 }
594 }
595
596 default:
597 break;
598 }
599
600 if (msg == g_wm_seamless_focus)
601 {
602 /* For some reason, SetForegroundWindow() on menus
603 closes them. Ignore focus requests for menu windows. */
604 if ((GetForegroundWindow() != hwnd) && !is_menu(hwnd))
605 SetForegroundWindow(hwnd);
606
607 vchannel_write("ACK", "%u", g_blocked_focus_serial);
608 }
609
610 end:
611 return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details);
612 }
613
614 static LRESULT CALLBACK
615 cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
616 {
617 if (code < 0)
618 goto end;
619
620 switch (code)
621 {
622 case HCBT_MINMAX:
623 {
624 int show, state, blocked;
625 HWND hwnd, blocked_hwnd;
626 unsigned int serial;
627 LONG style;
628
629 WaitForSingleObject(g_mutex, INFINITE);
630 blocked_hwnd = g_blocked_state_hwnd;
631 serial = g_blocked_state_serial;
632 blocked = g_blocked_state;
633 ReleaseMutex(g_mutex);
634
635 hwnd = (HWND) wparam;
636
637 style = GetWindowLong(hwnd, GWL_STYLE);
638
639 if (!(style & WS_VISIBLE))
640 break;
641
642 show = LOWORD(lparam);
643
644 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
645 || (show == SW_RESTORE))
646 state = 0;
647 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
648 state = 1;
649 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
650 state = 2;
651 else
652 {
653 debug("Unexpected show: %d", show);
654 break;
655 }
656
657 if ((blocked_hwnd == hwnd) && (blocked == state))
658 vchannel_write("ACK", "%u", serial);
659 else
660 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x",
661 hwnd, state, 0);
662
663 break;
664 }
665
666 default:
667 break;
668 }
669
670 end:
671 return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
672 }
673
674 DLL_EXPORT void
675 SetHooks(void)
676 {
677 if (!g_cbt_hook)
678 g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
679
680 if (!g_wndproc_hook)
681 g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
682
683 if (!g_wndprocret_hook)
684 g_wndprocret_hook =
685 SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
686 }
687
688 DLL_EXPORT void
689 RemoveHooks(void)
690 {
691 if (g_cbt_hook)
692 UnhookWindowsHookEx(g_cbt_hook);
693
694 if (g_wndproc_hook)
695 UnhookWindowsHookEx(g_wndproc_hook);
696
697 if (g_wndprocret_hook)
698 UnhookWindowsHookEx(g_wndprocret_hook);
699 }
700
701 DLL_EXPORT void
702 SafeMoveWindow(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
703 {
704 RECT rect;
705
706 WaitForSingleObject(g_mutex, INFINITE);
707 g_block_move_hwnd = hwnd;
708 g_block_move_serial = serial;
709 g_block_move.left = x;
710 g_block_move.top = y;
711 g_block_move.right = x + width;
712 g_block_move.bottom = y + height;
713 ReleaseMutex(g_mutex);
714
715 SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER);
716
717 vchannel_write("ACK", "%u", serial);
718
719 if (!GetWindowRect(hwnd, &rect))
720 debug("GetWindowRect failed!\n");
721 else if ((rect.left != x) || (rect.top != y) || (rect.right != x + width)
722 || (rect.bottom != y + height))
723 update_position(hwnd);
724
725 WaitForSingleObject(g_mutex, INFINITE);
726 g_block_move_hwnd = NULL;
727 memset(&g_block_move, 0, sizeof(RECT));
728 ReleaseMutex(g_mutex);
729 }
730
731 DLL_EXPORT void
732 SafeZChange(unsigned int serial, HWND hwnd, HWND behind)
733 {
734 WaitForSingleObject(g_mutex, INFINITE);
735 g_blocked_zchange_serial = serial;
736 g_blocked_zchange[0] = hwnd;
737 g_blocked_zchange[1] = behind;
738 ReleaseMutex(g_mutex);
739
740 if (behind == NULL)
741 behind = HWND_TOP;
742
743 SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
744
745 WaitForSingleObject(g_mutex, INFINITE);
746 g_blocked_zchange[0] = NULL;
747 g_blocked_zchange[1] = NULL;
748 ReleaseMutex(g_mutex);
749 }
750
751 DLL_EXPORT void
752 SafeFocus(unsigned int serial, HWND hwnd)
753 {
754 WaitForSingleObject(g_mutex, INFINITE);
755 g_blocked_focus_serial = serial;
756 g_blocked_focus = hwnd;
757 ReleaseMutex(g_mutex);
758
759 SendMessage(hwnd, g_wm_seamless_focus, 0, 0);
760
761 WaitForSingleObject(g_mutex, INFINITE);
762 g_blocked_focus = NULL;
763 ReleaseMutex(g_mutex);
764 }
765
766 DLL_EXPORT void
767 SafeSetState(unsigned int serial, HWND hwnd, int state)
768 {
769 LONG style;
770 int curstate;
771
772 vchannel_block();
773
774 style = GetWindowLong(hwnd, GWL_STYLE);
775
776 if (style & WS_MAXIMIZE)
777 curstate = 2;
778 else if (style & WS_MINIMIZE)
779 curstate = 1;
780 else
781 curstate = 0;
782
783 if (state == curstate)
784 {
785 vchannel_write("ACK", "%u", serial);
786 vchannel_unblock();
787 return;
788 }
789
790 WaitForSingleObject(g_mutex, INFINITE);
791 g_blocked_state_hwnd = hwnd;
792 g_blocked_state_serial = serial;
793 g_blocked_state = state;
794 ReleaseMutex(g_mutex);
795
796 vchannel_unblock();
797
798 if (state == 0)
799 ShowWindow(hwnd, SW_RESTORE);
800 else if (state == 1)
801 ShowWindow(hwnd, SW_MINIMIZE);
802 else if (state == 2)
803 ShowWindow(hwnd, SW_MAXIMIZE);
804 else
805 debug("Invalid state %d sent.", state);
806
807 WaitForSingleObject(g_mutex, INFINITE);
808 g_blocked_state_hwnd = NULL;
809 g_blocked_state = -1;
810 ReleaseMutex(g_mutex);
811 }
812
813 DLL_EXPORT int
814 GetInstanceCount()
815 {
816 return g_instance_count;
817 }
818
819 BOOL APIENTRY
820 DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
821 {
822 switch (ul_reason_for_call)
823 {
824 case DLL_PROCESS_ATTACH:
825 // remember our instance handle
826 g_instance = hinstDLL;
827
828 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
829 if (!g_mutex)
830 return FALSE;
831
832 WaitForSingleObject(g_mutex, INFINITE);
833 ++g_instance_count;
834 ReleaseMutex(g_mutex);
835
836 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
837
838 vchannel_open();
839
840 break;
841
842 case DLL_THREAD_ATTACH:
843 break;
844
845 case DLL_THREAD_DETACH:
846 break;
847
848 case DLL_PROCESS_DETACH:
849 vchannel_write("DESTROYGRP", "0x%08lx, 0x%08lx", GetCurrentProcessId(), 0);
850
851 WaitForSingleObject(g_mutex, INFINITE);
852 --g_instance_count;
853 ReleaseMutex(g_mutex);
854
855 vchannel_close();
856
857 CloseHandle(g_mutex);
858
859 break;
860 }
861
862 return TRUE;
863 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26