1
// For compilers that support precompilation, includes "wx.h".
2
#include "ExecHiddenMSW.h"
16
#include <wx/module.h>
19
#include <wx/process.h>
21
#include <wx/apptrait.h>
24
#include <wx/msw/private.h>
28
#if !defined(__GNUWIN32__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
35
#if defined(__GNUWIN32__)
36
#include <sys/unistd.h>
40
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
54
#if !(defined(_MSC_VER) && (_MSC_VER > 800))
60
#define wxWM_PROC_TERMINATED (WM_USER + 10000)
63
extern "C" WXDLLIMPEXP_BASE HWND
64
wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
66
static const wxChar *wxMSWEXEC_WNDCLASSNAME2 = wxT("_wxExecute_Internal_Class2");
67
static const wxChar *gs_classForHiddenWindow2 = NULL;
70
// structure describing the process we're being waiting for
76
if ( !::CloseHandle(hProcess) )
78
wxLogLastError(wxT("CloseHandle(hProcess)"));
82
HWND hWnd; // window to send wxWM_PROC_TERMINATED to
83
HANDLE hProcess; // handle of the process
84
DWORD dwProcessId; // pid of the process
86
DWORD dwExitCode; // the exit code of the process
87
bool state; // set to false when the process finishes
90
LRESULT APIENTRY _EXPORT wxExecuteWindowCbk2(HWND hWnd, UINT message,
91
WPARAM wParam, LPARAM lParam)
93
if ( message == wxWM_PROC_TERMINATED )
95
DestroyWindow(hWnd); // we don't need it any more
97
wxExecuteData2 * const data = (wxExecuteData2 *)lParam;
100
data->handler->OnTerminate((int)data->dwProcessId,
101
(int)data->dwExitCode);
106
// we're executing synchronously, tell the waiting thread
107
// that the process finished
112
// asynchronous execution - we should do the clean up
120
return ::DefWindowProc(hWnd, message, wParam, lParam);
125
// thread function for the thread monitoring the process termination
126
static DWORD __stdcall wxExecuteThread2(void *arg)
128
wxExecuteData2 * const data = (wxExecuteData2 *)arg;
130
if ( ::WaitForSingleObject(data->hProcess, INFINITE) != WAIT_OBJECT_0 )
132
wxLogDebug(_T("Waiting for the process termination failed!"));
136
if ( !::GetExitCodeProcess(data->hProcess, &data->dwExitCode) )
138
wxLogLastError(wxT("GetExitCodeProcess"));
141
wxASSERT_MSG( data->dwExitCode != STILL_ACTIVE,
142
wxT("process should have terminated") );
144
// send a message indicating process termination to the window
145
::SendMessage(data->hWnd, wxWM_PROC_TERMINATED, 0, (LPARAM)data);
152
long wxExecuteHidden(const wxString& cmd, int flags, wxProcess *handler)
154
wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );
157
// for many reasons, the code below breaks down if it's called from another
158
// thread -- this could be fixed, but as Unix versions don't support this
159
// neither I don't want to waste time on this now
160
wxASSERT_MSG( wxThread::IsMain(),
161
_T("wxExecute() can be called only from the main thread") );
162
#endif // wxUSE_THREADS
173
// the IO redirection is only supported with wxUSE_STREAMS
174
BOOL redirect = FALSE;
176
// create the process
182
// we don't show the (console) process
183
// window by default, but this can be overridden by the caller by
184
// specifying wxEXEC_NOHIDE flag
185
if ( !(flags & wxEXEC_NOHIDE) )
187
si.dwFlags |= STARTF_USESHOWWINDOW;
188
si.wShowWindow = SW_HIDE;
190
//END DM ADDED CODE HERE
192
PROCESS_INFORMATION pi;
193
DWORD dwFlags = CREATE_SUSPENDED;
196
dwFlags |= CREATE_DEFAULT_ERROR_MODE ;
198
// we are assuming commands without spaces for now
199
wxString moduleName = command.BeforeFirst(wxT(' '));
200
wxString arguments = command.AfterFirst(wxT(' '));
203
bool ok = ::CreateProcess
205
// WinCE requires appname to be non null
206
// Win32 allows for null
209
moduleName.c_str(), // application name
211
arguments.c_str(), // arguments
213
NULL, // application name (use only cmd line)
215
command.c_str(), // full command line
217
NULL, // security attributes: defaults for both
218
NULL, // the process and its main thread
219
redirect, // inherit handles if we use pipes
220
dwFlags, // process creation flags
221
NULL, // environment (use the same)
222
NULL, // current directory (use the same)
223
&si, // startup info (unused here)
230
wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
232
return flags & wxEXEC_SYNC ? -1 : 0;
236
// create a hidden window to receive notification about process
238
HWND hwnd = wxCreateHiddenWindow
240
&gs_classForHiddenWindow2,
241
wxMSWEXEC_WNDCLASSNAME2,
242
(WNDPROC)wxExecuteWindowCbk2
245
wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
248
wxExecuteData2 *data = new wxExecuteData2;
249
data->hProcess = pi.hProcess;
250
data->dwProcessId = pi.dwProcessId;
252
data->state = (flags & wxEXEC_SYNC) != 0;
253
if ( flags & wxEXEC_SYNC )
255
// handler may be !NULL for capturing program output, but we don't use
256
// it wxExecuteData struct in this case
257
data->handler = NULL;
261
// may be NULL or not
262
data->handler = handler;
266
HANDLE hThread = ::CreateThread(NULL,
273
// resume process we created now - whether the thread creation succeeded or
275
if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
277
// ignore it - what can we do?
278
wxLogLastError(wxT("ResumeThread in wxExecute"));
281
// close unneeded handle
282
if ( !::CloseHandle(pi.hThread) )
283
wxLogLastError(wxT("CloseHandle(hThread)"));
287
wxLogLastError(wxT("CreateThread in wxExecute"));
292
// the process still started up successfully...
293
return pi.dwProcessId;
296
::CloseHandle(hThread);
298
#if wxUSE_IPC && !defined(__WXWINCE__)
301
if ( !(flags & wxEXEC_SYNC) )
303
// clean up will be done when the process terminates
306
return pi.dwProcessId;
309
wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
310
wxCHECK_MSG( traits, -1, _T("no wxAppTraits in wxExecute()?") );
313
if ( !(flags & wxEXEC_NODISABLE) )
315
// disable all app windows while waiting for the child process to finish
316
cookie = traits->BeforeChildWaitLoop();
319
// wait until the child process terminates
320
while ( data->state )
322
// don't eat 100% of the CPU -- ugly but anything else requires
323
// real async IO which we don't have for the moment
326
// we must process messages or we'd never get wxWM_PROC_TERMINATED
327
traits->AlwaysYield();
330
if ( !(flags & wxEXEC_NODISABLE) )
332
// reenable disabled windows back
333
traits->AfterChildWaitLoop(cookie);
336
DWORD dwExitCode = data->dwExitCode;
339
// return the exit code
343
long wxExecuteHidden(wxChar **argv, int flags, wxProcess *handler)
356
return wxExecuteHidden(command, flags, handler);