/[rdesktop]/sourceforge.net/trunk/seamlessrdp/ServerExe/main.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/main.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 1163 by ossman_, Mon Mar 20 10:31:58 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 executable
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    
25  #include <windows.h>  #include <windows.h>
26  #include <stdio.h>  #include <stdio.h>
27    #include <wtsapi32.h>
28    #include <cchannel.h>
29    
30    #include "vchannel.h"
31    
32  #include "resource.h"  #include "resource.h"
33    
34  #define snprintf _snprintf  #define APP_NAME "SeamlessRDP Shell"
35    
36    #ifndef WM_WTSSESSION_CHANGE
37    #define WM_WTSSESSION_CHANGE 0x02B1
38    #endif
39    #ifndef WTS_REMOTE_CONNECT
40    #define WTS_REMOTE_CONNECT 0x3
41    #endif
42    
43    /* Global data */
44    static HINSTANCE g_instance;
45    static HWND g_hwnd;
46    
47    typedef void (*set_hooks_proc_t) ();
48    typedef void (*remove_hooks_proc_t) ();
49    typedef int (*get_instance_count_proc_t) ();
50    
51    typedef void (*move_window_proc_t) (HWND hwnd, int x, int y, int width, int height);
52    typedef void (*zchange_proc_t) (HWND hwnd, HWND behind);
53    typedef void (*focus_proc_t) (HWND hwnd);
54    typedef void (*set_state_proc_t) (HWND hwnd, int state);
55    
56    static move_window_proc_t g_move_window_fn = NULL;
57    static zchange_proc_t g_zchange_fn = NULL;
58    static focus_proc_t g_focus_fn = NULL;
59    static set_state_proc_t g_set_state_fn = NULL;
60    
61    static void
62    message(const char *text)
63    {
64            MessageBox(GetDesktopWindow(), text, "SeamlessRDP Shell", MB_OK);
65    }
66    
67    static char *
68    get_token(char **s)
69    {
70            char *comma, *head;
71            head = *s;
72    
73            if (!head)
74                    return NULL;
75    
76            comma = strchr(head, ',');
77            if (comma)
78            {
79                    *comma = '\0';
80                    *s = comma + 1;
81            }
82            else
83            {
84                    *s = NULL;
85            }
86    
87            return head;
88    }
89    
90    static BOOL CALLBACK
91    enum_cb(HWND hwnd, LPARAM lparam)
92    {
93            RECT rect;
94            unsigned short title[150];
95            LONG styles;
96            int state;
97            HWND parent;
98    
99            styles = GetWindowLong(hwnd, GWL_STYLE);
100    
101            if (!(styles & WS_VISIBLE))
102                    return TRUE;
103    
104            if (styles & WS_POPUP)
105                    parent = (HWND) GetWindowLong(hwnd, GWL_HWNDPARENT);
106            else
107                    parent = NULL;
108    
109            vchannel_write("CREATE", "0x%p,0x%p,0x%x", hwnd, parent, 0);
110    
111            if (!GetWindowRect(hwnd, &rect))
112            {
113                    debug("GetWindowRect failed!");
114                    return TRUE;
115            }
116    
117            vchannel_write("POSITION", "0x%p,%d,%d,%d,%d,0x%x",
118                           hwnd,
119                           rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
120    
121            GetWindowTextW(hwnd, title, sizeof(title) / sizeof(*title));
122    
123            vchannel_write("TITLE", "0x%x,%s,0x%x", hwnd, vchannel_strfilter_unicode(title), 0);
124    
125            if (styles & WS_MAXIMIZE)
126                    state = 2;
127            else if (styles & WS_MINIMIZE)
128                    state = 1;
129            else
130                    state = 0;
131    
132            vchannel_write("STATE", "0x%p,0x%x,0x%x", hwnd, state, 0);
133    
134            return TRUE;
135    }
136    
137    static void
138    do_sync(void)
139    {
140            vchannel_block();
141    
142            vchannel_write("SYNCBEGIN", "0x0");
143    
144            EnumWindows(enum_cb, 0);
145    
146            vchannel_write("SYNCEND", "0x0");
147    
148            vchannel_unblock();
149    }
150    
151    static void
152    do_state(unsigned int serial, HWND hwnd, int state)
153    {
154            g_set_state_fn(hwnd, state);
155    }
156    
157    static void
158    do_position(unsigned int serial, HWND hwnd, int x, int y, int width, int height)
159    {
160            g_move_window_fn(hwnd, x, y, width, height);
161    }
162    
163    static void
164    do_zchange(unsigned int serial, HWND hwnd, HWND behind)
165    {
166            g_zchange_fn(hwnd, behind);
167    }
168    
169    static void
170    do_focus(unsigned int serial, HWND hwnd)
171    {
172            g_focus_fn(hwnd);
173    }
174    
175    static void
176    process_cmds(void)
177    {
178            char line[VCHANNEL_MAX_LINE];
179            int size;
180    
181            char *p, *tok1, *tok2, *tok3, *tok4, *tok5, *tok6, *tok7, *tok8;
182    
183            while ((size = vchannel_read(line, sizeof(line))) >= 0)
184            {
185                    p = line;
186    
187                    tok1 = get_token(&p);
188                    tok2 = get_token(&p);
189                    tok3 = get_token(&p);
190                    tok4 = get_token(&p);
191                    tok5 = get_token(&p);
192                    tok6 = get_token(&p);
193                    tok7 = get_token(&p);
194                    tok8 = get_token(&p);
195    
196                    if (strcmp(tok1, "SYNC") == 0)
197                            do_sync();
198                    else if (strcmp(tok1, "STATE") == 0)
199                            do_state(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
200                                     strtol(tok4, NULL, 0));
201                    else if (strcmp(tok1, "POSITION") == 0)
202                            do_position(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
203                                        strtol(tok4, NULL, 0), strtol(tok5, NULL, 0), strtol(tok6, NULL,
204                                                                                             0),
205                                        strtol(tok7, NULL, 0));
206                    else if (strcmp(tok1, "ZCHANGE") == 0)
207                            do_zchange(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0),
208                                       (HWND) strtoul(tok4, NULL, 0));
209                    else if (strcmp(tok1, "FOCUS") == 0)
210                            do_focus(strtoul(tok2, NULL, 0), (HWND) strtoul(tok3, NULL, 0));
211            }
212    }
213    
214    static LRESULT CALLBACK
215    wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
216    {
217            if (message == WM_WTSSESSION_CHANGE)
218            {
219                    if (wparam == WTS_REMOTE_CONNECT)
220                    {
221                            /* These get reset on each reconnect */
222                            SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0);
223                            SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
224                            vchannel_write("HELLO", "0x%08x", 1);
225                    }
226            }
227    
228            return DefWindowProc(hwnd, message, wparam, lparam);
229    }
230    
231    static BOOL
232    register_class(void)
233    {
234            WNDCLASSEX wcx;
235    
236            memset(&wcx, 0, sizeof(wcx));
237    
238            wcx.cbSize = sizeof(wcx);
239            wcx.lpfnWndProc = wndproc;
240            wcx.hInstance = g_instance;
241            wcx.lpszClassName = "SeamlessClass";
242    
243            return RegisterClassEx(&wcx);
244    }
245    
246    static BOOL
247    create_wnd(void)
248    {
249            if (!register_class())
250                    return FALSE;
251    
252            g_hwnd = CreateWindow("SeamlessClass",
253                                  "Seamless Window",
254                                  WS_OVERLAPPEDWINDOW,
255                                  CW_USEDEFAULT,
256                                  CW_USEDEFAULT,
257                                  CW_USEDEFAULT,
258                                  CW_USEDEFAULT, (HWND) NULL, (HMENU) NULL, g_instance, (LPVOID) NULL);
259    
260            if (!g_hwnd)
261                    return FALSE;
262    
263            return TRUE;
264    }
265    
266    int WINAPI
267    WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR cmdline, int cmdshow)
268    {
269            HMODULE hookdll;
270    
271  //          set_hooks_proc_t set_hooks_fn;
272  // some global data          remove_hooks_proc_t remove_hooks_fn;
273  //          get_instance_count_proc_t instance_count_fn;
274  HWND ghWnd;  
275  NOTIFYICONDATA nid;          g_instance = instance;
276  HINSTANCE hAppInstance;  
277            hookdll = LoadLibrary("seamlessrdp.dll");
278  #define WM_TRAY_NOTIFY ( WM_APP + 1000 )          if (!hookdll)
279            {
280  static const char szAppName[] = "SeamlessRDP Shell";                  message("Could not load hook DLL. Unable to continue.");
281                    return -1;
282  typedef void ( *SetHooksProc ) ();          }
283  typedef void ( *RemoveHooksProc ) ();  
284  typedef int ( *GetInstanceCountProc ) ();          set_hooks_fn = (set_hooks_proc_t) GetProcAddress(hookdll, "SetHooks");
285            remove_hooks_fn = (remove_hooks_proc_t) GetProcAddress(hookdll, "RemoveHooks");
286  //          instance_count_fn = (get_instance_count_proc_t) GetProcAddress(hookdll, "GetInstanceCount");
287  // spawn a message box          g_move_window_fn = (move_window_proc_t) GetProcAddress(hookdll, "SafeMoveWindow");
288  //          g_zchange_fn = (zchange_proc_t) GetProcAddress(hookdll, "SafeZChange");
289  void Message( const char *message )          g_focus_fn = (focus_proc_t) GetProcAddress(hookdll, "SafeFocus");
290  {          g_set_state_fn = (set_state_proc_t) GetProcAddress(hookdll, "SafeSetState");
291      MessageBox( GetDesktopWindow(), message, "SeamlessRDP Shell", MB_OK );  
292  }          if (!set_hooks_fn || !remove_hooks_fn || !instance_count_fn || !g_move_window_fn
293                || !g_zchange_fn || !g_focus_fn || !g_set_state_fn)
294  //          {
295  // manage the tray icon                  FreeLibrary(hookdll);
296  //                  message("Hook DLL doesn't contain the correct functions. Unable to continue.");
297  BOOL InitTrayIcon()                  return -1;
298  {          }
299      nid.cbSize = sizeof( NOTIFYICONDATA );  
300      nid.hWnd = ghWnd;          /* Check if the DLL is already loaded */
301      nid.uID = 0;          if (instance_count_fn() != 1)
302      nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;          {
303      nid.uCallbackMessage = WM_TRAY_NOTIFY;                  FreeLibrary(hookdll);
304      strcpy( nid.szTip, szAppName );                  message("Another running instance of Seamless RDP detected.");
305      nid.hIcon = LoadIcon( hAppInstance, MAKEINTRESOURCE( IDI_TRAY ) );                  return -1;
306            }
307      if ( Shell_NotifyIcon( NIM_ADD, &nid ) != TRUE ) {  
308          Message( "Unable to create tray icon." );          if (!create_wnd())
309          return FALSE;          {
310      }                  FreeLibrary(hookdll);
311                    message("Couldn't create a window to catch events.");
312      return TRUE;                  return -1;
313  }          }
314    
315  //          WTSRegisterSessionNotification(g_hwnd, NOTIFY_FOR_THIS_SESSION);
316  // Remove tray icon  
317  //          vchannel_open();
318  BOOL RemoveTrayIcon()  
319  {          vchannel_write("HELLO", "0x%08x", 0);
320      if ( Shell_NotifyIcon( NIM_DELETE, &nid ) != TRUE ) {  
321          Message( "Unable to remove tray icon." );          set_hooks_fn();
322          return FALSE;  
323      }          /* Since we don't see the entire desktop we must resize windows
324               immediatly. */
325      return TRUE;          SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0);
326    
327  }          /* Disable screen saver since we cannot catch its windows. */
328            SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, NULL, 0);
329  //  
330  // manage the about dialog box          if (strlen(cmdline) == 0)
331  //          {
332  BOOL CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam,                  message("No command line specified.");
333                            LPARAM lParam )                  return -1;
334  {          }
335      if ( uMsg == WM_COMMAND ) {          else
336          WORD wID = LOWORD( wParam );          {
337          if ( wID == IDOK )                  BOOL result;
338              DestroyWindow( hwndDlg );                  DWORD exitcode;
339      }                  PROCESS_INFORMATION proc_info;
340                    STARTUPINFO startup_info;
341      return 0;                  MSG msg;
342  }  
343                    memset(&startup_info, 0, sizeof(STARTUPINFO));
344  void AboutDlg()                  startup_info.cb = sizeof(STARTUPINFO);
345  {  
346      DialogBox( hAppInstance, MAKEINTRESOURCE( IDD_ABOUT ), NULL, DialogProc );                  result = CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0,
347  }                                         NULL, NULL, &startup_info, &proc_info);
348    
349  //                  if (result)
350  // manage the context menu                  {
351  //                          do
352  void DoContextMenu()                          {
353  {                                  while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
354      HMENU hMenu, hSubMenu;                                  {
355      POINT pt;                                          TranslateMessage(&msg);
356          int cmd;                                          DispatchMessage(&msg);
357                                    }
358      hMenu = LoadMenu( hAppInstance, MAKEINTRESOURCE( IDR_TRAY ) );                                  process_cmds();
359      if ( hMenu == NULL ) {                                  Sleep(100);
360          Message( "Unable to load menu ressource." );                                  GetExitCodeProcess(proc_info.hProcess, &exitcode);
361          return ;                          }
362      }                          while (exitcode == STILL_ACTIVE);
363    
364      hSubMenu = GetSubMenu( hMenu, 0 );                          // Release handles
365      if ( hSubMenu == NULL ) {                          CloseHandle(proc_info.hProcess);
366          Message( "Unable to find popup mennu." );                          CloseHandle(proc_info.hThread);
367          return ;                  }
368      }                  else
369                    {
370      // get the cursor position                          // CreateProcess failed.
371      GetCursorPos( &pt );                          char msg[256];
372                            _snprintf(msg, sizeof(msg),
373      SetForegroundWindow( ghWnd );                                    "Unable to launch the requested application:\n%s", cmdline);
374      cmd = TrackPopupMenu( hSubMenu,                          message(msg);
375                                TPM_RETURNCMD | TPM_LEFTALIGN | TPM_RIGHTBUTTON,                  }
376                                pt.x, pt.y, 0, ghWnd, NULL );          }
377      DestroyMenu( hMenu );  
378            WTSUnRegisterSessionNotification(g_hwnd);
     switch ( cmd ) {  
     case ID_WMEXIT: {  
             PostQuitMessage( 0 );  
             break;  
         }  
     case ID_WMABOUT: {  
             AboutDlg();  
             break;  
         }  
     }  
 }  
   
 //  
 // manage the main window  
 //  
 LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )  
 {  
     switch ( uMsg ) {  
     case WM_DESTROY: {  
             PostQuitMessage( 0 );  
             return 0;  
         }  
     case WM_TRAY_NOTIFY: {  
             if ( lParam == WM_RBUTTONDOWN )  
                 DoContextMenu();  
             return 0;  
         }  
     }  
   
     return DefWindowProc( hWnd, uMsg, wParam, lParam );  
 }  
   
 //  
 //Init window  
 //  
 BOOL InitWindow()  
 {  
     // register the frame class  
     WNDCLASS wndclass;  
     wndclass.style = 0;  
     wndclass.lpfnWndProc = ( WNDPROC ) MainWndProc;  
     wndclass.cbClsExtra = 0;  
     wndclass.cbWndExtra = 0;  
     wndclass.hInstance = hAppInstance;  
     wndclass.hIcon = 0;  
     wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );  
     wndclass.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 );  
     wndclass.lpszMenuName = NULL;  
     wndclass.lpszClassName = szAppName;  
   
     if ( !RegisterClass( &wndclass ) ) {  
         Message( "Unable to register the window class." );  
         return FALSE;  
     }  
   
     // create the frame  
     ghWnd = CreateWindow( szAppName, szAppName,  
                           WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS |  
                           WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 640,  
                           480, NULL, NULL, hAppInstance, NULL );  
   
     // make sure window was created  
     if ( !ghWnd ) {  
         Message( "Unable to create the window." );  
         return FALSE;  
     }  
   
     return TRUE;  
 }  
   
 //  
 // our main loop  
 //  
 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,  
                     LPSTR lpCmdLine, int nCmdShow )  
 {  
     HMODULE hHookDLL;  
     GetInstanceCountProc pfnInstanceCount;  
     SetHooksProc pfnSetHooks;  
     RemoveHooksProc pfnRemoveHooks;  
   
     hAppInstance = hInstance;  
   
     hHookDLL = LoadLibrary( "hookdll.dll" );  
     if ( !hHookDLL ) {  
         Message( "Could not load hook DLL. Unable to continue." );  
         return -1;  
     }  
   
     pfnInstanceCount = (GetInstanceCountProc) GetProcAddress( hHookDLL, "GetInstanceCount" );  
     pfnSetHooks = (SetHooksProc) GetProcAddress( hHookDLL, "SetHooks" );  
     pfnRemoveHooks = (RemoveHooksProc) GetProcAddress( hHookDLL, "RemoveHooks" );  
   
     if ( !pfnInstanceCount || !pfnSetHooks || !pfnRemoveHooks ) {  
         FreeLibrary( hHookDLL );  
         Message( "Hook DLL doesn't contain the correct functions. Unable to continue." );  
         return -1;  
     }  
   
     /* Check if the DLL is already loaded */  
     if ( pfnInstanceCount() != 1 ) {  
         FreeLibrary( hHookDLL );  
         Message( "Another running instance of Seamless RDP detected." );  
         return -1;  
     }  
   
     pfnSetHooks();  
   
     // if we have been specified an app to launch, we will wait until the app has closed and use that for  
     // our cue to exit  
     if ( strlen( lpCmdLine ) > 0 ) {  
         // Because we do not have a explorer.exe we need to make this application the replacement  
         // shell. We do this by calling SystemParametersInfo. If we don't do this, we won't get the WH_SHELL notifications.  
   
         MINIMIZEDMETRICS mmm;  
         PROCESS_INFORMATION procInfo;  
         STARTUPINFO startupInfo = {  
                                       0  
                                   };  
         char attr[] = "";  
         LPTSTR process = lpCmdLine;  
         DWORD dwExitCode;  
         BOOL m_create;  
   
         // From MSDN:  
         // Note that custom shell applications do not receive WH_SHELL messages. Therefore, any application that  
         // registers itself as the default shell must call the SystemParametersInfo function with SPI_SETMINIMIZEDMETRICS  
         // before it (or any other application) can receive WH_SHELL messages.  
   
         mmm.cbSize = sizeof( MINIMIZEDMETRICS );  
         SystemParametersInfo( SPI_SETMINIMIZEDMETRICS,  
                               sizeof( MINIMIZEDMETRICS ), &mmm, 0 );  
   
         // We require DragFullWindows  
         SystemParametersInfo( SPI_SETDRAGFULLWINDOWS, TRUE, NULL, 0 );  
   
         //set the current directory to that of the requested app .exe location  
         //tokenise lpCmdLine. first is the exe path. second (if exists) is the current directory to set.  
         //SetCurrentDirectory ();  
   
         //start process specified from command line arg.  
         startupInfo.cb = sizeof( STARTUPINFO );  
   
         m_create =  
             CreateProcess( NULL, process, NULL, NULL, FALSE, 0, NULL, NULL,  
                            &startupInfo, &procInfo );  
   
         if ( m_create != FALSE ) {  
             // A loop to watch the process.  
             GetExitCodeProcess( procInfo.hProcess, &dwExitCode );  
   
             while ( dwExitCode == STILL_ACTIVE ) {  
                 GetExitCodeProcess( procInfo.hProcess, &dwExitCode );  
                 Sleep( 1000 );  
             }  
   
             // Release handles  
             CloseHandle( procInfo.hProcess );  
             CloseHandle( procInfo.hThread );  
         } else {  
             // CreateProcess failed.  
             char msg[ 256 ];  
             snprintf( msg, sizeof( msg ), "Unable to launch the requested application:\n%s", process );  
             Message( msg );  
         }  
     } else  
         // we are launching without an app, therefore we will show the system tray app and wait for the user to close it  
     {  
         MSG msg;  
   
                 // create a dummy window to receive WM_QUIT message  
         InitWindow();  
   
         // create the tray icon  
         InitTrayIcon();  
   
         // just get and dispatch messages until we're killed  
         while ( GetMessage( &msg, 0, 0, 0 ) ) {  
             TranslateMessage( &msg );  
             DispatchMessage( &msg );  
         };  
   
         // remove our tray icon  
         RemoveTrayIcon();  
     }  
379    
380            remove_hooks_fn();
381    
382      // remove hook before saying goodbye          FreeLibrary(hookdll);
     pfnRemoveHooks();  
383    
384      FreeLibrary( hHookDLL );          vchannel_close();
385    
386      return 1;          return 1;
387  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26