/[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 1440 - (show annotations)
Thu Mar 6 15:12:26 2008 UTC (16 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 17995 byte(s)
Ran indent-all

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 /* Determine the "parent" field for the CREATE response. */
93 static HWND
94 get_parent(HWND hwnd)
95 {
96 HWND result;
97 HWND owner;
98 LONG exstyle;
99
100 /* Use the same logic to determine if the window should be
101 "transient" (ie have no task icon) as MS uses. This is documented at
102 http://msdn2.microsoft.com/en-us/library/bb776822.aspx */
103 owner = GetWindow(hwnd, GW_OWNER);
104 exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
105 if (!owner && !(exstyle & WS_EX_TOOLWINDOW))
106 {
107 /* display taskbar icon */
108 result = NULL;
109 }
110 else
111 {
112 /* no taskbar icon */
113 if (owner)
114 result = owner;
115 else
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 {
379 goto end;
380 }
381
382 switch (msg)
383 {
384 case WM_WINDOWPOSCHANGED:
385 {
386 WINDOWPOS *wp = (WINDOWPOS *) lparam;
387
388 if (wp->flags & SWP_SHOWWINDOW)
389 {
390 unsigned short title[150];
391 int state;
392 DWORD pid;
393 int flags;
394 HICON icon;
395
396 GetWindowThreadProcessId(hwnd, &pid);
397
398 flags = 0;
399 if (style & DS_MODALFRAME)
400 flags |= SEAMLESS_CREATE_MODAL;
401
402 vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x",
403 (long) hwnd, (long) pid,
404 (long) get_parent(hwnd), flags);
405
406 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
407
408 vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
409 vchannel_strfilter_unicode(title), 0);
410
411 icon = get_icon(hwnd, 1);
412 if (icon)
413 {
414 update_icon(hwnd, icon, 1);
415 DeleteObject(icon);
416 }
417
418 icon = get_icon(hwnd, 0);
419 if (icon)
420 {
421 update_icon(hwnd, icon, 0);
422 DeleteObject(icon);
423 }
424
425 if (style & WS_MAXIMIZE)
426 state = 2;
427 else if (style & WS_MINIMIZE)
428 state = 1;
429 else
430 state = 0;
431
432 update_position(hwnd);
433
434 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd,
435 state, 0);
436 }
437
438 if (wp->flags & SWP_HIDEWINDOW)
439 vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
440
441 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
442 break;
443
444 if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
445 update_position(hwnd);
446
447 break;
448 }
449
450 case WM_SETICON:
451 if (!(style & WS_VISIBLE))
452 break;
453
454 switch (wparam)
455 {
456 case ICON_BIG:
457 if (lparam)
458 update_icon(hwnd, (HICON) lparam, 1);
459 else
460 vchannel_write("DELICON", "0x%08lx,RGBA,32,32",
461 hwnd);
462 break;
463 case ICON_SMALL:
464 case 2:
465 if (lparam)
466 update_icon(hwnd, (HICON) lparam, 0);
467 else
468 vchannel_write("DELICON", "0x%08lx,RGBA,16,16",
469 hwnd);
470 break;
471 default:
472 debug("Weird icon size %d", (int) wparam);
473 }
474
475 break;
476
477 case WM_SIZE:
478 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
479 break;
480 update_position(hwnd);
481 break;
482
483 case WM_MOVE:
484 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
485 break;
486 update_position(hwnd);
487 break;
488
489 case WM_DESTROY:
490 if (!(style & WS_VISIBLE))
491 break;
492 vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
493 break;
494
495 default:
496 break;
497 }
498
499 end:
500 return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
501 }
502
503 static LRESULT CALLBACK
504 wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)
505 {
506 HWND hwnd;
507 UINT msg;
508 WPARAM wparam;
509 LPARAM lparam;
510
511 LONG style;
512
513 if (code < 0)
514 goto end;
515
516 hwnd = ((CWPRETSTRUCT *) details)->hwnd;
517 msg = ((CWPRETSTRUCT *) details)->message;
518 wparam = ((CWPRETSTRUCT *) details)->wParam;
519 lparam = ((CWPRETSTRUCT *) details)->lParam;
520
521 style = GetWindowLong(hwnd, GWL_STYLE);
522
523 if (!is_toplevel(hwnd))
524 {
525 goto end;
526 }
527
528 switch (msg)
529 {
530 case WM_WINDOWPOSCHANGED:
531 {
532 WINDOWPOS *wp = (WINDOWPOS *) lparam;
533
534 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
535 break;
536
537 if (!(wp->flags & SWP_NOZORDER))
538 update_zorder(hwnd);
539
540 break;
541 }
542
543
544 case WM_SETTEXT:
545 {
546 unsigned short title[150];
547 if (!(style & WS_VISIBLE))
548 break;
549 /* We cannot use the string in lparam because
550 we need unicode. */
551 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
552 vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
553 vchannel_strfilter_unicode(title), 0);
554 break;
555 }
556
557 case WM_SETICON:
558 {
559 HICON icon;
560
561 /*
562 * Somehow, we never get WM_SETICON for the small icon.
563 * So trigger a read of it every time the large one is
564 * changed.
565 */
566 icon = get_icon(hwnd, 0);
567 if (icon)
568 {
569 update_icon(hwnd, icon, 0);
570 DeleteObject(icon);
571 }
572 }
573
574 default:
575 break;
576 }
577
578 if (msg == g_wm_seamless_focus)
579 {
580 /* FIXME: SetForegroundWindow() kills menus. Need to find a
581 clean way to solve this. */
582 if ((GetForegroundWindow() != hwnd) && !get_parent(hwnd))
583 SetForegroundWindow(hwnd);
584
585 vchannel_write("ACK", "%u", g_blocked_focus_serial);
586 }
587
588 end:
589 return CallNextHookEx(g_wndprocret_hook, code, cur_thread, details);
590 }
591
592 static LRESULT CALLBACK
593 cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
594 {
595 if (code < 0)
596 goto end;
597
598 switch (code)
599 {
600 case HCBT_MINMAX:
601 {
602 int show, state, blocked;
603 HWND hwnd, blocked_hwnd;
604 unsigned int serial;
605 LONG style;
606
607 WaitForSingleObject(g_mutex, INFINITE);
608 blocked_hwnd = g_blocked_state_hwnd;
609 serial = g_blocked_state_serial;
610 blocked = g_blocked_state;
611 ReleaseMutex(g_mutex);
612
613 hwnd = (HWND) wparam;
614
615 style = GetWindowLong(hwnd, GWL_STYLE);
616
617 if (!(style & WS_VISIBLE))
618 break;
619
620 show = LOWORD(lparam);
621
622 if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
623 || (show == SW_RESTORE))
624 state = 0;
625 else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
626 state = 1;
627 else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
628 state = 2;
629 else
630 {
631 debug("Unexpected show: %d", show);
632 break;
633 }
634
635 if ((blocked_hwnd == hwnd) && (blocked == state))
636 vchannel_write("ACK", "%u", serial);
637 else
638 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x",
639 hwnd, state, 0);
640
641 break;
642 }
643
644 default:
645 break;
646 }
647
648 end:
649 return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
650 }
651
652 DLL_EXPORT void
653 SetHooks(void)
654 {
655 if (!g_cbt_hook)
656 g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
657
658 if (!g_wndproc_hook)
659 g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
660
661 if (!g_wndprocret_hook)
662 g_wndprocret_hook =
663 SetWindowsHookEx(WH_CALLWNDPROCRET, wndprocret_hook_proc, g_instance, 0);
664 }
665
666 DLL_EXPORT void
667 RemoveHooks(void)
668 {
669 if (g_cbt_hook)
670 UnhookWindowsHookEx(g_cbt_hook);
671
672 if (g_wndproc_hook)
673 UnhookWindowsHookEx(g_wndproc_hook);
674
675 if (g_wndprocret_hook)
676 UnhookWindowsHookEx(g_wndprocret_hook);
677 }
678
679 DLL_EXPORT void
680 SafeMoveWindow(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
681 {
682 RECT rect;
683
684 WaitForSingleObject(g_mutex, INFINITE);
685 g_block_move_hwnd = hwnd;
686 g_block_move_serial = serial;
687 g_block_move.left = x;
688 g_block_move.top = y;
689 g_block_move.right = x + width;
690 g_block_move.bottom = y + height;
691 ReleaseMutex(g_mutex);
692
693 SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOACTIVATE | SWP_NOZORDER);
694
695 vchannel_write("ACK", "%u", serial);
696
697 if (!GetWindowRect(hwnd, &rect))
698 debug("GetWindowRect failed!\n");
699 else if ((rect.left != x) || (rect.top != y) || (rect.right != x + width)
700 || (rect.bottom != y + height))
701 update_position(hwnd);
702
703 WaitForSingleObject(g_mutex, INFINITE);
704 g_block_move_hwnd = NULL;
705 memset(&g_block_move, 0, sizeof(RECT));
706 ReleaseMutex(g_mutex);
707 }
708
709 DLL_EXPORT void
710 SafeZChange(unsigned int serial, HWND hwnd, HWND behind)
711 {
712 WaitForSingleObject(g_mutex, INFINITE);
713 g_blocked_zchange_serial = serial;
714 g_blocked_zchange[0] = hwnd;
715 g_blocked_zchange[1] = behind;
716 ReleaseMutex(g_mutex);
717
718 if (behind == NULL)
719 behind = HWND_TOP;
720
721 SetWindowPos(hwnd, behind, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
722
723 WaitForSingleObject(g_mutex, INFINITE);
724 g_blocked_zchange[0] = NULL;
725 g_blocked_zchange[1] = NULL;
726 ReleaseMutex(g_mutex);
727 }
728
729 DLL_EXPORT void
730 SafeFocus(unsigned int serial, HWND hwnd)
731 {
732 WaitForSingleObject(g_mutex, INFINITE);
733 g_blocked_focus_serial = serial;
734 g_blocked_focus = hwnd;
735 ReleaseMutex(g_mutex);
736
737 SendMessage(hwnd, g_wm_seamless_focus, 0, 0);
738
739 WaitForSingleObject(g_mutex, INFINITE);
740 g_blocked_focus = NULL;
741 ReleaseMutex(g_mutex);
742 }
743
744 DLL_EXPORT void
745 SafeSetState(unsigned int serial, HWND hwnd, int state)
746 {
747 LONG style;
748 int curstate;
749
750 vchannel_block();
751
752 style = GetWindowLong(hwnd, GWL_STYLE);
753
754 if (style & WS_MAXIMIZE)
755 curstate = 2;
756 else if (style & WS_MINIMIZE)
757 curstate = 1;
758 else
759 curstate = 0;
760
761 if (state == curstate)
762 {
763 vchannel_write("ACK", "%u", serial);
764 vchannel_unblock();
765 return;
766 }
767
768 WaitForSingleObject(g_mutex, INFINITE);
769 g_blocked_state_hwnd = hwnd;
770 g_blocked_state_serial = serial;
771 g_blocked_state = state;
772 ReleaseMutex(g_mutex);
773
774 vchannel_unblock();
775
776 if (state == 0)
777 ShowWindow(hwnd, SW_RESTORE);
778 else if (state == 1)
779 ShowWindow(hwnd, SW_MINIMIZE);
780 else if (state == 2)
781 ShowWindow(hwnd, SW_MAXIMIZE);
782 else
783 debug("Invalid state %d sent.", state);
784
785 WaitForSingleObject(g_mutex, INFINITE);
786 g_blocked_state_hwnd = NULL;
787 g_blocked_state = -1;
788 ReleaseMutex(g_mutex);
789 }
790
791 DLL_EXPORT int
792 GetInstanceCount()
793 {
794 return g_instance_count;
795 }
796
797 BOOL APIENTRY
798 DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
799 {
800 switch (ul_reason_for_call)
801 {
802 case DLL_PROCESS_ATTACH:
803 // remember our instance handle
804 g_instance = hinstDLL;
805
806 g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
807 if (!g_mutex)
808 return FALSE;
809
810 WaitForSingleObject(g_mutex, INFINITE);
811 ++g_instance_count;
812 ReleaseMutex(g_mutex);
813
814 g_wm_seamless_focus = RegisterWindowMessage(FOCUS_MSG_NAME);
815
816 vchannel_open();
817
818 break;
819
820 case DLL_THREAD_ATTACH:
821 break;
822
823 case DLL_THREAD_DETACH:
824 break;
825
826 case DLL_PROCESS_DETACH:
827 vchannel_write("DESTROYGRP", "0x%08lx, 0x%08lx", GetCurrentProcessId(), 0);
828
829 WaitForSingleObject(g_mutex, INFINITE);
830 --g_instance_count;
831 ReleaseMutex(g_mutex);
832
833 vchannel_close();
834
835 CloseHandle(g_mutex);
836
837 break;
838 }
839
840 return TRUE;
841 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26