/[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 1071 by ossman_, Thu Mar 9 12:00:15 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    #include <wtsapi32.h>
31    #include <cchannel.h>
32    
33    #include "hookdll.h"
34    
35  #define DLL_EXPORT __declspec(dllexport)  #define DLL_EXPORT __declspec(dllexport)
36    
# Line 17  Line 38 
38  #pragma data_seg ( "SHAREDDATA" )  #pragma data_seg ( "SHAREDDATA" )
39    
40  // 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
41  int iInstanceCount = 0;  int g_instance_count = 0;
 HWND hWnd = 0;  
42    
43  #pragma data_seg ()  #pragma data_seg ()
44    
45  #pragma comment(linker, "/section:SHAREDDATA,rws")  #pragma comment(linker, "/section:SHAREDDATA,rws")
46    
47  #define snprintf _snprintf  static HHOOK g_cbt_hook = NULL;
48    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;  
49    
50  void SendDebug( char *format, ... )  static HINSTANCE g_instance = NULL;
 {  
     va_list argp;  
     char buf [ 256 ];  
51    
52      sprintf( buf, "DEBUG1," );  static HANDLE g_mutex = NULL;
53    
54      va_start( argp, format );  static HANDLE g_vchannel = NULL;
     _vsnprintf( buf + sizeof( "DEBUG1," ) - 1,  
                sizeof( buf ) - sizeof( "DEBUG1," ) + 1, format, argp );  
     va_end( argp );  
   
     WriteToChannel( buf );  
 }  
55    
56    static void
57    debug(char *format, ...)
 BOOL APIENTRY DllMain( HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved )  
58  {  {
59      switch ( ul_reason_for_call ) {          va_list argp;
60      case DLL_PROCESS_ATTACH:          char buf[256];
         // 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;  
   
     case DLL_THREAD_DETACH:  
         break;  
   
     case DLL_PROCESS_DETACH:  
         WaitForSingleObject( hMutex, INFINITE );  
         --iInstanceCount;  
         ReleaseMutex( hMutex );  
   
         CloseVirtualChannel();  
61    
62          CloseHandle( hMutex );          sprintf(buf, "DEBUG1,");
63    
64          break;          va_start(argp, format);
65      }          _vsnprintf(buf + sizeof("DEBUG1,") - 1, sizeof(buf) - sizeof("DEBUG1,") + 1, format, argp);
66            va_end(argp);
67    
68      return TRUE;          vchannel_write(buf);
69  }  }
70    
71  LRESULT CALLBACK CallWndProc( int nCode, WPARAM wParam, LPARAM lParam )  static LRESULT CALLBACK
72    wndproc_hook_proc(int code, WPARAM cur_thread, LPARAM details)
73  {  {
74      char windowTitle[ 150 ] = { ""          HWND hwnd = ((CWPSTRUCT *) details)->hwnd;
75                                };          UINT msg = ((CWPSTRUCT *) details)->message;
76      HWND windowHandle = NULL;          WPARAM wparam = ((CWPSTRUCT *) details)->wParam;
77      HWND windowHandle2 = NULL;          LPARAM lparam = ((CWPSTRUCT *) details)->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;  
78    
79      if ( nCode < 0 ) {          LONG style = GetWindowLong(hwnd, GWL_STYLE);
80          return CallNextHookEx( hWndProc, nCode, wParam, lParam );          WINDOWPOS *wp = (WINDOWPOS *) lparam;
81      }          RECT rect;
82    
83      switch ( details->message ) {          if (code < 0)
84                    goto end;
85    
86      case WM_WINDOWPOSCHANGED:          switch (msg)
87          if ( dwStyle & WS_CHILD)          {
             break;  
88    
89                    case WM_WINDOWPOSCHANGED:
90                            if (style & WS_CHILD)
91                                    break;
92    
         if ( wp->flags & SWP_SHOWWINDOW ) {  
             // FIXME: Now, just like create!  
             SendDebug("SWP_SHOWWINDOW for %p!", details->hwnd);  
             WriteToChannel( "CREATE1,0x%p,0x%x", details->hwnd, 0 );  
93    
94              // FIXME: SETSTATE                          if (wp->flags & SWP_SHOWWINDOW)
95                            {
96                                    // FIXME: Now, just like create!
97                                    debug("SWP_SHOWWINDOW for %p!", hwnd);
98                                    vchannel_write("CREATE1,0x%p,0x%x", hwnd, 0);
99    
100              if ( !GetWindowRect( details->hwnd, &rect ) ) {                                  // FIXME: SETSTATE
                 SendDebug( "GetWindowRect failed!\n" );  
                 break;  
             }  
             WriteToChannel( "POSITION1,0x%p,%d,%d,%d,%d,0x%x",  
                             details->hwnd,  
                             rect.left, rect.top,  
                             rect.right - rect.left,  
                             rect.bottom - rect.top,  
                             0 );  
         }  
101    
102                                    if (!GetWindowRect(hwnd, &rect))
103                                    {
104                                            debug("GetWindowRect failed!\n");
105                                            break;
106                                    }
107                                    vchannel_write("POSITION1,0x%p,%d,%d,%d,%d,0x%x",
108                                                   hwnd,
109                                                   rect.left, rect.top,
110                                                   rect.right - rect.left, rect.bottom - rect.top, 0);
111                            }
112    
         if ( wp->flags & SWP_HIDEWINDOW )  
             WriteToChannel( "DESTROY1,0x%p,0x%x", details->hwnd, 0 );  
113    
114                            if (wp->flags & SWP_HIDEWINDOW)
115                                    vchannel_write("DESTROY1,0x%p,0x%x", hwnd, 0);
116    
         if ( !( dwStyle & WS_VISIBLE ) )  
             break;  
117    
118          if ( wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE )                          if (!(style & WS_VISIBLE))
119              break;                                  break;
120    
121          if ( !GetWindowRect( details->hwnd, &rect ) ) {                          if (wp->flags & SWP_NOMOVE && wp->flags & SWP_NOSIZE)
122              SendDebug( "GetWindowRect failed!\n" );                                  break;
             break;  
         }  
123    
124          WriteToChannel( "POSITION1,0x%p,%d,%d,%d,%d,0x%x",                          if (!GetWindowRect(hwnd, &rect))
125                          details->hwnd,                          {
126                          rect.left, rect.top,                                  debug("GetWindowRect failed!\n");
127                          rect.right - rect.left,                                  break;
128                          rect.bottom - rect.top,                          }
                         0 );  
129    
130          break;                          vchannel_write("POSITION1,0x%p,%d,%d,%d,%d,0x%x",
131                                           hwnd,
132                                           rect.left, rect.top,
133                                           rect.right - rect.left, rect.bottom - rect.top, 0);
134    
135                            break;
136    
         /* Note: WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED are  
         strange. Sometimes, for example when bringing up the  
         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;  
137    
138          if ( !( dwStyle & WS_VISIBLE ) )                          /* Note: WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED are
139              break;                             strange. Sometimes, for example when bringing up the
140                               Notepad About dialog, only an WM_WINDOWPOSCHANGING is
141                               sent. In some other cases, for exmaple when opening
142                               Format->Text in Notepad, both events are sent. Also, for
143                               some reason, when closing the Notepad About dialog, an
144                               WM_WINDOWPOSCHANGING event is sent which looks just like
145                               the event that was sent when the About dialog was opened...  */
146                    case WM_WINDOWPOSCHANGING:
147                            if (style & WS_CHILD)
148                                    break;
149    
150          if ( !( wp->flags & SWP_NOZORDER ) )                          if (!(style & WS_VISIBLE))
151              WriteToChannel( "ZCHANGE1,0x%p,0x%p,0x%x",                                  break;
                             details->hwnd,  
                             wp->flags & SWP_NOACTIVATE ? wp->hwndInsertAfter : 0,  
                             0 );  
152    
153          break;                          if (!(wp->flags & SWP_NOZORDER))
154                                    vchannel_write("ZCHANGE1,0x%p,0x%p,0x%x",
155                                                   hwnd,
156                                                   wp->flags & SWP_NOACTIVATE ? wp->hwndInsertAfter : 0,
157                                                   0);
158    
159                            break;
160    
161    
162    
     case WM_DESTROY:  
         if ( dwStyle & WS_CHILD)  
             break;  
163    
164          WriteToChannel( "DESTROY1,0x%p,0x%x", details->hwnd, 0 );                  case WM_DESTROY:
165                            if (style & WS_CHILD)
166                                    break;
167    
168          break;                          vchannel_write("DESTROY1,0x%p,0x%x", hwnd, 0);
169    
170                            break;
171    
     default:  
         break;  
     }  
172    
173      return CallNextHookEx( hWndProc, nCode, wParam, lParam );                  default:
174                            break;
175            }
176    
177          end:
178            return CallNextHookEx(g_wndproc_hook, code, cur_thread, details);
179  }  }
180    
181  LRESULT CALLBACK CbtProc( int nCode, WPARAM wParam, LPARAM lParam )  static LRESULT CALLBACK
182    cbt_hook_proc(int code, WPARAM wparam, LPARAM lparam)
183  {  {
184      char windowTitle[ 150 ] = { ""          char title[150];
                               };  
     HWND windowHandle = NULL;  
     char result[ 255 ] = { ""  
                          };  
   
         if ( nCode < 0 ) {  
         return CallNextHookEx( hCbtProc, nCode, wParam, lParam );  
     }  
185    
186          switch ( nCode ) {          if (code < 0)
187      case HCBT_MINMAX:                  goto end;
188    
189          if ( ( LOWORD( lParam ) == SW_SHOWMINIMIZED )          switch (code)
190                  || ( LOWORD( lParam ) == SW_MINIMIZE ) ) {          {
191              MessageBox( 0, "Minimizing windows is not allowed in this version. Sorry!", "SeamlessRDP", MB_OK );                  case HCBT_MINMAX:
192              return 1;                          {
193          }                                  int show;
194    
195          GetWindowText( ( HWND ) wParam, windowTitle, 150 );                                  show = LOWORD(lparam);
196    
197          WriteToChannel( "SETSTATE1,0x%p,%s,0x%x,0x%x",                                  if ((show == SW_SHOWMINIMIZED) || (show == SW_MINIMIZE))
198                          ( HWND ) wParam,                                  {
199                          windowTitle,                                          MessageBox(0,
200                          LOWORD( lParam ),                                                     "Minimizing windows is not allowed in this version. Sorry!",
201                          0 );                                                     "SeamlessRDP", MB_OK);
202          break;                                          return 1;
203                                    }
204    
205                                    GetWindowText((HWND) wparam, title, sizeof(title));
206    
207      default:                                  /* FIXME: Strip title of dangerous characters */
         break;  
     }  
208    
209                                    vchannel_write("SETSTATE1,0x%p,%s,0x%x,0x%x",
210                                                   (HWND) wparam, title, show, 0);
211                                    break;
212                            }
213    
214                    default:
215                            break;
216            }
217    
218      return CallNextHookEx( hCbtProc, nCode, wParam, lParam );        end:
219            return CallNextHookEx(g_cbt_hook, code, wparam, lparam);
220  }  }
221    
222    int
223  LRESULT CALLBACK ShellProc( int nCode, WPARAM wParam, LPARAM lParam )  vchannel_open()
224  {  {
225      char windowTitle[ 150 ] = { ""          g_vchannel = WTSVirtualChannelOpen(WTS_CURRENT_SERVER_HANDLE,
226                                };                                             WTS_CURRENT_SESSION, CHANNELNAME);
     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:  
227    
228          //get window id          if (g_vchannel == NULL)
229          windowHandle = ( HWND ) wParam;                  return 0;
230          itoa( ( int ) windowHandle, strWindowId, 10 );          else
231                    return 1;
232          //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 );  
233    
234          //get name  int
235          GetWindowText( windowHandle, windowTitle, 150 );  vchannel_close()
236    {
237            BOOL result;
238    
239          ////setup return string          result = WTSVirtualChannelClose(g_vchannel);
         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;  
240    
241      case HSHELL_WINDOWDESTROYED:          g_vchannel = NULL;
242    
243          //get window id          if (result)
244          windowHandle = ( HWND ) wParam;                  return 1;
245          itoa( ( int ) windowHandle, strWindowId, 10 );          else
246                    return 0;
247    }
248    
249          //get coords  int
250          GetWindowRect( windowHandle, &rect );  vchannel_is_open()
251          b = rect.bottom;  {
252          t = rect.top;          if (g_vchannel == NULL)
253          l = rect.left;                  return 0;
254          r = rect.right;          else
255          ltoa( b - t, strH, 10 );                  return 1;
256          ltoa( t, strY, 10 );  }
         ltoa( r - l, strW, 10 );  
         ltoa( l, strX, 10 );  
257    
258          //get name  int
259          GetWindowText( windowHandle, windowTitle, 150 );  vchannel_write(char *format, ...)
260    {
261            BOOL result;
262            va_list argp;
263            char buf[1024];
264            int size;
265            ULONG bytes_written;
266    
267          ////setup return string          if (!vchannel_is_open())
268          strcat( result, "MSG=HSHELL_WINDOWDESTROYED;OP=1;" );                  return 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;  
269    
270            va_start(argp, format);
271            size = _vsnprintf(buf, sizeof(buf), format, argp);
272            va_end(argp);
273    
274      default:          if (size >= sizeof(buf))
275          break;                  return 0;
     }  
276    
277            WaitForSingleObject(g_mutex, INFINITE);
278            result = WTSVirtualChannelWrite(g_vchannel, buf, (ULONG) strlen(buf), &bytes_written);
279            result = WTSVirtualChannelWrite(g_vchannel, "\n", (ULONG) 1, &bytes_written);
280            ReleaseMutex(g_mutex);
281    
282      return CallNextHookEx( hShellProc, nCode, wParam, lParam );          if (result)
283                    return 1;
284            else
285                    return 0;
286  }  }
287    
288  DLL_EXPORT void SetHooks( void )  DLL_EXPORT void
289    SetHooks(void)
290  {  {
291      if ( !hCbtProc ) {          if (!g_cbt_hook)
292          hCbtProc = SetWindowsHookEx( WH_CBT, ( HOOKPROC ) CbtProc, hInst, ( DWORD ) NULL );                  g_cbt_hook = SetWindowsHookEx(WH_CBT, cbt_hook_proc, g_instance, 0);
     }  
   
 #if 0  
     if ( !hShellProc ) {  
         hShellProc = SetWindowsHookEx( WH_SHELL, ( HOOKPROC ) ShellProc, hInst, ( DWORD ) NULL );  
     }  
 #endif  
293    
294      if ( !hWndProc ) {          if (!g_wndproc_hook)
295          hWndProc = SetWindowsHookEx( WH_CALLWNDPROC, ( HOOKPROC ) CallWndProc, hInst, ( DWORD ) NULL );                  g_wndproc_hook = SetWindowsHookEx(WH_CALLWNDPROC, wndproc_hook_proc, g_instance, 0);
     }  
296  }  }
297    
298  DLL_EXPORT void RemoveHooks( void )  DLL_EXPORT void
299    RemoveHooks(void)
300  {  {
301      if ( hCbtProc ) {          if (g_cbt_hook)
302          UnhookWindowsHookEx( hCbtProc );                  UnhookWindowsHookEx(g_cbt_hook);
     }  
303    
304      if ( hShellProc ) {          if (g_wndproc_hook)
305          UnhookWindowsHookEx( hShellProc );                  UnhookWindowsHookEx(g_wndproc_hook);
     }  
   
     if ( hWndProc ) {  
         UnhookWindowsHookEx( hWndProc );  
     }  
306  }  }
307    
308  DLL_EXPORT int GetInstanceCount()  DLL_EXPORT int
309    GetInstanceCount()
310  {  {
311      return iInstanceCount;          return g_instance_count;
312  }  }
313    
314  int OpenVirtualChannel()  BOOL APIENTRY
315    DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved)
316  {  {
317      m_vcHandle = WTSVirtualChannelOpen( WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, CHANNELNAME );          switch (ul_reason_for_call)
318            {
319                    case DLL_PROCESS_ATTACH:
320                            // remember our instance handle
321                            g_instance = hinstDLL;
322    
323      if ( m_vcHandle == NULL ) {                          g_mutex = CreateMutex(NULL, FALSE, "Local\\Seamless");
324          return 0;                          if (!g_mutex)
325      } else {                                  return FALSE;
         return 1;  
     }  
 }  
326    
327  int CloseVirtualChannel()                          WaitForSingleObject(g_mutex, INFINITE);
328  {                          ++g_instance_count;
329      BOOL result = WTSVirtualChannelClose( m_vcHandle );                          ReleaseMutex(g_mutex);
330    
331      m_vcHandle = NULL;                          vchannel_open();
332    
333      if ( result ) {                          break;
         return 1;  
     } else {  
         return 0;  
     }  
 }  
334    
335  int ChannelIsOpen()                  case DLL_THREAD_ATTACH:
336  {                          break;
     if ( m_vcHandle == NULL ) {  
         return 0;  
     } else {  
         return 1;  
     }  
 }  
337    
338  int WriteToChannel( char *format, ... )                  case DLL_THREAD_DETACH:
339  {                          break;
     BOOL result;  
     va_list argp;  
     char buf [ 1024 ];  
     int size;  
     PULONG bytesRead = 0;  
     PULONG pBytesWritten = 0;  
340    
341      if ( !ChannelIsOpen() )                  case DLL_PROCESS_DETACH:
342          return 1;                          WaitForSingleObject(g_mutex, INFINITE);
343                            --g_instance_count;
344                            ReleaseMutex(g_mutex);
345    
346      va_start( argp, format );                          vchannel_close();
     size = _vsnprintf( buf, sizeof( buf ), format, argp );  
     va_end( argp );  
347    
348      if ( size >= sizeof( buf ) )                          CloseHandle(g_mutex);
         return 0;  
349    
350      WaitForSingleObject( hMutex, INFINITE );                          break;
351      result = WTSVirtualChannelWrite( m_vcHandle, buf, ( ULONG ) strlen( buf ), pBytesWritten );          }
     result = WTSVirtualChannelWrite( m_vcHandle, "\n", ( ULONG ) 1, pBytesWritten );  
     ReleaseMutex( hMutex );  
352    
353      if ( result ) {          return TRUE;
         return 1;  
     } else {  
         return 0;  
     }  
354  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26