1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/os2/utilsexec.cpp
3// Purpose:     Various utilities
4// Author:      David Webster
5// Modified by:
6// Created:     10/17/99
7// RCS-ID:      $Id: utilsexc.cpp 38920 2006-04-26 08:21:31Z ABX $
8// Copyright:   (c) David Webster
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifndef WX_PRECOMP
16    #include "wx/utils.h"
17    #include "wx/app.h"
18    #include "wx/intl.h"
19    #include "wx/log.h"
20#endif
21
22#include "wx/process.h"
23
24#include "wx/os2/private.h"
25
26#define PURE_32
27#ifndef __EMX__
28    #include <upm.h>
29    #ifndef __WATCOMC__
30        #include <netcons.h>
31        #include <netbios.h>
32    #endif
33#endif
34
35#include <ctype.h>
36#ifdef __EMX__
37#include <dirent.h>
38#endif
39
40#include <sys/stat.h>
41#include <io.h>
42
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <errno.h>
47#include <stdarg.h>
48
49
50// this message is sent when the process we're waiting for terminates
51#define wxWM_PROC_TERMINATED (WM_USER + 10000)
52
53#ifndef NO_ERROR
54#  define NO_ERROR  0
55#endif
56
57// structure describing the process we're being waiting for
58struct wxExecuteData
59{
60public:
61    ~wxExecuteData()
62    {
63//         cout << "Closing thread: " << endl;
64        DosExit(EXIT_PROCESS, 0);
65    }
66
67    HWND         hWnd;          // window to send wxWM_PROC_TERMINATED to [not used]
68    RESULTCODES  vResultCodes;
69    wxProcess*   pHandler;
70    ULONG        ulExitCode;    // the exit code of the process
71    bool         bState;        // set to false when the process finishes
72};
73
74static ULONG wxExecuteThread(wxExecuteData* pData)
75{
76    ULONG ulRc;
77    PID   vPidChild;
78
79//     cout << "Executing thread: " << endl;
80
81    ulRc = ::DosWaitChild( DCWA_PROCESSTREE
82                          ,DCWW_NOWAIT
83                          ,&pData->vResultCodes
84                          ,&vPidChild
85                          ,pData->vResultCodes.codeTerminate // process PID to look at
86                         );
87    if (ulRc != NO_ERROR)
88    {
89        wxLogLastError(wxT("DosWaitChild"));
90    }
91    delete pData;
92    return 0;
93}
94
95// window procedure of a hidden window which is created just to receive
96// the notification message when a process exits
97MRESULT APIENTRY wxExecuteWindowCbk( HWND   hWnd,
98                                     ULONG  ulMessage,
99                                     MPARAM WXUNUSED(wParam),
100                                     MPARAM lParam)
101{
102    if (ulMessage == wxWM_PROC_TERMINATED)
103    {
104        wxExecuteData*              pData = (wxExecuteData *)lParam;
105
106        if (pData->pHandler)
107        {
108            pData->pHandler->OnTerminate( (int)pData->vResultCodes.codeTerminate
109                                         ,(int)pData->vResultCodes.codeResult
110                                        );
111        }
112
113        if (pData->bState)
114        {
115            // we're executing synchronously, tell the waiting thread
116            // that the process finished
117            pData->bState = 0;
118        }
119        else
120        {
121            // asynchronous execution - we should do the clean up
122            delete pData;
123        }
124        ::WinDestroyWindow(hWnd);    // we don't need it any more
125    }
126    return 0;
127}
128
129long wxExecute( const wxString& rCommand,
130                int flags,
131                wxProcess* pHandler)
132{
133    if (rCommand.empty())
134    {
135//         cout << "empty command in wxExecute." << endl;
136        return 0;
137    }
138
139    // create the process
140    UCHAR                           vLoadError[CCHMAXPATH] = {0};
141    RESULTCODES                     vResultCodes = {0};
142    ULONG                           ulExecFlag;
143    PSZ                             zArgs = NULL;
144    PSZ                             zEnvs = NULL;
145    APIRET                          rc;
146    TID                             vTID;
147
148    if (flags & wxEXEC_SYNC)
149        ulExecFlag = EXEC_SYNC;
150    else
151        ulExecFlag = EXEC_ASYNCRESULT;
152
153    rc = ::DosExecPgm( (PCHAR)vLoadError
154                      ,sizeof(vLoadError)
155                      ,ulExecFlag
156                      ,zArgs
157                      ,zEnvs
158                      ,&vResultCodes
159                      ,(PSZ)rCommand.c_str()
160                     );
161    if (rc != NO_ERROR)
162    {
163        wxLogSysError(_("Execution of command '%s' failed with error: %ul"), rCommand.c_str(), rc);
164        return 0;
165    }
166//     cout << "Executing: " << rCommand.c_str() << endl;
167    // Alloc data
168    wxExecuteData*                  pData = new wxExecuteData;
169
170    pData->vResultCodes = vResultCodes;
171    pData->hWnd         = NULLHANDLE;
172    pData->bState       = (flags & wxEXEC_SYNC) != 0;
173    if (flags & wxEXEC_SYNC)
174    {
175        wxASSERT_MSG(!pHandler, wxT("wxProcess param ignored for sync execution"));
176        pData->pHandler = NULL;
177    }
178    else
179    {
180        // may be NULL or not
181        pData->pHandler = pHandler;
182    }
183
184    rc = ::DosCreateThread( &vTID
185                           ,(PFNTHREAD)&wxExecuteThread
186                           ,(ULONG)pData
187                           ,CREATE_READY|STACK_SPARSE
188                           ,8192
189                          );
190    if (rc != NO_ERROR)
191    {
192        wxLogLastError(wxT("CreateThread in wxExecute"));
193        delete pData;
194
195        // the process still started up successfully...
196        return vResultCodes.codeTerminate;
197    }
198    if (!(flags & wxEXEC_SYNC))
199    {
200        // return the pid
201        // warning: don't exit your app unless you actively
202        // kill and cleanup you child processes
203        // Maybe detach the process here???
204        // If cmd.exe need to pass DETACH to detach the process here
205        return vResultCodes.codeTerminate;
206    }
207
208    // waiting until command executed
209    ::DosWaitThread(&vTID, DCWW_WAIT);
210
211    ULONG ulExitCode = pData->vResultCodes.codeResult;
212    delete pData;
213
214    // return the exit code
215    return (long)ulExitCode;
216}
217
218long wxExecute(
219  char**                            ppArgv
220, int                               flags
221, wxProcess*                        pHandler
222)
223{
224    wxString                        sCommand;
225
226    while (*ppArgv != NULL)
227    {
228        wxString                    sArg((wxChar*)(*ppArgv++));
229
230
231        sCommand << sArg.c_str() << ' ';
232    }
233    sCommand.RemoveLast();
234    return wxExecute( sCommand
235                     ,flags
236                     ,pHandler
237                    );
238}
239
240bool wxGetFullHostName( wxChar* zBuf, int nMaxSize)
241{
242    return wxGetHostName( zBuf, nMaxSize );
243}
244