~efargaspro/+junk/codeblocks-16.01-release

« back to all changes in this revision

Viewing changes to src/plugins/contrib/PythonPlugins/XmlRpcEmbedder/ExecHiddenMSW.cpp

  • Committer: damienlmoore at gmail
  • Date: 2016-02-02 02:43:22 UTC
  • Revision ID: damienlmoore@gmail.com-20160202024322-yql5qmtbwdyamdwd
Code::BlocksĀ 16.01

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// For compilers that support precompilation, includes "wx.h".
 
2
#include "ExecHiddenMSW.h"
 
3
 
 
4
#ifdef __WXMSW__
 
5
#include <wx/wxprec.h>
 
6
 
 
7
#ifdef __BORLANDC__
 
8
    #pragma hdrstop
 
9
#endif
 
10
 
 
11
#ifndef WX_PRECOMP
 
12
    #include <wx/utils.h>
 
13
    #include <wx/app.h>
 
14
    #include <wx/intl.h>
 
15
    #include <wx/log.h>
 
16
    #include <wx/module.h>
 
17
#endif
 
18
 
 
19
#include <wx/process.h>
 
20
 
 
21
#include <wx/apptrait.h>
 
22
 
 
23
 
 
24
#include <wx/msw/private.h>
 
25
 
 
26
#include <ctype.h>
 
27
 
 
28
#if !defined(__GNUWIN32__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
 
29
    #include <direct.h>
 
30
#ifndef __MWERKS__
 
31
    #include <dos.h>
 
32
#endif
 
33
#endif
 
34
 
 
35
#if defined(__GNUWIN32__)
 
36
    #include <sys/unistd.h>
 
37
    #include <sys/stat.h>
 
38
#endif
 
39
 
 
40
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
 
41
    #ifndef __UNIX__
 
42
        #include <io.h>
 
43
    #endif
 
44
 
 
45
    #ifndef __GNUWIN32__
 
46
        #include <shellapi.h>
 
47
    #endif
 
48
#endif
 
49
 
 
50
#include <stdio.h>
 
51
#include <stdlib.h>
 
52
#include <string.h>
 
53
#ifndef __WATCOMC__
 
54
    #if !(defined(_MSC_VER) && (_MSC_VER > 800))
 
55
        #include <errno.h>
 
56
    #endif
 
57
#endif
 
58
#include <stdarg.h>
 
59
 
 
60
#define wxWM_PROC_TERMINATED (WM_USER + 10000)
 
61
 
 
62
 
 
63
extern "C" WXDLLIMPEXP_BASE HWND
 
64
wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
 
65
 
 
66
static const wxChar *wxMSWEXEC_WNDCLASSNAME2 = wxT("_wxExecute_Internal_Class2");
 
67
static const wxChar *gs_classForHiddenWindow2 = NULL;
 
68
 
 
69
 
 
70
// structure describing the process we're being waiting for
 
71
struct wxExecuteData2
 
72
{
 
73
public:
 
74
    ~wxExecuteData2()
 
75
    {
 
76
        if ( !::CloseHandle(hProcess) )
 
77
        {
 
78
            wxLogLastError(wxT("CloseHandle(hProcess)"));
 
79
        }
 
80
    }
 
81
 
 
82
    HWND       hWnd;          // window to send wxWM_PROC_TERMINATED to
 
83
    HANDLE     hProcess;      // handle of the process
 
84
    DWORD      dwProcessId;   // pid of the process
 
85
    wxProcess *handler;
 
86
    DWORD      dwExitCode;    // the exit code of the process
 
87
    bool       state;         // set to false when the process finishes
 
88
};
 
89
 
 
90
LRESULT APIENTRY _EXPORT wxExecuteWindowCbk2(HWND hWnd, UINT message,
 
91
                                            WPARAM wParam, LPARAM lParam)
 
