/[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

Diff of /sourceforge.net/trunk/seamlessrdp/ServerExe/HookDll/hookdll.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1167 by ossman_, Mon Mar 20 14:35:02 2006 UTC revision 1439 by astrand, Thu Mar 6 15:11:53 2008 UTC
# Line 4  Line 4 
4    
5     Based on code copyright (C) 2004-2005 Martin Wickett     Based on code copyright (C) 2004-2005 Martin Wickett
6    
7     Copyright (C) Peter Åstrand <astrand@cendio.se> 2005-2006     Copyright 2005-2008 Peter Åstrand <astrand@cendio.se> for Cendio AB
8     Copyright (C) Pierre Ossman <ossman@cendio.se> 2006     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     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     it under the terms of the GNU General Public License as published by
# Line 22  Line 22 
22     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */  */
24    
25    #include <assert.h>
26  #include <stdio.h>  #include <stdio.h>
27  #include <stdarg.h>  #include <stdarg.h>
28    
# Line 74  static HINSTANCE g_instance = NULL; Line 75  static HINSTANCE g_instance = NULL;
75    
76  static HANDLE g_mutex = NULL;  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            {
106                    /* display taskbar icon */
107                    result = NULL;
108            }
109            else
110            {
111                    /* no taskbar icon */
112                    if (owner)
113                            result = owner;
114                    else
115                            result = (HWND) - 1;
116            }
117    
118            return result;
119    }
120    
121  static void  static void
122  update_position(HWND hwnd)  update_position(HWND hwnd)
123  {  {
# Line 99  update_position(HWND hwnd) Line 143  update_position(HWND hwnd)
143              && (rect.right == blocked.right) && (rect.bottom == blocked.bottom))              && (rect.right == blocked.right) && (rect.bottom == blocked.bottom))
144                  goto end;                  goto end;
145    
146          vchannel_write("POSITION", "0x%p,%d,%d,%d,%d,0x%x",          vchannel_write("POSITION", "0x%08lx,%d,%d,%d,%d,0x%08x",
147                         hwnd,                         hwnd,
148                         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);                         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
149    
# Line 138  update_zorder(HWND hwnd) Line 182  update_zorder(HWND hwnd)
182          if ((hwnd == block_hwnd) && (behind == block_behind))          if ((hwnd == block_hwnd) && (behind == block_behind))
183                  vchannel_write("ACK", "%u", serial);                  vchannel_write("ACK", "%u", serial);
184          else          else
185                  vchannel_write("ZCHANGE", "0x%p,0x%p,0x%x", hwnd, behind, 0);                  vchannel_write("ZCHANGE", "0x%08lx,0x%08lx,0x%08x", hwnd, behind, 0);
186    
187          vchannel_unblock();          vchannel_unblock();
188  }  }
189    
190    static HICON
191    get_icon(HWND hwnd, int large)
192    {
193            HICON icon;
194    
195            if (!SendMessageTimeout(hwnd, WM_GETICON, large ? ICON_BIG : ICON_SMALL,
196                                    0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) & icon))
197                    return NULL;
198    
199            if (icon)
200                    return icon;
201    
202            /*
203             * Modern versions of Windows uses the voodoo value of 2 instead of 0
204             * for the small icons.
205             */
206            if (!large)
207            {
208                    if (!SendMessageTimeout(hwnd, WM_GETICON, 2,
209                                            0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) & icon))
210                            return NULL;
211            }
212    
213            if (icon)
214                    return icon;
215    
216            icon = (HICON) GetClassLong(hwnd, large ? GCL_HICON : GCL_HICONSM);
217    
218            if (icon)
219                    return icon;
220    
221            return NULL;
222    }
223    
224    static int
225    extract_icon(HICON icon, char *buffer, int maxlen)
226    {
227            ICONINFO info;
228            HDC hdc;
229            BITMAP mask_bmp, color_bmp;
230            BITMAPINFO bmi;
231            int size, i;
232            char *mask_buf, *color_buf;
233            char *o, *m, *c;
234            int ret = -1;
235    
236            assert(buffer);
237            assert(maxlen > 0);
238    
239            if (!GetIconInfo(icon, &info))
240                    goto fail;
241    
242            if (!GetObject(info.hbmMask, sizeof(BITMAP), &mask_bmp))
243                    goto free_bmps;
244            if (!GetObject(info.hbmColor, sizeof(BITMAP), &color_bmp))
245                    goto free_bmps;
246    
247            if (mask_bmp.bmWidth != color_bmp.bmWidth)
248                    goto free_bmps;
249            if (mask_bmp.bmHeight != color_bmp.bmHeight)
250                    goto free_bmps;
251    
252            if ((mask_bmp.bmWidth * mask_bmp.bmHeight * 4) > maxlen)
253                    goto free_bmps;
254    
255            size = (mask_bmp.bmWidth + 3) / 4 * 4;
256            size *= mask_bmp.bmHeight;
257            size *= 4;
258    
259            mask_buf = malloc(size);
260            if (!mask_buf)
261                    goto free_bmps;
262            color_buf = malloc(size);
263            if (!color_buf)
264                    goto free_mbuf;
265    
266            memset(&bmi, 0, sizeof(BITMAPINFO));
267    
268            bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
269            bmi.bmiHeader.biWidth = mask_bmp.bmWidth;
270            bmi.bmiHeader.biHeight = -mask_bmp.bmHeight;
271            bmi.bmiHeader.biPlanes = 1;
272            bmi.bmiHeader.biBitCount = 32;
273            bmi.bmiHeader.biCompression = BI_RGB;
274            bmi.bmiHeader.biSizeImage = size;
275    
276            hdc = CreateCompatibleDC(NULL);
277            if (!hdc)
278                    goto free_cbuf;
279    
280            if (!GetDIBits(hdc, info.hbmMask, 0, mask_bmp.bmHeight, mask_buf, &bmi, DIB_RGB_COLORS))
281                    goto del_dc;
282            if (!GetDIBits(hdc, info.hbmColor, 0, color_bmp.bmHeight, color_buf, &bmi, DIB_RGB_COLORS))
283                    goto del_dc;
284    
285            o = buffer;
286            m = mask_buf;
287            c = color_buf;
288            for (i = 0; i < size / 4; i++)
289            {
290                    o[0] = c[2];
291                    o[1] = c[1];
292                    o[2] = c[0];
293    
294                    o[3] = ((int) (unsigned char) m[0] + (unsigned char) m[1] +
295                            (unsigned char) m[2]) / 3;
296                    o[3] = 0xff - o[3];
297    
298                    o += 4;
299                    m += 4;
300                    c += 4;
301            }
302    
303            ret = size;
304    
305          del_dc:
306            DeleteDC(hdc);
307    
308          free_cbuf:
309            free(color_buf);
310          free_mbuf:
311            free(mask_buf);
312    
313          free_bmps:
314            DeleteObject(info.hbmMask);
315            DeleteObject(info.hbmColor);
316    
317          fail:
318            return ret;
319    }
320    
321    #define ICON_CHUNK 400
322    
323    static void
324    update_icon(HWND hwnd, HICON icon, int large)
325    {
326            int i, j, size, chunks;
327            char buf[32 * 32 * 4];
328            char asciibuf[ICON_CHUNK * 2 + 1];
329    
330            size = extract_icon(icon, buf, sizeof(buf));
331            if (size <= 0)
332                    return;
333    
334            if ((!large && size != 16 * 16 * 4) || (large && size != 32 * 32 * 4))
335            {
336                    debug("Unexpected icon size.");
337                    return;
338            }
339    
340            chunks = (size + ICON_CHUNK - 1) / ICON_CHUNK;
341            for (i = 0; i < chunks; i++)
342            {
343                    for (j = 0; j < ICON_CHUNK; j++)
344                    {
345                            if (i * ICON_CHUNK + j >= size)
346                                    break;
347                            sprintf(asciibuf + j * 2, "%02x",
348                                    (int) (unsigned char) buf[i * ICON_CHUNK + j]);
349                    }
350    
351                    vchannel_write("SETICON", "0x%08lx,%d,RGBA,%d,%d,%s", hwnd, i,
352                                   large ? 32 : 16, large ? 32 : 16, asciibuf);
353            }
354    }
355    
356  static LRESULT CALLBACK  static LRESULT CALLBACK
357  wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)  wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
358  {  {
359          HWND hwnd, parent;          HWND hwnd;
360          UINT msg;          UINT msg;
361          WPARAM wparam;          WPARAM wparam;
362          LPARAM lparam;          LPARAM lparam;
# Line 163  wndproc_hook_proc(int code, WPARAM cur_t Line 373  wndproc_hook_proc(int code, WPARAM cur_t
373    
374          style = GetWindowLong(hwnd, GWL_STYLE);          style = GetWindowLong(hwnd, GWL_STYLE);
375    
376          /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,          if (!is_toplevel(hwnd)) {
            but they exist nonetheless. */  
         if ((style & WS_CHILD) && !(style & WS_POPUP))  
377                  goto end;                  goto end;
   
         if (style & WS_POPUP)  
         {  
                 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);  
                 if (!parent)  
                         parent = (HWND) - 1;  
378          }          }
         else  
                 parent = NULL;  
379    
380          switch (msg)          switch (msg)
381          {          {
# Line 187  wndproc_hook_proc(int code, WPARAM cur_t Line 387  wndproc_hook_proc(int code, WPARAM cur_t
387                                  {                                  {
388                                          unsigned short title[150];                                          unsigned short title[150];
389                                          int state;                                          int state;
390                                            DWORD pid;
391                                          vchannel_write("CREATE", "0x%p,0x%p,0x%x", hwnd, parent, 0);                                          int flags;
392                                            HICON icon;
393    
394                                            GetWindowThreadProcessId(hwnd, &pid);
395    
396                                            flags = 0;
397                                            if (style & DS_MODALFRAME)
398                                                    flags |= SEAMLESS_CREATE_MODAL;
399    
400                                            vchannel_write("CREATE", "0x%08lx,0x%08lx,0x%08lx,0x%08x",
401                                                           (long) hwnd, (long) pid, (long) get_parent(hwnd),
402                                                           flags);
403    
404                                          GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));                                          GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
405    
406                                          vchannel_write("TITLE", "0x%x,%s,0x%x", hwnd,                                          vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
407                                                         vchannel_strfilter_unicode(title), 0);                                                         vchannel_strfilter_unicode(title), 0);
408    
409                                            icon = get_icon(hwnd, 1);
410                                            if (icon)
411                                            {
412                                                    update_icon(hwnd, icon, 1);
413                                                    DeleteObject(icon);
414                                            }
415    
416                                            icon = get_icon(hwnd, 0);
417                                            if (icon)
418                                            {
419                                                    update_icon(hwnd, icon, 0);
420                                                    DeleteObject(icon);
421                                            }
422    
423                                          if (style & WS_MAXIMIZE)                                          if (style & WS_MAXIMIZE)
424                                                  state = 2;                                                  state = 2;
425                                          else if (style & WS_MINIMIZE)                                          else if (style & WS_MINIMIZE)
# Line 204  wndproc_hook_proc(int code, WPARAM cur_t Line 429  wndproc_hook_proc(int code, WPARAM cur_t
429    
430                                          update_position(hwnd);                                          update_position(hwnd);
431    
432                                          vchannel_write("STATE", "0x%p,0x%x,0x%x", hwnd, state, 0);                                          vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x", hwnd,
433                                                           state, 0);
434                                  }                                  }
435    
436                                  if (wp->flags & SWP_HIDEWINDOW)                                  if (wp->flags & SWP_HIDEWINDOW)
437                                          vchannel_write("DESTROY", "0x%p,0x%x", hwnd, 0);                                          vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
438    
439                                  if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))                                  if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
440                                          break;                                          break;
# Line 219  wndproc_hook_proc(int code, WPARAM cur_t Line 445  wndproc_hook_proc(int code, WPARAM cur_t
445                                  break;                                  break;
446                          }                          }
447    
448                    case WM_SETICON:
449                            if (!(style & WS_VISIBLE))
450                                    break;
451    
452                            switch (wparam)
453                            {
454                                    case ICON_BIG:
455                                            if (lparam)
456                                                    update_icon(hwnd, (HICON) lparam, 1);
457                                            else
458                                                    vchannel_write("DELICON", "0x%08lx,RGBA,32,32",
459                                                                   hwnd);
460                                            break;
461                                    case ICON_SMALL:
462                                    case 2:
463                                            if (lparam)
464                                                    update_icon(hwnd, (HICON) lparam, 0);
465                                            else
466                                                    vchannel_write("DELICON", "0x%08lx,RGBA,16,16",
467                                                                   hwnd);
468                                            break;
469                                    default:
470                                            debug("Weird icon size %d", (int) wparam);
471                            }
472    
473                            break;
474    
475                  case WM_SIZE:                  case WM_SIZE:
476                          if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))                          if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
477                                  break;                                  break;
# Line 234  wndproc_hook_proc(int code, WPARAM cur_t Line 487  wndproc_hook_proc(int code, WPARAM cur_t
487                  case WM_DESTROY:                  case WM_DESTROY:
488                          if (!(style & WS_VISIBLE))                          if (!(style & WS_VISIBLE))
489                                  break;                                  break;
490                          vchannel_write("DESTROY", "0x%p,0x%x", hwnd, 0);                          vchannel_write("DESTROY", "0x%08lx,0x%08x", hwnd, 0);
491                          break;                          break;
492    
493                  default:                  default:
# Line 248  wndproc_hook_proc(int code, WPARAM cur_t Line 501  wndproc_hook_proc(int code, WPARAM cur_t
501  static LRESULT CALLBACK  static LRESULT CALLBACK
502  wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)  wndprocret_hook_proc(int code, WPARAM cur_thread, LPARAM details)
503  {  {
504          HWND hwnd, parent;          HWND hwnd;
505          UINT msg;          UINT msg;
506          WPARAM wparam;          WPARAM wparam;
507          LPARAM lparam;          LPARAM lparam;
# Line 265  wndprocret_hook_proc(int code, WPARAM cu Line 518  wndprocret_hook_proc(int code, WPARAM cu
518    
519          style = GetWindowLong(hwnd, GWL_STYLE);          style = GetWindowLong(hwnd, GWL_STYLE);
520    
521          /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,          if (!is_toplevel(hwnd)) {
            but they exist nonetheless. */  
         if ((style & WS_CHILD) && !(style & WS_POPUP))  
522                  goto end;                  goto end;
   
         if (style & WS_POPUP)  
         {  
                 parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);  
                 if (!parent)  
                         parent = (HWND) - 1;  
523          }          }
         else  
                 parent = NULL;  
524    
525          switch (msg)          switch (msg)
526          {          {
# Line 303  wndprocret_hook_proc(int code, WPARAM cu Line 546  wndprocret_hook_proc(int code, WPARAM cu
546                                  /* We cannot use the string in lparam because                                  /* We cannot use the string in lparam because
547                                     we need unicode. */                                     we need unicode. */
548                                  GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));                                  GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
549                                  vchannel_write("TITLE", "0x%p,%s,0x%x", hwnd,                                  vchannel_write("TITLE", "0x%08lx,%s,0x%08x", hwnd,
550                                                 vchannel_strfilter_unicode(title), 0);                                                 vchannel_strfilter_unicode(title), 0);
551                                  break;                                  break;
552                          }                          }
553    
554                    case WM_SETICON:
555                            {
556                                    HICON icon;
557    
558                                    /*
559                                     * Somehow, we never get WM_SETICON for the small icon.
560                                     * So trigger a read of it every time the large one is
561                                     * changed.
562                                     */
563                                    icon = get_icon(hwnd, 0);
564                                    if (icon)
565                                    {
566                                            update_icon(hwnd, icon, 0);
567                                            DeleteObject(icon);
568                                    }
569                            }
570    
571                  default:                  default:
572                          break;                          break;
573          }          }
574    
575          if (msg == g_wm_seamless_focus)          if (msg == g_wm_seamless_focus)
576          {          {
577                  /* FIXME: SetActiveWindow() kills menus. Need to find a clean                  /* FIXME: SetForegroundWindow() kills menus. Need to find a
578                     way to solve this. */                     clean way to solve this. */
579                  if ((GetActiveWindow() != hwnd) && !parent)                  if ((GetForegroundWindow() != hwnd) && !get_parent(hwnd))
580                          SetActiveWindow(hwnd);                          SetForegroundWindow(hwnd);
581    
582                  vchannel_write("ACK", "%u", g_blocked_focus_serial);                  vchannel_write("ACK", "%u", g_blocked_focus_serial);
583          }          }
# Line 337  cbt_hook_proc(int code, WPARAM wparam, L Line 597  cbt_hook_proc(int code, WPARAM wparam, L
597                  case HCBT_MINMAX:                  case HCBT_MINMAX:
598                          {                          {
599                                  int show, state, blocked;                                  int show, state, blocked;
600                                  HWND blocked_hwnd;                                  HWND hwnd, blocked_hwnd;
601                                  unsigned int serial;                                  unsigned int serial;
602                                    LONG style;
603    
604                                  WaitForSingleObject(g_mutex, INFINITE);                                  WaitForSingleObject(g_mutex, INFINITE);
605                                  blocked_hwnd = g_blocked_state_hwnd;                                  blocked_hwnd = g_blocked_state_hwnd;
# Line 346  cbt_hook_proc(int code, WPARAM wparam, L Line 607  cbt_hook_proc(int code, WPARAM wparam, L
607                                  blocked = g_blocked_state;                                  blocked = g_blocked_state;
608                                  ReleaseMutex(g_mutex);                                  ReleaseMutex(g_mutex);
609    
610                                    hwnd = (HWND) wparam;
611    
612                                    style = GetWindowLong(hwnd, GWL_STYLE);
613    
614                                    if (!(style & WS_VISIBLE))
615                                            break;
616    
617                                  show = LOWORD(lparam);                                  show = LOWORD(lparam);
618    
619                                  if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)                                  if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
# Line 361  cbt_hook_proc(int code, WPARAM wparam, L Line 629  cbt_hook_proc(int code, WPARAM wparam, L
629                                          break;                                          break;
630                                  }                                  }
631    
632                                  if ((blocked_hwnd == (HWND) wparam) && (blocked == state))                                  if ((blocked_hwnd == hwnd) && (blocked == state))
633                                          vchannel_write("ACK", "%u", serial);                                          vchannel_write("ACK", "%u", serial);
634                                  else                                  else
635                                          vchannel_write("STATE", "0x%p,0x%x,0x%x", (HWND) wparam,                                          vchannel_write("STATE", "0x%08lx,0x%08x,0x%08x",
636                                                         state, 0);                                                         hwnd, state, 0);
637    
638                                  break;                                  break;
639                          }                          }
# Line 553  DllMain(HINSTANCE hinstDLL, DWORD ul_rea Line 821  DllMain(HINSTANCE hinstDLL, DWORD ul_rea
821                          break;                          break;
822    
823                  case DLL_PROCESS_DETACH:                  case DLL_PROCESS_DETACH:
824                            vchannel_write("DESTROYGRP", "0x%08lx, 0x%08lx", GetCurrentProcessId(), 0);
825    
826                          WaitForSingleObject(g_mutex, INFINITE);                          WaitForSingleObject(g_mutex, INFINITE);
827                          --g_instance_count;                          --g_instance_count;
828                          ReleaseMutex(g_mutex);                          ReleaseMutex(g_mutex);

Legend:
Removed from v.1167  
changed lines
  Added in v.1439

  ViewVC Help
Powered by ViewVC 1.1.26