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(__SALFORDC__)
48 #include <sys/unistd.h>
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
214 ::ZeroMemory(&si
, sizeof(si
));
217 PROCESS_INFORMATION pi
;
219 if ( ::CreateProcess(
220 NULL
, // application name (use only cmd line)
221 (char *)command
.c_str(), // full command line
222 NULL
, // security attributes: defaults for both
223 NULL
, // the process and its main thread
224 FALSE
, // don't inherit handles
225 CREATE_DEFAULT_ERROR_MODE
, // flags
226 NULL
, // environment (use the same)
227 NULL
, // current directory (use the same)
228 &si
, // startup info (unused here)
232 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
237 // close unneeded handle
238 if ( !::CloseHandle(pi
.hThread
) )
239 wxLogLastError("CloseHandle(hThread)");
241 // create a hidden window to receive notification about process
243 HWND hwnd
= ::CreateWindow(wxPanelClassName
, NULL
, 0, 0, 0, 0, 0, NULL
,
244 (HMENU
)NULL
, wxGetInstance(), 0);
245 wxASSERT_MSG( hwnd
, "can't create a hidden window for wxExecute" );
247 FARPROC ExecuteWindowInstance
= MakeProcInstance((FARPROC
)wxExecuteWindowCbk
,
250 ::SetWindowLong(hwnd
, GWL_WNDPROC
, (LONG
) ExecuteWindowInstance
);
253 wxExecuteData
*data
= new wxExecuteData
;
254 data
->hProcess
= pi
.hProcess
;
255 data
->dwProcessId
= pi
.dwProcessId
;
258 data
->handler
= handler
;
261 HANDLE hThread
= ::CreateThread(NULL
,
263 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
270 wxLogLastError("CreateThread in wxExecute");
275 // the process still started up successfully...
276 return pi
.dwProcessId
;
281 // clean up will be done when the process terminates
282 return pi
.dwProcessId
;
285 // waiting until command executed
286 while ( data
->state
)
291 return pi
.dwProcessId
;
294 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
295 if (instanceID
< 32) return(0);
301 running
= GetModuleUsage((HANDLE
)instanceID
);
309 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
313 while ( *argv
!= NULL
)
315 command
<< *argv
++ << ' ';
318 command
.RemoveLast();
320 return wxExecute(command
, sync
, handler
);