92
{
 
93
    if ( message == wxWM_PROC_TERMINATED )
 
94
    {
 
95
        DestroyWindow(hWnd);    // we don't need it any more
 
96
 
 
97
        wxExecuteData2 * const data = (wxExecuteData2 *)lParam;
 
98
        if ( data->handler )
 
99
        {
 
100
            data->handler->OnTerminate((int)data->dwProcessId,
 
101
                                       (int)data->dwExitCode);
 
102
        }
 
103
 
 
104
        if ( data->state )
 
105
        {
 
106
            // we're executing synchronously, tell the waiting thread
 
107
            // that the process finished
 
108
            data->state = 0;
 
109
        }
 
110
        else
 
111
        {
 
112
            // asynchronous execution - we should do the clean up
 
113
            delete data;
 
114
        }
 
115
 
 
116
        return 0;
 
117
    }
 
118
    else
 
119
    {
 
120
        return ::DefWindowProc(hWnd, message, wParam, lParam);
 
121
    }
 
122
}
 
123
 
 
124
 
 
125
// thread function for the thread monitoring the process termination
 
126
static DWORD __stdcall wxExecuteThread2(void *arg)
 
127
{
 
128
    wxExecuteData2 * const data = (wxExecuteData2 *)arg;
 
129
 
 
130
    if ( ::WaitForSingleObject(data->hProcess, INFINITE) != WAIT_OBJECT_0 )
 
131
    {
 
132
        wxLogDebug(_T("Waiting for the process termination failed!"));
 
133
    }
 
134
 
 
135
    // get the exit code
 
136
    if ( !::GetExitCodeProcess(data->hProcess, &data->dwExitCode) )
 
137
    {
 
138
        wxLogLastError(wxT("GetExitCodeProcess"));
 
139
    }
 
140
 
 
141
    wxASSERT_MSG( data->dwExitCode != STILL_ACTIVE,
 
142
                  wxT("process should have terminated") );
 
143
 
 
144
    // send a message indicating process termination to the window
 
145
    ::SendMessage(data->hWnd, wxWM_PROC_TERMINATED, 0, (LPARAM)data);
 
146
 
 
147
    return 0;
 
148
}
 
149
 
 
150
 
 
151
 
 
152
long wxExecuteHidden(const wxString& cmd, int flags, wxProcess *handler)
 
153
{
 
154
    wxCHECK_MSG( !cmd.empty(), 0, wxT("empty command in wxExecute") );
 
155
 
 
156
#if wxUSE_THREADS
 
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
 
163
 
 
164
    wxString command;
 
165
 
 
166
#if wxUSE_IPC
 
167
#endif // wxUSE_IPC
 
168
    {
 
169
        // no DDE
 
170
        command = cmd;
 
171
    }
 
172
 
 
173
    // the IO redirection is only supported with wxUSE_STREAMS
 
174
    BOOL redirect = FALSE;
 
175
 
 
176
    // create the process
 
177
    STARTUPINFO si;
 
178
    wxZeroMemory(si);
 
179
    si.cb = sizeof(si);
 
180
 
 
181
//DM ADDED CODE HERE
 
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) )
 
186
    {
 
187
        si.dwFlags |= STARTF_USESHOWWINDOW;
 
188
        si.wShowWindow = SW_HIDE;
 
189
    }
 
190
//END DM ADDED CODE HERE
 
191
 
 
192
    PROCESS_INFORMATION pi;
 
193
    DWORD dwFlags = CREATE_SUSPENDED;
 
194
 
 
195
#ifndef __WXWINCE__
 
196
    dwFlags |= CREATE_DEFAULT_ERROR_MODE ;
 
197
#else
 
198
    // we are assuming commands without spaces for now
 
199
    wxString moduleName = command.BeforeFirst(wxT(' '));
 
200
    wxString arguments = command.AfterFirst(wxT(' '));
 
201
#endif
 
202
 
 
203
    bool ok = ::CreateProcess
 
204
                (
 
205
                    // WinCE requires appname to be non null
 
206
                    // Win32 allows for null
 
207
#ifdef __WXWINCE__
 
208
                 (wxChar *)
 
209
                 moduleName.c_str(), // application name
 
210
                 (wxChar *)
 
211
                 arguments.c_str(),  // arguments
 
212
#else
 
213
                 NULL,               // application name (use only cmd line)
 
214
                 (wxChar *)
 
215
                 command.c_str(),    // full command line
 
216
#endif
 
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)
 
224
                 &pi                 // process info
 
225
                ) != 0;
 
226
 
 
227
    if ( !ok )
 
228
    {
 
229
 
 
230
        wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
 
231
 
 
232
        return flags & wxEXEC_SYNC ? -1 : 0;
 
233
    }
 
234
 
 
235
 
 
236
    // create a hidden window to receive notification about process
 
