/[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 1442 - (show annotations)
Thu Mar 6 15:35:28 2008 UTC (16 years, 3 months ago) by astrand
File MIME type: text/plain
File size: 18338 byte(s)
Applied patch:

[ 1715359 ] seamlessrdp topmost windows

(slightly modified). Requires support in rdesktop.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26