/[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 1069 by ossman_, Thu Mar 9 09:46:30 2006 UTC revision 1131 by ossman_, Wed Mar 15 12:15:23 2006 UTC
# Line 1  Line 1 
1  //  /* -*- c-basic-offset: 8 -*-
2  // Copyright (C) 2004-2005 Martin Wickett     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 (C) Peter Åstrand <astrand@cendio.se> 2005-2006
8       Copyright (C) Pierre Ossman <ossman@cendio.se> 2006
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    
 #include "hookdll.h"  
 #include <windows.h>  
 #include <winuser.h>  
25  #include <stdio.h>  #include <stdio.h>
26  #include <stdarg.h>  #include <stdarg.h>
27    
28  #include "wtsapi32.h"  #include <windows.h>
29  #include "cchannel.h"  #include <winuser.h>
30    
31    #include "../vchannel.h"
32    
33  #define DLL_EXPORT __declspec(dllexport)  #define DLL_EXPORT __declspec(dllexport)
34    
# Line 17  Line 36 
36  #pragma data_seg ( "SHAREDDATA" )  #pragma data_seg ( "SHAREDDATA" )
37    
38  // this is the total number of processes this dll is currently attached to  // this is the total number of processes this dll is currently attached to
39  int iInstanceCount = 0;  int g_instance_count = 0;
 HWND hWnd = 0;  
40    
41  #pragma data_seg ()  #pragma data_seg ()
42    
43  #pragma comment(linker, "/section:SHAREDDATA,rws")  #pragma comment(linker, "/section:SHAREDDATA,rws")
44    
45  #define snprintf _snprintf  static HHOOK g_cbt_hook = NULL;
46    static HHOOK g_wndproc_hook = NULL;
 HHOOK hCbtProc = 0;  
 HHOOK hShellProc = 0;  
 HHOOK hWndProc = 0;  
 HINSTANCE hInst = 0;  
 HANDLE m_vcHandle = 0;  
 HANDLE hMutex = 0;  
   
 void SendDebug( char *format, ... )  
 {  
     va_list argp;  
     char buf [ 256 ];  
   
     sprintf( buf, "DEBUG1," );  
   
     va_start( argp, format );  
     _vsnprintf( buf + sizeof( "DEBUG1," ) - 1,  
                sizeof( buf ) - sizeof( "DEBUG1," ) + 1, format, argp );  
     va_end( argp );  
   
     WriteToChannel( buf );  
 }  
47    
48    static HINSTANCE g_instance = NULL;
49    
50    static HANDLE g_mutex = NULL;
51    
52  BOOL APIENTRY DllMain( HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved )  static void
53    update_position(HWND hwnd)
54  {  {
55      switch ( ul_reason_for_call ) {          RECT rect;
     case DLL_PROCESS_ATTACH:  
         // remember our instance handle  
         hInst = hinstDLL;  
   
         hMutex = CreateMutex( NULL, FALSE, "Local\\Seamless" );  
         if (!hMutex)  
             return FALSE;  
   
         WaitForSingleObject( hMutex, INFINITE );  
         ++iInstanceCount;  
         ReleaseMutex( hMutex );  
   
         OpenVirtualChannel();  
   
         break;  
   
     case DLL_THREAD_ATTACH:  
         break;  
56    
57      case DLL_THREAD_DETACH:          if (!GetWindowRect(hwnd, &rect))
58          break;          {
59                    debug("GetWindowRect failed!\n");
60                    return;
61            }
62    
63      case DLL_PROCESS_DETACH:          vchannel_write("POSITION,0x%p,%d,%d,%d,%d,0x%x",
64          WaitForSingleObject( hMutex, INFINITE );                         hwnd,
65          --iInstanceCount;                         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
         ReleaseMutex( hMutex );  
   
         CloseVirtualChannel();  
   
         CloseHandle( hMutex );  
   
         break;  
     }  
   
     return TRUE;  
66  }  }
67    
68  LRESULT CALLBACK CallWndProc( int nCode, WPARAM wParam, LPARAM lParam )  static LRESULT CALLBACK
69    wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
70  {  {
71      char windowTitle[ 150 ] = { ""          HWND hwnd, parent;
72                                };          UINT msg;
73      HWND windowHandle = NULL;          WPARAM wparam;
74      HWND windowHandle2 = NULL;          LPARAM lparam;
     char result[ 255 ] = { ""  
                          };  
     CWPSTRUCT *details = ( CWPSTRUCT * ) lParam;  
     CREATESTRUCT *cs = ( CREATESTRUCT * ) details->lParam;  
     LONG dwStyle = GetWindowLong( details->hwnd, GWL_STYLE );  
     WINDOWPOS *wp = ( WINDOWPOS * ) details->lParam;  
     RECT rect;  
   
     if ( nCode < 0 ) {  
         return CallNextHookEx( hWndProc, nCode, wParam, lParam );  
     }  
75    
76      switch ( details->message ) {          LONG style;
77    
78      case WM_WINDOWPOSCHANGED:          if (code < 0)
79          if ( dwStyle & WS_CHILD)                  goto end;
             break;  
80    
81            hwnd = ((CWPSTRUCT *) details)->hwnd;
82            msg = ((CWPSTRUCT *) details)->message;
83            wparam = ((CWPSTRUCT *) details)->wParam;
84            lparam = ((CWPSTRUCT *) details)->lParam;
85    
86          if ( wp->flags & SWP_SHOWWINDOW ) {          style = GetWindowLong(hwnd, GWL_STYLE);
             // FIXME: Now, just like create!  
             SendDebug("SWP_SHOWWINDOW for %p!", details->hwnd);  
             WriteToChannel( "CREATE1,0x%p,0x%x", details->hwnd, 0 );  
87    
88              // FIXME: SETSTATE          /* Docs say that WS_CHILD and WS_POPUP is an illegal combination,
89               but they exist nonetheless. */
90            if ((style & WS_CHILD) && !(style & WS_POPUP))
91                    goto end;
92    
93              if ( !GetWindowRect( details->hwnd, &rect ) ) {          if (style & WS_POPUP)
94                  SendDebug( "GetWindowRect failed!\n" );          {
95                  break;                  parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
96              }                  if (!parent)
97              WriteToChannel( "POSITION1,0x%p,%d,%d,%d,%d,0x%x",                          parent = (HWND) - 1;
98                              details->hwnd,          }
99                              rect.left, rect.top,          else
100                              rect.right - rect.left,                  parent = NULL;
                             rect.bottom - rect.top,  
                             0 );  
         }  
101    
102            switch (msg)
103            {
104    
105          if ( wp->flags & SWP_HIDEWINDOW )                  case WM_WINDOWPOSCHANGED:
106              WriteToChannel( "DESTROY1,0x%p,0x%x", details->hwnd, 0 );                          {
107                                    WINDOWPOS *wp = (WINDOWPOS *) lparam;
108    
109                                    if (wp->flags & SWP_SHOWWINDOW)
110                                    {
111                                            char title[150];
112                                            int state;
113    
114          if ( !( dwStyle & WS_VISIBLE ) )                                          vchannel_write("CREATE,0x%p,0x%p,0x%x", hwnd, parent, 0);
             break;  
115    
116          if ( wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE )                                          GetWindowText(hwnd, title, sizeof(title));
             break;  
117    
118          if ( !GetWindowRect( details->hwnd, &rect ) ) {                                          vchannel_write("TITLE,0x%x,%s,0x%x", hwnd,
119              SendDebug( "GetWindowRect failed!\n" );                                                         vchannel_strfilter(title), 0);
             break;  
         }  
120    
121          WriteToChannel( "POSITION1,0x%p,%d,%d,%d,%d,0x%x",                                          if (style & WS_MAXIMIZE)
122                          details->hwnd,                                                  state = 2;
123                          rect.left, rect.top,                                          else if (style & WS_MINIMIZE)
124                          rect.right - rect.left,                                                  state = 1;
125                          rect.bottom - rect.top,                                          else
126                          0 );                                                  state = 0;
127    
128          break;                                          update_position(hwnd);
129    
130                                            vchannel_write("STATE,0x%p,0x%x,0x%x", hwnd, state, 0);
131                                    }
132    
133          /* Note: WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED are                                  if (wp->flags & SWP_HIDEWINDOW)
134          strange. Sometimes, for example when bringing up the                                          vchannel_write("DESTROY,0x%p,0x%x", hwnd, 0);
         Notepad About dialog, only an WM_WINDOWPOSCHANGING is  
         sent. In some other cases, for exmaple when opening  
         Format->Text in Notepad, both events are sent. Also, for  
         some reason, when closing the Notepad About dialog, an  
         WM_WINDOWPOSCHANGING event is sent which looks just like  
         the event that was sent when the About dialog was opened...  */  
     case WM_WINDOWPOSCHANGING:  
         if ( dwStyle & WS_CHILD)  
             break;  
135    
136          if ( !( dwStyle & WS_VISIBLE ) )                                  if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
137              break;                                          break;
138    
139          if ( !( wp->flags & SWP_NOZORDER ) )                                  if (!(wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE))
140              WriteToChannel( "ZCHANGE1,0x%p,0x%p,0x%x",                                          update_position(hwnd);
                             details->hwnd,  
                             wp->flags & SWP_NOACTIVATE ? wp->hwndInsertAfter : 0,  
                             0 );  
141    
142          break;                                  if (!(wp->flags & SWP_NOZORDER))
143                                    {
144                                            vchannel_write("ZCHANGE,0x%p,0x%p,0x%x",
145                                                           hwnd,
146                                                           wp->flags & SWP_NOACTIVATE ? wp->
147                                                           hwndInsertAfter : 0, 0);
148                                    }
149    
150                                    break;
151                            }
152    
153                    case WM_SIZE:
154                            if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
155                                    break;
156                            update_position(hwnd);
157                            break;
158    
159                    case WM_MOVE:
160                            if (!(style & WS_VISIBLE) || (style & WS_MINIMIZE))
161                                    break;
162                            update_position(hwnd);
163                            break;
164    
165      case WM_DESTROY:                  case WM_SETTEXT:
166          if ( dwStyle & WS_CHILD)                          {
167              break;                                  char *title;
168                                    if (!(style & WS_VISIBLE))
169                                            break;
170                                    title = _strdup((char *) lparam);
171                                    vchannel_write("TITLE,0x%p,%s,0x%x", hwnd,
172                                                   vchannel_strfilter(title), 0);
173                                    free(title);
174                                    break;
175                            }
176    
177          WriteToChannel( "DESTROY1,0x%p,0x%x", details->hwnd, 0 );                  case WM_DESTROY:
178                            if (!(style & WS_VISIBLE))
179                                    break;
180                            vchannel_write("DESTROY,0x%p,0x%x", hwnd, 0);
181                            break;
182    
183          break;                  default:
184                            break;
185            }
186    
187          end:
188      default:          return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
         break;  
     }  
   
     return CallNextHookEx( hWndProc, nCode, wParam, lParam );  
189  }  }
190    
191  LRESULT CALLBACK CbtProc( int nCode, WPARAM wParam, LPARAM lParam )  static LRESULT CALLBACK
192    cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
193  {  {
194      char windowTitle[ 150 ] = { ""          if (code < 0)
195                                };                  goto end;
     HWND windowHandle = NULL;  
     char result[ 255 ] = { ""  
                          };  
   
         if ( nCode < 0 ) {  
         return CallNextHookEx( hCbtProc, nCode, wParam, lParam );  
     }  
   
         switch ( nCode ) {  
     case HCBT_MINMAX:  
   
         if ( ( LOWORD( lParam ) == SW_SHOWMINIMIZED )  
                 || ( LOWORD( lParam ) == SW_MINIMIZE ) ) {  
             MessageBox( 0, "Minimizing windows is not allowed in this version. Sorry!", "SeamlessRDP", MB_OK );  
             return 1;  
         }  
   
         GetWindowText( ( HWND ) wParam, windowTitle, 150 );  
196    
197          WriteToChannel( "SETSTATE1,0x%p,%s,0x%x,0x%x",          switch (code)
198                          ( HWND ) wParam,          {
199                          windowTitle,                  case HCBT_MINMAX:
200                          LOWORD( lParam ),                          {
201                          0 );                                  int show, state;
         break;  
202    
203                                    show = LOWORD(lparam);
204    
205      default:                                  if ((show == SW_NORMAL) || (show == SW_SHOWNORMAL)
206          break;                                      || (show == SW_RESTORE))
207      }                                          state = 0;
208                                    else if ((show == SW_MINIMIZE) || (show == SW_SHOWMINIMIZED))
209                                            state = 1;
210                                    else if ((show == SW_MAXIMIZE) || (show == SW_SHOWMAXIMIZED))
211                                            state = 2;
212                                    else
213                                    {
214                                            debug("Unexpected show: %d", show);
215                                            break;
216                                    }
217                                    vchannel_write("STATE,0x%p,0x%x,0x%x", (HWND) wparam, state, 0);
218                                    break;
219                            }
220    
221                    default:
222                            break;
223            }
224    
225          end:
226      return CallNextHookEx( hCbtProc, nCode, wParam, lParam );          return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
227  }  }
228    
229    DLL_EXPORT void
230  LRESULT CALLBACK ShellProc( int nCode, WPARAM wParam, LPARAM lParam )  SetHooks(void)
231  {  {
232      char windowTitle[ 150 ] = { ""          if (!g_cbt_hook)
233                                };                  g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
     HWND windowHandle = NULL;  
     char result[ 255 ] = { ""  
                          };  
     char strWindowId[ 25 ];  
     LONG b, t, l, r;  
     char strW[ 5 ];  
     char strY[ 5 ];  
     char strX[ 5 ];  
     char strH[ 5 ];  
     RECT rect;  
   
     if ( nCode < 0 ) {  
         return CallNextHookEx( hShellProc, nCode, wParam, lParam );  
     }  
   
     switch ( nCode ) {  
     case HSHELL_WINDOWCREATED:  
   
         //get window id  
         windowHandle = ( HWND ) wParam;  
         itoa( ( int ) windowHandle, strWindowId, 10 );  
   
         //get coords  
         GetWindowRect( windowHandle, &rect );  
         b = rect.bottom;  
         t = rect.top;  
         l = rect.left;  
         r = rect.right;  
         ltoa( b - t, strH, 10 );  
         ltoa( t, strY, 10 );  
         ltoa( r - l, strW, 10 );  
         ltoa( l, strX, 10 );  
   
         //get name  
         GetWindowText( windowHandle, windowTitle, 150 );  
   
         ////setup return string  
         strcat( result, "MSG=HSHELL_WINDOWCREATED;OP=0;" );  
         strcat( result, "ID=" );  
         strcat( result, strWindowId );  
         strcat( result, ";" );  
         strcat( result, "TITLE=" );  
         strcat( result, windowTitle );  
         strcat( result, ";" );  
         strcat( result, "X=" );  
         strcat( result, strX );  
         strcat( result, ";" );  
         strcat( result, "Y=" );  
         strcat( result, strY );  
         strcat( result, ";" );  
         strcat( result, "H=" );  
         strcat( result, strH );  
         strcat( result, ";" );  
         strcat( result, "W=" );  
         strcat( result, strW );  
         strcat( result, "." );  
         WriteToChannel( result );  
         break;  
   
     case HSHELL_WINDOWDESTROYED:  
   
         //get window id  
         windowHandle = ( HWND ) wParam;  
         itoa( ( int ) windowHandle, strWindowId, 10 );  
   
         //get coords  
         GetWindowRect( windowHandle, &rect );  
         b = rect.bottom;  
         t = rect.top;  
         l = rect.left;  
         r = rect.right;  
         ltoa( b - t, strH, 10 );  
         ltoa( t, strY, 10 );  
         ltoa( r - l, strW, 10 );  
         ltoa( l, strX, 10 );  
   
         //get name  
         GetWindowText( windowHandle, windowTitle, 150 );  
   
         ////setup return string  
         strcat( result, "MSG=HSHELL_WINDOWDESTROYED;OP=1;" );  
         strcat( result, "ID=" );  
         strcat( result, strWindowId );  
         strcat( result, ";" );  
         strcat( result, "TITLE=" );  
         strcat( result, windowTitle );  
         strcat( result, ";" );  
         strcat( result, "X=" );  
         strcat( result, strX );  
         strcat( result, ";" );  
         strcat( result, "Y=" );  
         strcat( result, strY );  
         strcat( result, ";" );  
         strcat( result, "H=" );  
         strcat( result, strH );  
         strcat( result, ";" );  
         strcat( result, "W=" );  
         strcat( result, strW );  
         strcat( result, "." );  
         WriteToChannel( result );  
         break;  
   
   
     default:  
         break;  
     }  
   
234    
235      return CallNextHookEx( hShellProc, nCode, wParam, lParam );          if (!g_wndproc_hook)
236                    g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
237  }  }
238    
239  DLL_EXPORT void SetHooks( void )  DLL_EXPORT void
240    RemoveHooks(void)
241  {  {
242      if ( !hCbtProc ) {          if (g_cbt_hook)
243          hCbtProc = SetWindowsHookEx( WH_CBT, ( HOOKPROC ) CbtProc, hInst, ( DWORD ) NULL );                  UnhookWindowsHookEx(g_cbt_hook);
     }  
   
 #if 0  
     if ( !hShellProc ) {  
         hShellProc = SetWindowsHookEx( WH_SHELL, ( HOOKPROC ) ShellProc, hInst, ( DWORD ) NULL );  
     }  
 #endif  
   
     if ( !hWndProc ) {  
         hWndProc = SetWindowsHookEx( WH_CALLWNDPROC, ( HOOKPROC ) CallWndProc, hInst, ( DWORD ) NULL );  
     }  
 }  
244    
245  DLL_EXPORT void RemoveHooks( void )          if (g_wndproc_hook)
246  {                  UnhookWindowsHookEx(g_wndproc_hook);
     if ( hCbtProc ) {  
         UnhookWindowsHookEx( hCbtProc );  
     }  
   
     if ( hShellProc ) {  
         UnhookWindowsHookEx( hShellProc );  
     }  
   
     if ( hWndProc ) {  
         UnhookWindowsHookEx( hWndProc );  
     }  
247  }  }
248    
249  DLL_EXPORT int GetInstanceCount()  DLL_EXPORT int
250    GetInstanceCount()
251  {  {
252      return iInstanceCount;          return g_instance_count;
253  }  }
254    
255  int OpenVirtualChannel()  BOOL APIENTRY
256    DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
257  {  {
258      m_vcHandle = WTSVirtualChannelOpen( WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, CHANNELNAME );          switch (ul_reason_for_call)
259            {
260                    case DLL_PROCESS_ATTACH:
261                            // remember our instance handle
262                            g_instance = hinstDLL;
263    
264      if ( m_vcHandle == NULL ) {                          g_mutex = CreateMutex(NULL, FALSE, "Local\\SeamlessDLL");
265          return 0;                          if (!g_mutex)
266      } else {                                  return FALSE;
         return 1;  
     }  
 }  
267    
268  int CloseVirtualChannel()                          WaitForSingleObject(g_mutex, INFINITE);
269  {                          ++g_instance_count;
270      BOOL result = WTSVirtualChannelClose( m_vcHandle );                          ReleaseMutex(g_mutex);
271    
272      m_vcHandle = NULL;                          vchannel_open();
273    
274      if ( result ) {                          break;
         return 1;  
     } else {  
         return 0;  
     }  
 }  
275    
276  int ChannelIsOpen()                  case DLL_THREAD_ATTACH:
277  {                          break;
     if ( m_vcHandle == NULL ) {  
         return 0;  
     } else {  
         return 1;  
     }  
 }  
278    
279  int WriteToChannel( char *format, ... )                  case DLL_THREAD_DETACH:
280  {                          break;
281      BOOL result;  
282      va_list argp;                  case DLL_PROCESS_DETACH:
283      char buf [ 1024 ];                          WaitForSingleObject(g_mutex, INFINITE);
284      int size;                          --g_instance_count;
285      PULONG bytesRead = 0;                          ReleaseMutex(g_mutex);
286      PULONG pBytesWritten = 0;  
287                            vchannel_close();
288      if ( !ChannelIsOpen() )  
289          return 1;                          CloseHandle(g_mutex);
290    
291      va_start( argp, format );                          break;
292      size = _vsnprintf( buf, sizeof( buf ), format, argp );          }
293      va_end( argp );  
294            return TRUE;
     if ( size >= sizeof( buf ) )  
         return 0;  
   
     WaitForSingleObject( hMutex, INFINITE );  
     result = WTSVirtualChannelWrite( m_vcHandle, buf, ( ULONG ) strlen( buf ), pBytesWritten );  
     result = WTSVirtualChannelWrite( m_vcHandle, "\n", ( ULONG ) 1, pBytesWritten );  
     ReleaseMutex( hMutex );  
   
     if ( result ) {  
         return 1;  
     } else {  
         return 0;  
     }  
295  }  }

Legend:
Removed from v.1069  
changed lines
  Added in v.1131

  ViewVC Help
Powered by ViewVC 1.1.26