237
    // termination
 
238
    HWND hwnd = wxCreateHiddenWindow
 
239
                (
 
240
                    &gs_classForHiddenWindow2,
 
241
                    wxMSWEXEC_WNDCLASSNAME2,
 
242
                    (WNDPROC)wxExecuteWindowCbk2
 
243
                );
 
244
 
 
245
    wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") );
 
246
 
 
247
    // Alloc data
 
248
    wxExecuteData2 *data = new wxExecuteData2;
 
249
    data->hProcess    = pi.hProcess;
 
250
    data->dwProcessId = pi.dwProcessId;
 
251
    data->hWnd        = hwnd;
 
252
    data->state       = (flags & wxEXEC_SYNC) != 0;
 
253
    if ( flags & wxEXEC_SYNC )
 
254
    {
 
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;
 
258
    }
 
259
    else
 
260
    {
 
261
        // may be NULL or not
 
262
        data->handler = handler;
 
263
    }
 
264
 
 
265
    DWORD tid;
 
266
    HANDLE hThread = ::CreateThread(NULL,
 
267
                                    0,
 
268
                                    wxExecuteThread2,
 
269
                                    (void *)data,
 
270
                                    0,
 
271
                                    &tid);
 
272
 
 
273
    // resume process we created now - whether the thread creation succeeded or
 
274
    // not
 
275
    if ( ::ResumeThread(pi.hThread) == (DWORD)-1 )
 
276
    {
 
277
        // ignore it - what can we do?
 
278
        wxLogLastError(wxT("ResumeThread in wxExecute"));
 
279
    }
 
280
 
 
281
    // close unneeded handle
 
282
    if ( !::CloseHandle(pi.hThread) )
 
283
        wxLogLastError(wxT("CloseHandle(hThread)"));
 
284
 
 
285
    if ( !hThread )
 
286
    {
 
287
        wxLogLastError(wxT("CreateThread in wxExecute"));
 
288
 
 
289
        DestroyWindow(hwnd);
 
290
        delete data;
 
291
 
 
292
        // the process still started up successfully...
 
293
        return pi.dwProcessId;
 
294
    }
 
295
 
 
296
    ::CloseHandle(hThread);
 
297
 
 
298
#if wxUSE_IPC && !defined(__WXWINCE__)
 
299
#endif // wxUSE_IPC
 
300
 
 
301
    if ( !(flags & wxEXEC_SYNC) )
 
302
    {
 
303
        // clean up will be done when the process terminates
 
304
 
 
305
        // return the pid
 
306
        return pi.dwProcessId;
 
307
    }
 
308
 
 
309
    wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
 
310
    wxCHECK_MSG( traits, -1, _T("no wxAppTraits in wxExecute()?") );
 
311
 
 
312
    void *cookie = NULL;
 
313
    if ( !(flags & wxEXEC_NODISABLE) )
 
314
    {
 
315
        // disable all app windows while waiting for the child process to finish
 
316
        cookie = traits->BeforeChildWaitLoop();
 
317
    }
 
318
 
 
319
    // wait until the child process terminates
 
320
    while ( data->state )
 
321
    {
 
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
 
324
        ::Sleep(50);
 
325
 
 
326
        // we must process messages or we'd never get wxWM_PROC_TERMINATED
 
327
        traits->AlwaysYield();
 
328
    }
 
329
 
 
330
    if ( !(flags & wxEXEC_NODISABLE) )
 
331
    {
 
332
        // reenable disabled windows back
 
333
        traits->AfterChildWaitLoop(cookie);
 
334
    }
 
335
 
 
336
    DWORD dwExitCode = data->dwExitCode;
 
337
    delete data;
 
338
 
 
339
    // return the exit code
 
340
    return dwExitCode;
 
341
}
 
342
 
 
343
long wxExecuteHidden(wxChar **argv, int flags, wxProcess *handler)
 
344
{
 
345
    wxString command;
 
346
 
 
347
    for ( ;; )
 
348
    {
 
349
        command += *argv++;
 
350
        if ( !*argv )
 
351
            break;
 
352
 
 
353
        command += _T(' ');
 
354
    }
 
355
 
 
356
    return wxExecuteHidden(command, flags, handler);
 
357
}
 
358
 
 
359
#endif /*__WXMSW__*/