/[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 1439 - (show annotations)
Thu Mar 6 15:11:53 2008 UTC (16 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 17998 byte(s)
Yet another try at get_parent. The previous implementation incorrectly
returned -1 for many transient windows, which made them transient for
the root window rather than the application window at the X11 side.

With this implementation, the transient test case in
seamlessrdp-channel.txt passes.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26