1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/utilsexec.cpp
3 // Purpose: Various utilities
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
40 #include "wx/process.h"
43 #include "wx/msw/private.h"
47 #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
54 #if defined(__GNUWIN32__) && !defined(__TWIN32__)
55 #include <sys/unistd.h>
59 #if defined(__WIN32__) && !defined(__WXWINE__)
71 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
77 // ----------------------------------------------------------------------------
79 // ----------------------------------------------------------------------------
81 // this message is sent when the process we're waiting for terminates
82 #define wxWM_PROC_TERMINATED (WM_USER + 10000)
84 // ----------------------------------------------------------------------------
85 // this module globals
86 // ----------------------------------------------------------------------------
88 // we need to create a hidden window to receive the process termination
89 // notifications and for this we need a (Win) class name for it which we will
90 // register the first time it's needed
91 static const wxChar
*gs_classForHiddenWindow
= NULL
;
93 // ----------------------------------------------------------------------------
95 // ----------------------------------------------------------------------------
97 // structure describing the process we're being waiting for
104 if ( !::CloseHandle(hProcess
) )
106 wxLogLastError("CloseHandle(hProcess)");
111 HWND hWnd
; // window to send wxWM_PROC_TERMINATED to
112 HANDLE hProcess
; // handle of the process
113 DWORD dwProcessId
; // pid of the process
115 DWORD dwExitCode
; // the exit code of the process
116 bool state
; // set to FALSE when the process finishes
119 // ============================================================================
121 // ============================================================================
124 static DWORD
wxExecuteThread(wxExecuteData
*data
)
126 WaitForSingleObject(data
->hProcess
, INFINITE
);
129 if ( !GetExitCodeProcess(data
->hProcess
, &data
->dwExitCode
) )
131 wxLogLastError("GetExitCodeProcess");
134 wxASSERT_MSG( data
->dwExitCode
!= STILL_ACTIVE
,
135 wxT("process should have terminated") );
137 // send a message indicating process termination to the window
138 SendMessage(data
->hWnd
, wxWM_PROC_TERMINATED
, 0, (LPARAM
)data
);
143 // window procedure of a hidden window which is created just to receive
144 // the notification message when a process exits
145 LRESULT APIENTRY _EXPORT
wxExecuteWindowCbk(HWND hWnd
, UINT message
,
146 WPARAM wParam
, LPARAM lParam
)
148 if ( message
== wxWM_PROC_TERMINATED
)
150 DestroyWindow(hWnd
); // we don't need it any more
152 wxExecuteData
*data
= (wxExecuteData
*)lParam
;
155 data
->handler
->OnTerminate((int)data
->dwProcessId
,
156 (int)data
->dwExitCode
);
161 // we're executing synchronously, tell the waiting thread
162 // that the process finished
167 // asynchronous execution - we should do the clean up
176 long wxExecute(const wxString
& command
, bool sync
, wxProcess
*handler
)
178 wxCHECK_MSG( !!command
, 0, wxT("empty command in wxExecute") );
180 #if defined(__WIN32__) && !defined(__TWIN32__)
181 // the old code is disabled because we really need a process handle
182 // if we want to execute it asynchronously or even just get its
183 // return code and for this we must use CreateProcess() and not
186 // isolate command and arguments
187 wxString commandName
;
188 bool insideQuotes
= FALSE
;
190 for ( pc
= command
.c_str(); *pc
!= '\0'; pc
++ )
201 insideQuotes
= !insideQuotes
;
206 continue; // skip the next break
209 // only reached for space not inside quotes
213 wxString commandArgs
= pc
;
215 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
216 HWND hwndTop
= (HWND
)(winTop
? winTop
->GetHWND() : 0);
220 result
= ShellExecute(hwndTop
,
221 (const wchar_t)"open",
222 (const wchar_t)commandName
,
223 (const wchar_t)commandArgs
,
227 result
= ShellExecute(hwndTop
, "open", commandName
,
228 commandArgs
, NULL
, SW_SHOWNORMAL
);
231 if ( ((long)result
) <= 32 )
232 wxLogSysError(_("Can't execute command '%s'"), command
.c_str());
236 // create the process
242 PROCESS_INFORMATION pi
;
244 if ( ::CreateProcess(
245 NULL
, // application name (use only cmd line)
246 (wxChar
*)command
.c_str(), // full command line
247 NULL
, // security attributes: defaults for both
248 NULL
, // the process and its main thread
249 FALSE
, // don't inherit handles
250 CREATE_DEFAULT_ERROR_MODE
, // flags
251 NULL
, // environment (use the same)
252 NULL
, // current directory (use the same)
253 &si
, // startup info (unused here)
257 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
262 // close unneeded handle
263 if ( !::CloseHandle(pi
.hThread
) )
264 wxLogLastError("CloseHandle(hThread)");
266 if ( !gs_classForHiddenWindow
)
268 gs_classForHiddenWindow
= _T("wxHiddenWindow");
271 wxZeroMemory(wndclass
);
272 wndclass
.lpfnWndProc
= (WNDPROC
)wxExecuteWindowCbk
;
273 wndclass
.hInstance
= wxGetInstance();
274 wndclass
.lpszClassName
= gs_classForHiddenWindow
;
276 if ( !::RegisterClass(&wndclass
) )
278 wxLogLastError("RegisterClass(hidden window)");
284 // create a hidden window to receive notification about process
286 HWND hwnd
= ::CreateWindow(gs_classForHiddenWindow
, NULL
,
288 (HMENU
)NULL
, wxGetInstance(), 0);
289 wxASSERT_MSG( hwnd
, wxT("can't create a hidden window for wxExecute") );
292 wxExecuteData
*data
= new wxExecuteData
;
293 data
->hProcess
= pi
.hProcess
;
294 data
->dwProcessId
= pi
.dwProcessId
;
299 wxASSERT_MSG( !handler
, wxT("wxProcess param ignored for sync execution") );
301 data
->handler
= NULL
;
305 // may be NULL or not
306 data
->handler
= handler
;
310 HANDLE hThread
= ::CreateThread(NULL
,
312 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
319 wxLogLastError("CreateThread in wxExecute");
324 // the process still started up successfully...
325 return pi
.dwProcessId
;
330 // clean up will be done when the process terminates
333 return pi
.dwProcessId
;
336 // waiting until command executed
337 while ( data
->state
)
340 DWORD dwExitCode
= data
->dwExitCode
;
343 // return the exit code
347 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
348 if (instanceID
< 32) return(0);
354 running
= GetModuleUsage((HINSTANCE
)instanceID
);
362 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
366 while ( *argv
!= NULL
)
368 command
<< *argv
++ << ' ';
371 command
.RemoveLast();
373 return wxExecute(command
, sync
, handler
);