/[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 1412 - (show annotations)
Mon Jun 18 11:59:38 2007 UTC (16 years, 11 months ago) by ossman_
File MIME type: text/plain
File size: 17945 byte(s)
Add support for transferring window icons.

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-2006 Peter Åstrand <astrand@cendio.se> for Cendio AB
8 Copyright 2006-2007 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 void
79 update_position(HWND hwnd)
80 {
81 RECT rect, blocked;
82 HWND blocked_hwnd;
83 unsigned int serial;
84
85 WaitForSingleObject(g_mutex, INFINITE);
86 blocked_hwnd = g_block_move_hwnd;
87 serial = g_block_move_serial;
88 memcpy(&blocked, &g_block_move, sizeof(RECT));
89 ReleaseMutex(g_mutex);
90
91 vchannel_block();
92
93 if (!GetWindowRect(hwnd, &rect))
94 {
95 debug("GetWindowRect failed!\n");
96 goto end;
97 }
98
99 if ((hwnd == blocked_hwnd) && (rect.left == blocked.left) && (rect.top == blocked.top)
100 && (rect.right == blocked.right) && (rect.bottom == blocked.bottom))
101 goto end;
102
103 vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x",
104 hwnd,
105 rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
106
107 end:
108 vchannel_unblock();
109 }
110
111 static void
112 update_zorder(HWND hwnd)
113 {
114 HWND behind;
115 HWND block_hwnd, block_behind;
116 unsigned int serial;
117
118 WaitForSingleObject(g_mutex, INFINITE);
119 serial = g_blocked_zchange_serial;
120 block_hwnd = g_blocked_zchange[0];
121 block_behind = g_blocked_zchange[1];
122 ReleaseMutex(g_mutex);
123
124 vchannel_block();
125
126 behind = GetNextWindow(hwnd, GW_HWNDPREV);
127 while (behind)
128 {
129 LONG style;
130
131 style = GetWindowLong(behind, GWL_STYLE);
132
133 if ((!(style & WS_CHILD) || (style & WS_POPUP)) && (style & WS_VISIBLE))
134 break;
135
136 behind = GetNextWindow(behind, GW_HWNDPREV);
137 }
138
139 if ((hwnd == block_hwnd) && (behind == block_behind))
140 vchannel_write("ACK", "%u", serial);
141 else
142 vchannel_write("ZCHANGE", "0x%08lx,0x%08lx,0x%08x", hwnd, behind, 0);
143
144 vchannel_unblock();
145 }
146
147 static HWND
148 get_parent(HWND hwnd)
149 {
150 LONG style;
151 HWND parent;
152
153 style = GetWindowLong(hwnd, GWL_STYLE);
154
155 if (style & (WS_POPUP | DS_MODALFRAME))
156 {
157 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
158
159 if (parent)
160 {
161 style = GetWindowLong(parent, GWL_STYLE);
162 if (((style & WS_CHILD) && !(style & WS_POPUP)) || !(style & WS_VISIBLE))
163 parent = NULL;
164 }
165
166 if (!parent)
167 parent = GetWindow(hwnd, GW_OWNER);
168
169 if (parent)
170 {
171 style = GetWindowLong(parent, GWL_STYLE);
172 if (((style & WS_CHILD) && !(style & WS_POPUP)) || !(style & WS_VISIBLE))
173 parent = NULL;
174 }
175
176 if (!parent)
177 parent = (HWND) - 1;
178 }
179 else
180 parent = NULL;
181
182 return parent;
183 }
184
185 static HICON
186 get_icon(HWND hwnd, int large)
187 {
188 HICON icon;
189
190 if (!SendMessageTimeout(hwnd, WM_GETICON, large ? ICON_BIG : ICON_SMALL,
191 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) & icon))
192 return NULL;
193
194 if (icon)
195 return icon;
196
197 /*
198 * Modern versions of Windows uses the voodoo value of 2 instead of 0
199 * for the small icons.
200 */
201 if (!large)
202 {
203 if (!SendMessageTimeout(hwnd, WM_GETICON, 2,
204 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) & icon))
205 return NULL;
206 }
207
208 if (icon)
209 return icon;
210
211 icon = (HICON) GetClassLong(hwnd, large ? GCL_HICON : GCL_HICONSM);
212
213 if (icon)
214 return icon;
215
216 return NULL;
217 }
218
219 static int
220 extract_icon(HICON icon, char *buffer, int maxlen)
221 {
222 ICONINFO info;
223 HDC hdc;
224 BITMAP mask_bmp, color_bmp;
225 BITMAPINFO bmi;
226 int size, i;
227 char *mask_buf, *color_buf;
228 char *o, *m, *c;
229 int ret = -1;
230
231 assert(buffer);
232 assert(maxlen > 0);
233
234 if (!GetIconInfo(icon, &info))
235 goto fail;
236
237 if (!GetObject(info.hbmMask, sizeof(BITMAP), &mask_bmp))
238 goto free_bmps;
239 if (!GetObject(info.hbmColor, sizeof(BITMAP), &color_bmp))
240 goto free_bmps;
241
242 if (mask_bmp.bmWidth != color_bmp.bmWidth)
243 goto free_bmps;
244 if (mask_bmp.bmHeight != color_bmp.bmHeight)
245 goto free_bmps;
246
247 if ((mask_bmp.bmWidth * mask_bmp.bmHeight * 4) > maxlen)
248 goto free_bmps;
249
250 size = (mask_bmp.bmWidth + 3) / 4 * 4;
251 size *= mask_bmp.bmHeight;
252 size *= 4;
253
254 mask_buf = malloc(size);
255 if (!mask_buf)
256 goto free_bmps;
257 color_buf = malloc(size);
258 if (!color_buf)
259 goto free_mbuf;
260
261 memset(&bmi, 0, sizeof(BITMAPINFO));
262
263 bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
264 bmi.bmiHeader.biWidth = mask_bmp.bmWidth;
265 bmi.bmiHeader.biHeight = -mask_bmp.bmHeight;
266 bmi.bmiHeader.biPlanes = 1;
267 bmi.bmiHeader.biBitCount = 32;
268 bmi.bmiHeader.biCompression = BI_RGB;
269 bmi.bmiHeader.biSizeImage = size;
270
271 hdc = CreateCompatibleDC(NULL);
272 if (!hdc)
273 goto free_cbuf;
274
275 if (!GetDIBits(hdc, info.hbmMask, 0, mask_bmp.bmHeight, mask_buf, &bmi, DIB_RGB_COLORS))
276 goto del_dc;
277 if (!GetDIBits(hdc, info.hbmColor, 0, color_bmp.bmHeight, color_buf, &bmi, DIB_RGB_COLORS))
278 goto del_dc;
279
280 o = buffer;
281 m = mask_buf;
282 c = color_buf;
283 for (i = 0; i < size / 4; i++)
284 {
285 o[0] = c[2];
286 o[1] = c[1];
287 o[2] = c[0];
288
289 o[3] = ((int) (unsigned char) m[0] + (unsigned char) m[1] +
290 (unsigned char) m[2]) / 3;
291 o[3] = 0xff - o[3];
292
293 o += 4;
294 m += 4;
295 c += 4;
296 }
297
298 ret = size;
299
300 del_dc:
301 DeleteDC(hdc);
302
303 free_cbuf:
304 free(color_buf);
305 free_mbuf:
306 free(mask_buf);
307
308 free_bmps:
309 DeleteObject(info.hbmMask);
310 DeleteObject(info.hbmColor);
311
312 fail:
313 return ret;
314 }
315
316 #define ICON_CHUNK 400
317
318 static void
319 update_icon(HWND hwnd, HICON icon, int large)
320 {
321 int i, j, size, chunks;
322 char buf[32 * 32 * 4];
323 char asciibuf[ICON_CHUNK * 2 + 1];
324
325 size = extract_icon(icon, buf, sizeof(buf));
326 if (size <= 0)
327 return;
328
329 if ((!large && size != 16 * 16 * 4) || (large && size != 32 * 32 * 4))
330 {
331 debug("Unexpected icon size.");
332 return;
333 }
334
335 chunks = (size + ICON_CHUNK - 1) / ICON_CHUNK;
336 for (i = 0; i < chunks; i++)
337 {
338 for (j = 0; j < ICON_CHUNK; j++)
339 {
340 if (i * ICON_CHUNK + j >= size)
341 break;
342 sprintf(asciibuf + j * 2, "%02x",
343 (int) (unsigned char) buf[i * ICON_CHUNK + j]);
344 }
345
346 vchannel_write("SETICON", "0x%08lx,%d,RGBA,%d,%d,%s", hwnd, i,
347 large ? 32 : 16, large ? 32 : 16, asciibuf);
348 }
349 }
350
351 static LRESULT CALLBACK
352 wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
353 {
354 HWND hwnd, parent;
355 UINT msg;
356 WPARAM wparam;
357 LPARAM lparam;
358
359 LONG style;
360
361 if (code < 0)
362 goto end;
363
364 hwnd = ((CWPSTRUCT *) details)->hwnd;
365 msg = ((CWPSTRUCT *) details)->message;
366 wparam = ((CWPSTRUCT *) details)->wParam;
367 lparam = ((CWPSTRUCT *) details)->lParam;
368
369 style = GetWindowLong(hwnd, GWL_STYLE);
370
371 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
372 but they exist nonetheless. */
373 if ((style & WS_CHILD) && !(style & WS_POPUP))
374 goto end;
375
376 parent = get_parent(hwnd);
377
378 switch (msg)
379 {
380 case WM_WINDOWPOSCHANGED:
381 {
382 WINDOWPOS *wp = (WINDOWPOS *) lparam;
383
384 if (wp->flags & SWP_SHOWWINDOW)
385 {
386 unsigned short title[150];
387 int state;
388 DWORD pid;
389 int flags;
390 HICON icon;
391
392 GetWindowThreadProcessId(hwnd, &pid);
393
394 flags = 0;
395 if (style & DS_MODALFRAME)
396 flags |= SEAMLESS_CREATE_MODAL;
397
398 vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x",
399 (long) hwnd, (long) pid, (long) parent,
400 flags);
401
402 GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
403
404 vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
405 vchannel_strfilter_unicode(title), 0);
406
407 icon = get_icon(hwnd, 1);
408 if (icon)
409 {
410 update_icon(hwnd, icon, 1);
411 DeleteObject(icon);
412 }
413
414 icon = get_icon(hwnd, 0);
415 if (icon)
416 {
417 update_icon(hwnd, icon, 0);
418 DeleteObject(icon);
419 }
420
421 if (style & WS_MAXIMIZE)
422 state = 2;
423 else if (style & WS_MINIMIZE)
424 state = 1;
425 else
426 state = 0;
427
428 update_position(hwnd);
429
430 vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd,
431 state, 0);
432 }
433
434 if (wp->flags & SWP_HIDEWINDOW)
435 vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
436
437 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
438 break;
439
440 if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
441 update_position(hwnd);
442
443 break;
444 }
445
446 case WM_SETICON:
447 if (!(style & WS_VISIBLE))
448 break;
449
450 switch (wparam)
451 {
452 case ICON_BIG:
453 if (lparam)
454 update_icon(hwnd, (HICON) lparam, 1);
455 else
456 vchannel_write("DELICON", "0x%08lx,RGBA,32,32",
457 hwnd);
458 break;
459 case ICON_SMALL:
460 case 2:
461 if (lparam)
462 update_icon(hwnd, (HICON) lparam, 0);
463 else
464 vchannel_write("DELICON", "0x%08lx,RGBA,16,16",
465 hwnd);
466 break;
467 default:
468 debug("Weird icon size %d", (int) wparam);
469 }
470
471 break;
472
473 case WM_SIZE:
474 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
475 break;
476 update_position(hwnd);
477 break;
478
479 case WM_MOVE:
480 if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
481 break;
482 update_position(hwnd);
483 break;
484
485 case WM_DESTROY:
486 if (!(style & WS_VISIBLE))
487 break;
488 vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
489 break;
490
491 default:
492 break;
493 }
494
495 end:
496 return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
497 }
498
499 static LRESULT CALLBACK
500 wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)
501 {
502 HWND hwnd, parent;
503 UINT msg;
504 WPARAM wparam;
505 LPARAM lparam;
506
507 LONG style;
508
509 if (code < 0)
510 goto end;
511
512 hwnd = ((CWPRETSTRUCT *) details)->hwnd;
513 msg = ((CWPRETSTRUCT *) details)->message;
514 wparam = ((CWPRETSTRUCT *) details)->wParam;
515 lparam = ((CWPRETSTRUCT *) details)->lParam;
516
517 style = GetWindowLong(hwnd, GWL_STYLE);
518
519 /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
520 but they exist nonetheless. */
521 if ((style & WS_CHILD) && !(style & WS_POPUP))
522 goto end;
523
524 parent = get_parent(hwnd);
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) && !parent)
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