/[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 1437 - (show annotations)
Thu Feb 21 10:16:19 2008 UTC (16 years, 4 months ago) by astrand
File MIME type: text/plain
File size: 18114 byte(s)
Re-worked the logic for determining which windows to ignore (all but
toplevel ones). Also, rewrote get_parent to use a simpler and
documented approach.

A side effect of these changes is that combobox windows are now
correctly handled as top-level windows and thus can appear outside
application windows.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26