]> git.saurik.com Git - wxWidgets.git/commitdiff
avoid needless Unicode<->MB conversions in Unix wxExecute(); simplify the code; provi...
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 23 Mar 2008 02:27:23 +0000 (02:27 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 23 Mar 2008 02:27:23 +0000 (02:27 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52722 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/utils.h
interface/utils.h
src/mac/corefoundation/utilsexc_base.cpp
src/msw/utilsexc.cpp
src/unix/utilsunx.cpp

index 95cf1a6ada8cc27ce91f02fb1340ca93505044a2..86824cee31aadbe6104a809b115766d240a3f088 100644 (file)
@@ -347,10 +347,15 @@ enum
 // If flags contain wxEXEC_SYNC, return -1 on failure and the exit code of the
 // process if everything was ok. Otherwise (i.e. if wxEXEC_ASYNC), return 0 on
 // failure and the PID of the launched process if ok.
-WXDLLIMPEXP_BASE long wxExecute(wxChar **argv, int flags = wxEXEC_ASYNC,
-                           wxProcess *process = (wxProcess *) NULL);
-WXDLLIMPEXP_BASE long wxExecute(const wxString& command, int flags = wxEXEC_ASYNC,
-                           wxProcess *process = (wxProcess *) NULL);
+WXDLLIMPEXP_BASE long wxExecute(wchar_t **argv,
+                                int flags = wxEXEC_ASYNC,
+                                wxProcess *process = NULL);
+WXDLLIMPEXP_BASE long wxExecute(char **argv,
+                                int flags = wxEXEC_ASYNC,
+                                wxProcess *process = NULL);
+WXDLLIMPEXP_BASE long wxExecute(const wxString& command,
+                                int flags = wxEXEC_ASYNC,
+                                wxProcess *process = NULL);
 
 // execute the command capturing its output into an array line by line, this is
 // always synchronous
index c29bbd8dfb6dce8a8c084c7d53acec618a861d21..0d6d74a2b727cded9a0eee0e585133b5d2c43f2f 100644 (file)
@@ -624,8 +624,10 @@ wxString wxGetUserHome(const wxString& user = "");
         array, any additional ones are the command parameters and the array must be
         terminated with a @NULL pointer.
     @param flags
-        Combination of bit masks wxEXEC_ASYNC,
-        wxEXEC_SYNC and wxEXEC_NOHIDE
+        Must include either wxEXEC_ASYNC or wxEXEC_SYNC and can also include
+        wxEXEC_NOHIDE, wxEXEC_MAKE_GROUP_LEADER (in either case) or
+        wxEXEC_NODISABLE and wxEXEC_NOEVENTS or wxEXEC_BLOCK, which is equal to
+        their combination, in wxEXEC_SYNC case.
     @param callback
         An optional pointer to wxProcess
 
@@ -633,18 +635,22 @@ wxString wxGetUserHome(const wxString& user = "");
 
     @header{wx/utils.h}
 */
-long wxExecute(const wxString& command, int sync = wxEXEC_ASYNC,
-                wxProcess* callback = NULL);
-wxPerl note: long wxExecute(char** argv,
-                            int flags = wxEXEC_ASYNC,
-                            wxProcess* callback = NULL);
-wxPerl note: long wxExecute(const wxString& command,
-                            wxArrayString& output,
-                            int flags = 0);
-wxPerl note: long wxExecute(const wxString& command,
-                            wxArrayString& output,
-                            wxArrayString& errors,
-                            int flags = 0);
+long wxExecute(const wxString& command,
+               int sync = wxEXEC_ASYNC,
+               wxProcess* callback = NULL);
+long wxExecute(char** argv,
+               int flags = wxEXEC_ASYNC,
+               wxProcess* callback = NULL);
+long wxExecute(wchar_t** argv,
+               int flags = wxEXEC_ASYNC,
+               wxProcess* callback = NULL);
+long wxExecute(const wxString& command,
+               wxArrayString& output,
+               int flags = 0);
+long wxExecute(const wxString& command,
+               wxArrayString& output,
+               wxArrayString& errors,
+               int flags = 0);
 //@}
 
 /**
index 878d2ed8142f69062b9d974033a4da7a4fa88d8b..41172aed2ded766d1928cb97b4f7e9a3889fd741 100644 (file)
@@ -1,6 +1,6 @@
 /////////////////////////////////////////////////////////////////////////////
 // Name:        mac/corefoundation/utilsexc_base.cpp
-// Purpose:     wxMacExecute
+// Purpose:     wxMacLaunch
 // Author:      Ryan Norton
 // Modified by:
 // Created:     2005-06-21
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
-//    wxMacExecute
+//    wxMacLaunch
 //
 // argv is the command line split up, with the application path first
 // flags are the flags from wxExecute
 // process is the process passed from wxExecute for pipe streams etc.
 // returns -1 on error for wxEXEC_SYNC and 0 on error for wxEXEC_ASYNC
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-long wxMacExecute(wxChar **argv,
-               int flags,
-               wxProcess *WXUNUSED(process))
+bool wxMacLaunch(char **argv)
 {
-    // Semi-macros used for return value of wxMacExecute
-    const long errorCode = ((flags & wxEXEC_SYNC) ? -1 : 0);
-    const long successCode = ((flags & wxEXEC_SYNC) ? 0 : -1); // fake PID
-
     // Obtains the number of arguments for determining the size of
     // the CFArray used to hold them
     CFIndex cfiCount = 0;
-    for(wxChar** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
+    for(char** argvcopy = argv; *argvcopy != NULL ; ++argvcopy)
     {
         ++cfiCount;
     }
@@ -75,8 +69,8 @@ long wxMacExecute(wxChar **argv,
     // to launch
     if(cfiCount == 0)
     {
-        wxLogDebug(wxT("wxMacExecute No file to launch!"));
-        return errorCode ;
+        wxLogDebug(wxT("wxMacLaunch No file to launch!"));
+        return false ;
     }
 
     // Path to bundle
@@ -94,8 +88,8 @@ long wxMacExecute(wxChar **argv,
     // Check for error from the CFURL
     if(!cfurlApp)
     {
-        wxLogDebug(wxT("wxMacExecute Can't open path: %s"), path.c_str());
-        return errorCode ;
+        wxLogDebug(wxT("wxMacLaunch Can't open path: %s"), path.c_str());
+        return false ;
     }
 
     // Create a CFBundle from the CFURL created earlier
@@ -106,9 +100,9 @@ long wxMacExecute(wxChar **argv,
     // at all (maybe a simple directory etc.)
     if(!cfbApp)
     {
-        wxLogDebug(wxT("wxMacExecute Bad bundle: %s"), path.c_str());
+        wxLogDebug(wxT("wxMacLaunch Bad bundle: %s"), path.c_str());
         CFRelease(cfurlApp);
-        return errorCode ;
+        return false ;
     }
 
     // Get the bundle type and make sure its an 'APPL' bundle
@@ -117,10 +111,10 @@ long wxMacExecute(wxChar **argv,
     CFBundleGetPackageInfo(cfbApp, &dwBundleType, &dwBundleCreator);
     if(dwBundleType != 'APPL')
     {
-        wxLogDebug(wxT("wxMacExecute Not an APPL bundle: %s"), path.c_str());
+        wxLogDebug(wxT("wxMacLaunch Not an APPL bundle: %s"), path.c_str());
         CFRelease(cfbApp);
         CFRelease(cfurlApp);
-        return errorCode ;
+        return false ;
     }
 
     // Create a CFArray for dealing with the command line
@@ -129,10 +123,10 @@ long wxMacExecute(wxChar **argv,
                                     cfiCount-1, &kCFTypeArrayCallBacks);
     if(!cfaFiles) //This should never happen
     {
-        wxLogDebug(wxT("wxMacExecute Could not create CFMutableArray"));
+        wxLogDebug(wxT("wxMacLaunch Could not create CFMutableArray"));
         CFRelease(cfbApp);
         CFRelease(cfurlApp);
-        return errorCode ;
+        return false ;
     }
 
     // Loop through command line arguments to the bundle,
@@ -184,7 +178,7 @@ long wxMacExecute(wxChar **argv,
         if(!cfurlCurrentFile)
         {
             wxLogDebug(
-                wxT("wxMacExecute Could not create CFURL for argument:%s"),
+                wxT("wxMacLaunch Could not create CFURL for argument:%s"),
                 *argv);
             continue;
         }
@@ -222,12 +216,12 @@ long wxMacExecute(wxChar **argv,
     // Check for error from LSOpenFromURLSpec
     if(status != noErr)
     {
-        wxLogDebug(wxT("wxMacExecute LSOpenFromURLSpec Error: %d"),
+        wxLogDebug(wxT("wxMacLaunch LSOpenFromURLSpec Error: %d"),
                    (int)status);
-        return errorCode ;
+        return false ;
     }
 
     // No error from LSOpenFromURLSpec, so app was launched
-    return successCode;
+    return true ;
 }
 
index 456594d8342ed25c11d7306afd86f979e783baea..2c39f64dcede61d6605fcd9b7b5489420d2f37af 100644 (file)
@@ -1012,9 +1012,11 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
     return dwExitCode;
 }
 
-long wxExecute(wxChar **argv, int flags, wxProcess *handler)
+template <typename CharType>
+long wxExecuteImpl(CharType **argv, int flags, wxProcess *handler)
 {
     wxString command;
+    command.reserve(1024);
 
     for ( ;; )
     {
@@ -1022,8 +1024,18 @@ long wxExecute(wxChar **argv, int flags, wxProcess *handler)
         if ( !*argv )
             break;
 
-        command += _T(' ');
+        command += ' ';
     }
 
     return wxExecute(command, flags, handler);
 }
+
+long wxExecute(char **argv, int flags, wxProcess *handler)
+{
+    return wxExecuteImpl(argv, flags, handler);
+}
+
+long wxExecute(wchar_t **argv, int flags, wxProcess *handler)
+{
+    return wxExecuteImpl(argv, flags, handler);
+}
index 086f538d064a7a45fb602d94a423c51210669dcc..823a853b25ead08b5bcb34639615a507c18dfd52 100644 (file)
@@ -263,106 +263,74 @@ int wxKill(long pid, wxSignal sig, wxKillError *rc, int flags)
     return err;
 }
 
-#define WXEXECUTE_NARGS   127
-
-#if defined(__DARWIN__)
-long wxMacExecute(wxChar **argv,
-               int flags,
-               wxProcess *process);
-#endif
-
-long wxExecute( const wxString& command, int flags, wxProcess *process )
+// Shutdown or reboot the PC
+bool wxShutdown(wxShutdownFlags wFlags)
 {
-    wxCHECK_MSG( !command.empty(), 0, wxT("can't exec empty command") );
-
-    wxLogTrace(wxT("exec"), wxT("Executing \"%s\""), command.c_str());
-
-#if wxUSE_THREADS
-    // fork() doesn't mix well with POSIX threads: on many systems the program
-    // deadlocks or crashes for some reason. Probably our code is buggy and
-    // doesn't do something which must be done to allow this to work, but I
-    // don't know what yet, so for now just warn the user (this is the least we
-    // can do) about it
-    wxASSERT_MSG( wxThread::IsMain(),
-                    _T("wxExecute() can be called only from the main thread") );
-#endif // wxUSE_THREADS
+    wxChar level;
+    switch ( wFlags )
+    {
+        case wxSHUTDOWN_POWEROFF:
+            level = _T('0');
+            break;
 
-    int argc = 0;
-    wxChar *argv[WXEXECUTE_NARGS];
-    wxString argument;
-    const wxChar *cptr = command.c_str();
-    wxChar quotechar = wxT('\0'); // is arg quoted?
-    bool escaped = false;
+        case wxSHUTDOWN_REBOOT:
+            level = _T('6');
+            break;
 
-    // split the command line in arguments
-    do
-    {
-        argument = wxEmptyString;
-        quotechar = wxT('\0');
+        default:
+            wxFAIL_MSG( _T("unknown wxShutdown() flag") );
+            return false;
+    }
 
-        // eat leading whitespace:
-        while ( wxIsspace(*cptr) )
-            cptr++;
+    return system(wxString::Format(_T("init %c"), level).mb_str()) == 0;
+}
 
-        if ( *cptr == wxT('\'') || *cptr == wxT('"') )
-            quotechar = *cptr++;
+// ----------------------------------------------------------------------------
+// wxStream classes to support IO redirection in wxExecute
+// ----------------------------------------------------------------------------
 
-        do
-        {
-            if ( *cptr == wxT('\\') && ! escaped )
-            {
-                escaped = true;
-                cptr++;
-                continue;
-            }
+#if HAS_PIPE_INPUT_STREAM
 
-            // all other characters:
-            argument += *cptr++;
-            escaped = false;
+bool wxPipeInputStream::CanRead() const
+{
+    if ( m_lasterror == wxSTREAM_EOF )
+        return false;
 
-            // have we reached the end of the argument?
-            if ( (*cptr == quotechar && ! escaped)
-                 || (quotechar == wxT('\0') && wxIsspace(*cptr))
-                 || *cptr == wxT('\0') )
-            {
-                wxASSERT_MSG( argc < WXEXECUTE_NARGS,
-                              wxT("too many arguments in wxExecute") );
+    // check if there is any input available
+    struct timeval tv;
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
 
-                argv[argc] = new wxChar[argument.length() + 1];
-                wxStrcpy(argv[argc], argument.c_str());
-                argc++;
+    const int fd = m_file->fd();
 
-                // if not at end of buffer, swallow last character:
-                if(*cptr)
-                    cptr++;
+    fd_set readfds;
 
-                break; // done with this one, start over
-            }
-        } while(*cptr);
-    } while(*cptr);
-    argv[argc] = NULL;
+    wxFD_ZERO(&readfds);
+    wxFD_SET(fd, &readfds);
 
-    long lRc;
-#if defined(__DARWIN__)
-    // wxMacExecute only executes app bundles.
-    // It returns an error code if the target is not an app bundle, thus falling
-    // through to the regular wxExecute for non app bundles.
-    lRc = wxMacExecute(argv, flags, process);
-    if( lRc != ((flags & wxEXEC_SYNC) ? -1 : 0))
-        return lRc;
-#endif
+    switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
+    {
+        case -1:
+            wxLogSysError(_("Impossible to get child process input"));
+            // fall through
 
-    // do execute the command
-    lRc = wxExecute(argv, flags, process);
+        case 0:
+            return false;
 
-    // clean up
-    argc = 0;
-    while( argv[argc] )
-        delete [] argv[argc++];
+        default:
+            wxFAIL_MSG(_T("unexpected select() return value"));
+            // still fall through
 
-    return lRc;
+        case 1:
+            // input available -- or maybe not, as select() returns 1 when a
+            // read() will complete without delay, but it could still not read
+            // anything
+            return !Eof();
+    }
 }
 
+#endif // HAS_PIPE_INPUT_STREAM
+
 // ----------------------------------------------------------------------------
 // wxShell
 // ----------------------------------------------------------------------------
@@ -396,79 +364,142 @@ bool wxShell(const wxString& command, wxArrayString& output)
     return wxExecute(wxMakeShellCommand(command), output);
 }
 
-// Shutdown or reboot the PC
-bool wxShutdown(wxShutdownFlags wFlags)
+namespace
 {
-    wxChar level;
-    switch ( wFlags )
+
+// helper class for storing arguments as char** array suitable for passing to
+// execvp(), whatever form they were passed to us
+class ArgsArray
+{
+public:
+    ArgsArray(const wxArrayString& args)
     {
-        case wxSHUTDOWN_POWEROFF:
-            level = _T('0');
-            break;
+        Init(args.size());
 
-        case wxSHUTDOWN_REBOOT:
-            level = _T('6');
-            break;
+        for ( int i = 0; i < m_argc; i++ )
+        {
+            m_argv[i] = wxStrdup(args[i]);
+        }
+    }
 
-        default:
-            wxFAIL_MSG( _T("unknown wxShutdown() flag") );
-            return false;
+    ArgsArray(wchar_t **wargv)
+    {
+        int argc = 0;
+        while ( *wargv++ )
+            argc++;
+
+        Init(argc);
+
+        for ( int i = 0; i < m_argc; i++ )
+        {
+            m_argv[i] = wxSafeConvertWX2MB(wargv[i]).release();
+        }
     }
 
-    return system(wxString::Format(_T("init %c"), level).mb_str()) == 0;
-}
+    ~ArgsArray()
+    {
+        for ( int i = 0; i < m_argc; i++ )
+        {
+            free(m_argv[i]);
+        }
+
+        delete [] m_argv;
+    }
+
+    operator char**() const { return m_argv; }
+
+private:
+    void Init(int argc)
+    {
+        m_argc = argc;
+        m_argv = new char *[m_argc + 1];
+        m_argv[m_argc] = NULL;
+    }
+
+    int m_argc;
+    char **m_argv;
+
+    DECLARE_NO_COPY_CLASS(ArgsArray);
+};
+
+} // anonymous namespace
 
 // ----------------------------------------------------------------------------
-// wxStream classes to support IO redirection in wxExecute
+// wxExecute implementations
 // ----------------------------------------------------------------------------
 
-#if HAS_PIPE_INPUT_STREAM
+#if defined(__DARWIN__)
+bool wxMacLaunch(char **argv);
+#endif
 
-bool wxPipeInputStream::CanRead() const
+long wxExecute(const wxString& command, int flags, wxProcess *process)
 {
-    if ( m_lasterror == wxSTREAM_EOF )
-        return false;
+    wxArrayString args;
 
-    // check if there is any input available
-    struct timeval tv;
-    tv.tv_sec = 0;
-    tv.tv_usec = 0;
+    const char *cptr = command.c_str();
 
-    const int fd = m_file->fd();
+    // split the command line in arguments
+    //
+    // TODO: combine this with wxCmdLineParser::ConvertStringToArgs(), it
+    //       doesn't do exactly the same thing right now but it's pretty close
+    //       and we shouldn't maintain 2 copies of this code
+    do
+    {
+        wxString argument;
+        char quotechar = '\0'; // is arg quoted?
+        bool escaped = false;
 
-    fd_set readfds;
+        // eat leading whitespace:
+        while ( wxIsspace(*cptr) )
+            cptr++;
 
-    wxFD_ZERO(&readfds);
-    wxFD_SET(fd, &readfds);
+        if ( *cptr == '\'' || *cptr == '"' )
+            quotechar = *cptr++;
 
-    switch ( select(fd + 1, &readfds, NULL, NULL, &tv) )
-    {
-        case -1:
-            wxLogSysError(_("Impossible to get child process input"));
-            // fall through
+        do
+        {
+            if ( *cptr == '\\' && !escaped )
+            {
+                escaped = true;
+                cptr++;
+                continue;
+            }
 
-        case 0:
-            return false;
+            // all other characters:
+            argument += *cptr++;
+            escaped = false;
 
-        default:
-            wxFAIL_MSG(_T("unexpected select() return value"));
-            // still fall through
+            // have we reached the end of the argument?
+            if ( (*cptr == quotechar && !escaped)
+                 || (quotechar == '\0' && wxIsspace(*cptr))
+                 || *cptr == '\0' )
+            {
+                args.push_back(argument);
 
-        case 1:
-            // input available -- or maybe not, as select() returns 1 when a
-            // read() will complete without delay, but it could still not read
-            // anything
-            return !Eof();
-    }
+                // if not at end of buffer, swallow last character:
+                if ( *cptr )
+                    cptr++;
+
+                break; // done with this one, start over
+            }
+        } while ( *cptr );
+    } while ( *cptr );
+
+    ArgsArray argv(args);
+
+    // do execute the command
+    return wxExecute(argv, flags, process);
 }
 
-#endif // HAS_PIPE_INPUT_STREAM
+long wxExecute(wchar_t **wargv, int flags, wxProcess *process)
+{
+    ArgsArray argv(wargv);
 
-// ----------------------------------------------------------------------------
-// wxExecute: the real worker function
-// ----------------------------------------------------------------------------
+    return wxExecute(argv, flags, process);
+}
 
-long wxExecute(wxChar **argv, int flags, wxProcess *process)
+// wxExecute: the real worker function
+long wxExecute(char **argv, int flags, wxProcess *process)
 {
     // for the sync execution, we return -1 to indicate failure, but for async
     // case we return 0 which is never a valid PID
@@ -479,38 +510,29 @@ long wxExecute(wxChar **argv, int flags, wxProcess *process)
 
     wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );
 
-#if wxUSE_UNICODE
-    int mb_argc = 0;
-    char *mb_argv[WXEXECUTE_NARGS];
+#if wxUSE_THREADS
+    // fork() doesn't mix well with POSIX threads: on many systems the program
+    // deadlocks or crashes for some reason. Probably our code is buggy and
+    // doesn't do something which must be done to allow this to work, but I
+    // don't know what yet, so for now just warn the user (this is the least we
+    // can do) about it
+    wxASSERT_MSG( wxThread::IsMain(),
+                    _T("wxExecute() can be called only from the main thread") );
+#endif // wxUSE_THREADS
 
-    while (argv[mb_argc])
+#if defined(__DARWIN__)
+    // wxMacLaunch() only executes app bundles and only does it asynchronously.
+    // It returns false if the target is not an app bundle, thus falling
+    // through to the regular code for non app bundles.
+    if ( !(flags & wxEXEC_SYNC) && wxMacLaunch(argv) )
     {
-        wxWX2MBbuf mb_arg = wxSafeConvertWX2MB(argv[mb_argc]);
-        mb_argv[mb_argc] = strdup(mb_arg);
-        mb_argc++;
+        // we don't have any PID to return so just make up something non null
+        return -1;
     }
-    mb_argv[mb_argc] = (char *) NULL;
-
-    // this macro will free memory we used above
-    #define ARGS_CLEANUP                                 \
-        for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
-            free(mb_argv[mb_argc])
-#else // ANSI
-    // no need for cleanup
-    #define ARGS_CLEANUP
-
-    wxChar **mb_argv = argv;
-#endif // Unicode/ANSI
-
-    // we want this function to work even if there is no wxApp so ensure that
-    // we have a valid traits pointer
-    wxConsoleAppTraits traitsConsole;
-    wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
-    if ( !traits )
-        traits = &traitsConsole;
-
-    // this struct contains all information which we pass to and from
-    // wxAppTraits methods
+#endif // __DARWIN__
+
+
+    // this struct contains all information which we use for housekeeping
     wxExecuteData execData;
     execData.flags = flags;
     execData.process = process;
@@ -520,8 +542,6 @@ long wxExecute(wxChar **argv, int flags, wxProcess *process)
     {
         wxLogError( _("Failed to execute '%s'\n"), *argv );
 
-        ARGS_CLEANUP;
-
         return ERROR_RETURN_CODE;
     }
 
@@ -536,8 +556,6 @@ long wxExecute(wxChar **argv, int flags, wxProcess *process)
         {
             wxLogError( _("Failed to execute '%s'\n"), *argv );
 
-            ARGS_CLEANUP;
-
             return ERROR_RETURN_CODE;
         }
     }
@@ -557,8 +575,6 @@ long wxExecute(wxChar **argv, int flags, wxProcess *process)
     {
         wxLogSysError( _("Fork failed") );
 
-        ARGS_CLEANUP;
-
         return ERROR_RETURN_CODE;
     }
     else if ( pid == 0 )  // we're in child
@@ -618,12 +634,11 @@ long wxExecute(wxChar **argv, int flags, wxProcess *process)
             pipeErr.Close();
         }
 
-        execvp (*mb_argv, mb_argv);
+        execvp(*argv, argv);
 
         fprintf(stderr, "execvp(");
-        // CS changed ppc to ppc_ as ppc is not available under mac os CW Mach-O
-        for ( char **ppc_ = mb_argv; *ppc_; ppc_++ )
-            fprintf(stderr, "%s%s", ppc_ == mb_argv ? "" : ", ", *ppc_);
+        for ( char **a = argv; *a; a++ )
+            fprintf(stderr, "%s%s", a == argv ? "" : ", ", *a);
         fprintf(stderr, ") failed with error %d!\n", errno);
 
         // there is no return after successful exec()
@@ -641,8 +656,6 @@ long wxExecute(wxChar **argv, int flags, wxProcess *process)
     }
     else // we're in parent
     {
-        ARGS_CLEANUP;
-
         // save it for WaitForChild() use
         execData.pid = pid;
 
@@ -685,6 +698,13 @@ long wxExecute(wxChar **argv, int flags, wxProcess *process)
             pipeErr.Close();
         }
 
+        // we want this function to work even if there is no wxApp so ensure
+        // that we have a valid traits pointer
+        wxConsoleAppTraits traitsConsole;
+        wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
+        if ( !traits )
+            traits = &traitsConsole;
+
         return traits->WaitForChild(execData);
     }
 
@@ -694,7 +714,6 @@ long wxExecute(wxChar **argv, int flags, wxProcess *process)
 }
 
 #undef ERROR_RETURN_CODE
-#undef ARGS_CLEANUP
 
 // ----------------------------------------------------------------------------
 // file and directory functions