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
80 if ( !::CloseHandle(hProcess
) )
82 wxLogLastError("CloseHandle(hProcess)");
86 HWND hWnd
; // window to send wxWM_PROC_TERMINATED to
87 HANDLE hProcess
; // handle of the process
88 DWORD dwProcessId
; // pid of the process
90 DWORD dwExitCode
; // the exit code of the process
91 bool state
; // set to FALSE when the process finishes
96 static DWORD
wxExecuteThread(wxExecuteData
*data
)
98 WaitForSingleObject(data
->hProcess
, INFINITE
);
101 if ( !GetExitCodeProcess(data
->hProcess
, &data
->dwExitCode
) )
103 wxLogLastError("GetExitCodeProcess");
106 wxASSERT_MSG( data
->dwExitCode
!= STILL_ACTIVE
,
107 "process should have terminated" );
109 // send a message indicating process termination to the window
110 SendMessage(data
->hWnd
, wxWM_PROC_TERMINATED
, 0, (LPARAM
)data
);
116 // window procedure of a hidden window which is created just to receive
117 // the notification message when a process exits
118 LRESULT APIENTRY _EXPORT
wxExecuteWindowCbk(HWND hWnd
, UINT message
,
119 WPARAM wParam
, LPARAM lParam
)
121 if ( message
== wxWM_PROC_TERMINATED
)
123 DestroyWindow(hWnd
); // we don't need it any more
125 wxExecuteData
*data
= (wxExecuteData
*)lParam
;
128 data
->handler
->OnTerminate((int)data
->dwProcessId
,
129 (int)data
->dwExitCode
);
134 // we're executing synchronously, tell the waiting thread
135 // that the process finished
140 // asynchronous execution - we should do the clean up
148 extern char wxPanelClassName
[];
150 long wxExecute(const wxString
& command
, bool sync
, wxProcess
*handler
)
152 wxCHECK_MSG( !!command
, 0, "empty command in wxExecute" );
154 #if defined(__WIN32__) && !defined(__TWIN32__)
155 // the old code is disabled because we really need a process handle
156 // if we want to execute it asynchronously or even just get its
157 // return code and for this we must use CreateProcess() and not
160 // isolate command and arguments
161 wxString commandName
;
162 bool insideQuotes
= FALSE
;
164 for ( pc
= command
.c_str(); *pc
!= '\0'; pc
++ )
175 insideQuotes
= !insideQuotes
;
180 continue; // skip the next break
183 // only reached for space not inside quotes
187 wxString commandArgs
= pc
;
189 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
190 HWND hwndTop
= (HWND
)(winTop
? winTop
->GetHWND() : 0);
194 result
= ShellExecute(hwndTop
,
195 (const wchar_t)"open",
196 (const wchar_t)commandName
,
197 (const wchar_t)commandArgs
,
201 result
= ShellExecute(hwndTop
, "open", commandName
,
202 commandArgs
, NULL
, SW_SHOWNORMAL
);
205 if ( ((long)result
) <= 32 )
206 wxLogSysError(_("Can't execute command '%s'"), command
.c_str());
210 // create the process
212 ::ZeroMemory(&si
, sizeof(si
));
215 PROCESS_INFORMATION pi
;
217 if ( ::CreateProcess(
218 NULL
, // application name (use only cmd line)
219 (char *)command
.c_str(), // full command line
220 NULL
, // security attributes: defaults for both
221 NULL
, // the process and its main thread
222 FALSE
, // don't inherit handles
223 CREATE_DEFAULT_ERROR_MODE
, // flags
224 NULL
, // environment (use the same)
225 NULL
, // current directory (use the same)
226 &si
, // startup info (unused here)
230 wxLogSysError(_("Execution of command '%s' failed"), command
.c_str());
235 // close unneeded handle
236 if ( !::CloseHandle(pi
.hThread
) )
237 wxLogLastError("CloseHandle(hThread)");
239 // create a hidden window to receive notification about process
241 HWND hwnd
= ::CreateWindow(wxPanelClassName
, NULL
, 0, 0, 0, 0, 0, NULL
,
242 (HMENU
)NULL
, wxGetInstance(), 0);
243 wxASSERT_MSG( hwnd
, "can't create a hidden window for wxExecute" );
245 FARPROC ExecuteWindowInstance
= MakeProcInstance((FARPROC
)wxExecuteWindowCbk
,
248 ::SetWindowLong(hwnd
, GWL_WNDPROC
, (LONG
) ExecuteWindowInstance
);
251 wxExecuteData
*data
= new wxExecuteData
;
252 data
->hProcess
= pi
.hProcess
;
253 data
->dwProcessId
= pi
.dwProcessId
;
256 data
->handler
= handler
;
259 HANDLE hThread
= ::CreateThread(NULL
,
261 (LPTHREAD_START_ROUTINE
)wxExecuteThread
,
268 wxLogLastError("CreateThread in wxExecute");
273 // the process still started up successfully...
274 return pi
.dwProcessId
;
279 // clean up will be done when the process terminates
280 return pi
.dwProcessId
;
283 // waiting until command executed
284 while ( data
->state
)
289 return pi
.dwProcessId
;
292 long instanceID
= WinExec((LPCSTR
) WXSTRINGCAST command
, SW_SHOW
);
293 if (instanceID
< 32) return(0);
299 running
= GetModuleUsage((HANDLE
)instanceID
);
307 long wxExecute(char **argv
, bool sync
, wxProcess
*handler
)
311 while ( *argv
!= NULL
)
313 command
<< *argv
++ << ' ';
316 command
.RemoveLast();
318 return wxExecute(command
, sync
, handler
);