/[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 1450 - (show annotations)
Fri Mar 14 07:22:55 2008 UTC (16 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 18727 byte(s)
Corrected is_menu, so that menus works with Seamonkey as well.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26