1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Various utilities
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
31 #include "wx/process.h"
33 #include "wx/msw/private.h"
39 #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
48 #include <sys/unistd.h>
53 #if defined(__WIN32__) && !defined(__WXWINE__)
65 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
71 // this message is sent when the process we're waiting for terminates
72 #define wxWM_PROC_TERMINATED (WM_USER + 10000)
74 // structure describing the process we're being waiting for
81 if ( !::CloseHandle(hProcess
) )
83 wxLogLastError("CloseHandle(hProcess)");
88 HWND hWnd
; // window to send wxWM_PROC_TERMINATED to
89 HANDLE hProcess
; // handle of the process
90 DWORD dwProcessId
; // pid of the process
92 DWORD dwExitCode
; // the exit code of the process
93 bool state
; // set to FALSE when the process finishes
98 static DWORD
wxExecuteThread(wxExecuteData
*data
)
100 WaitForSingleObject(data
->hProcess
, INFINITE
);
103 if ( !GetExitCodeProcess(data
->hProcess
, &data
->dwExitCode
) )
105 wxLogLastError("GetExitCodeProcess");
108 wxASSERT_MSG( data
->dwExitCode
!= STILL_ACTIVE
,
109 "process should have terminated" );
111 // send a message indicating process termination to the window
112 SendMessage(data
->hWnd
, wxWM_PROC_TERMINATED
, 0, (LPARAM
)data
);
118 // window procedure of a hidden window which is created just to receive
119 // the notification message when a process exits
120 LRESULT APIENTRY _EXPORT
wxExecuteWindowCbk(HWND hWnd
, UINT message
,
121 WPARAM wParam
, LPARAM lParam
)
123 if ( message
== wxWM_PROC_TERMINATED
)
125 DestroyWindow(hWnd
); // we don't need it any more
127 wxExecuteData
*data
= (wxExecuteData
*)lParam
;
130 data
->handler
->OnTerminate((int)data
->dwProcessId
,
131 (int)data
->dwExitCode
);
136 // we're executing synchronously, tell the waiting thread
137 // that the process finished
142 // asynchronous execution - we should do the clean up
150 extern char wxPanelClassName
[];
152 long wxExecute(const wxString
& command
, bool sync
, wxProcess
*handler
)
154 wxCHECK_MSG( !!command
, 0, "empty command in wxExecute" );
156 #if defined(__WIN32__) && !defined(__TWIN32__)
157 // the old code is disabled because we really need a process handle
158 // if we want to execute it asynchronously or even just get its
159 // return code and for this we must use CreateProcess() and not
162 // isolate command and arguments
163 wxString commandName
;
164 bool insideQuotes
= FALSE
;
166 for ( pc
= command
.c_str(); *pc
!= '\0'; pc
++ )
177 insideQuotes
= !insideQuotes
;
182 continue; // skip the next break
185 // only reached for space not inside quotes
189 wxString commandArgs
= pc
;
191 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
192 HWND hwndTop
= (HWND
)(winTop
? winTop
->GetHWND() : 0);
196 result
= ShellExecute(hwndTop
,
197 (const wchar_t)"open",
198 (const wchar_t)commandName
,
199 (const wchar_t)commandArgs
,
203 result
= ShellExecute(hwndTop
, "open", commandName
,
204 commandArgs
, NULL
, SW_SHOWNORMAL
);
207 if ( ((long)result
) <= 32 )
208 wxLogSysError(_("Can't execute command '%s'"), command
.c_str());
212 // create the process
215 memset(&si
, 0, sizeof(si
));
217 ::ZeroMemory(&si
, sizeof(si
));
222 PROCESS_INFORMATION pi
;
224 if ( ::CreateProcess(
225 NULL
, // application name (use only cmd line)
226 (char *)command
.c_str(), // full command line
227 NULL
, // security attributes: defaults for both
228 NULL
, // the process and its main thread
229 FALSE
, // don't inherit handles
230 CREATE_DEFAULT_ERROR_MODE
, // flags
231 NULL
, // environment (use the same)
232 NULL
, // current directory (use the same)
233 &si
, // startup info (unused here)
237 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
242 // close unneeded handle
243 if ( !::CloseHandle(pi
.hThread
) )
244 wxLogLastError("CloseHandle(hThread)");
246 // create a hidden window to receive notification about process
248 HWND hwnd
= ::CreateWindow(wxPanelClassName
, NULL
, 0, 0, 0, 0, 0, NULL
,
249 (HMENU
)NULL
, wxGetInstance(), 0);
250 wxASSERT_MSG( hwnd
, "can't create a hidden window for wxExecute" );
252 FARPROC ExecuteWindowInstance
= MakeProcInstance((FARPROC
)wxExecuteWindowCbk
,
255 ::SetWindowLong(hwnd
, GWL_WNDPROC
, (LONG
) ExecuteWindowInstance
);
258 wxExecuteData
*data
= new wxExecuteData
;
259 data
->hProcess
= pi
.hProcess
;
260 data
->dwProcessId
= pi
.dwProcessId
;
265 wxASSERT_MSG( !handler
, "wxProcess param ignored for sync execution" );
267 data
->handler
= NULL
;
271 // may be NULL or not
272 data
->handler
= handler
;
276 HANDLE hThread
= ::CreateThread(NULL
,
278 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
285 wxLogLastError("CreateThread in wxExecute");
290 // the process still started up successfully...
291 return pi
.dwProcessId
;
296 // clean up will be done when the process terminates
299 return pi
.dwProcessId
;
302 // waiting until command executed
303 while ( data
->state
)
306 DWORD dwExitCode
= data
->dwExitCode
;
309 // return the exit code
313 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
314 if (instanceID
< 32) return(0);
320 running
= GetModuleUsage((HANDLE
)instanceID
);
328 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
332 while ( *argv
!= NULL
)
334 command
<< *argv
++ << ' ';
337 command
.RemoveLast();
339 return wxExecute(command
, sync
, handler
);