]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/utilsexc.cpp
wxWizardPage(Simple) can do two-phase creation now
[wxWidgets.git] / src / msw / utilsexc.cpp
index 7bfdc8234ab6738053deecf5c2b3920d16fd7384..21b74439c33f7289e21634a72d3428fe4a1c592e 100644 (file)
@@ -45,7 +45,7 @@
 
 #include <ctype.h>
 
-#if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__)
+#if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__)
     #include <direct.h>
 #ifndef __MWERKS__
     #include <dos.h>
@@ -57,7 +57,7 @@
     #include <sys/stat.h>
 #endif
 
-#if defined(__WIN32__) && !defined(__WXWINE__)
+#if defined(__WIN32__) && !defined(__WXWINE__) && !defined(__WXMICROWIN__)
 #include <io.h>
 
 #ifndef __GNUWIN32__
@@ -259,8 +259,10 @@ size_t wxPipeOutputStream::OnSysWrite(const void *buffer, size_t len)
 
 #ifdef __WIN32__
 
-static DWORD wxExecuteThread(wxExecuteData *data)
+static DWORD __stdcall wxExecuteThread(void *arg)
 {
+    wxExecuteData *data = (wxExecuteData*)arg;
+
     WaitForSingleObject(data->hProcess, INFINITE);
 
     // get the exit code
@@ -315,7 +317,50 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message,
 }
 #endif // Win32
 
-long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
+#if wxUSE_IPC
+
+// connect to the given server via DDE and ask it to execute the command
+static bool wxExecuteDDE(const wxString& ddeServer,
+                         const wxString& ddeTopic,
+                         const wxString& ddeCommand)
+{
+    bool ok;
+
+    wxDDEClient client;
+    wxConnectionBase *conn = client.MakeConnection(_T(""),
+                                                   ddeServer,
+                                                   ddeTopic);
+    if ( !conn )
+    {
+        ok = FALSE;
+    }
+    else // connected to DDE server
+    {
+        // the added complication here is that although most
+        // programs use XTYP_EXECUTE for their DDE API, some
+        // important ones - like IE and other MS stuff - use
+        // XTYP_REQUEST!
+        //
+        // so we try it first and then the other one if it
+        // failed
+        {
+            wxLogNull noErrors;
+            ok = conn->Request(ddeCommand) != NULL;
+        }
+
+        if ( !ok )
+        {
+            // now try execute - but show the errors
+            ok = conn->Execute(ddeCommand);
+        }
+    }
+
+    return ok;
+}
+
+#endif // wxUSE_IPC
+
+long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
 {
     wxCHECK_MSG( !!cmd, 0, wxT("empty command in wxExecute") );
 
@@ -334,6 +379,11 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
     static const size_t lenDdePrefix = 7;   // strlen("WX_DDE:")
     if ( cmd.Left(lenDdePrefix) == _T("WX_DDE#") )
     {
+        // speed up the concatenations below
+        ddeServer.reserve(256);
+        ddeTopic.reserve(256);
+        ddeCommand.reserve(256);
+
         const wxChar *p = cmd.c_str() + 7;
         while ( *p && *p != _T('#') )
         {
@@ -385,27 +435,21 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
             ddeCommand += *p++;
         }
 
-        // maybe we don't have to launch the DDE server at all - if it is
-        // already running, for example
-        wxDDEClient client;
-        wxLogNull nolog;
-        wxConnectionBase *conn = client.MakeConnection(_T(""),
-                                                       ddeServer,
-                                                       ddeTopic);
-        if ( conn )
+        // if we want to just launch the program and not wait for its
+        // termination, try to execute DDE command right now, it can succeed if
+        // the process is already running - but as it fails if it's not
+        // running, suppress any errors it might generate
+        if ( !(flags & wxEXEC_SYNC) )
         {
-            // FIXME we don't check the return code as for some strange reason
-            //       it will sometimes be FALSE - it is probably a bug in our
-            //       DDE code but I don't see anything wrong there
-            (void)conn->Execute(ddeCommand);
-
-            // ok, the command executed - return value indicating success,
-            // making it up for async case as we really don't have any way to
-            // get the real PID of the DDE server here
-            return sync ? 0 : -1;
+            wxLogNull noErrors;
+            if ( wxExecuteDDE(ddeServer, ddeTopic, ddeCommand) )
+            {
+                // a dummy PID - this is a hack, of course, but it's well worth
+                // it as we don't open a new server each time we're called
+                // which would be quite bad
+                return -1;
+            }
         }
-        //else: couldn't establish DDE conversation, now try launching the app
-        //      and sending the DDE request again
     }
     else
 #endif // wxUSE_IPC
@@ -440,8 +484,9 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
         {
             wxLogSysError(_("Can't create the inter-process read pipe"));
 
-            // indicate failure in both cases
-            return sync ? -1 : 0;
+            // indicate failure: we need to return different error code
+            // depending on the sync flag
+            return flags & wxEXEC_SYNC ? -1 : 0;
         }
 
         // and a stdout one
@@ -452,7 +497,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
 
             wxLogSysError(_("Can't create the inter-process write pipe"));
 
-            return sync ? -1 : 0;
+            return flags & wxEXEC_SYNC ? -1 : 0;
         }
 
         (void)::CreatePipe(&hpipeStderr[0], &hpipeStderr[1], &security, 0);
@@ -469,15 +514,20 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
 #if wxUSE_STREAMS
     if ( redirect )
     {
-        // when the std IO is redirected, we don't show the (console) process
-        // window
-        si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+        si.dwFlags = STARTF_USESTDHANDLES;
 
         si.hStdInput = hpipeStdin[0];
         si.hStdOutput = hpipeStdout[1];
         si.hStdError = hpipeStderr[1];
 
-        si.wShowWindow = SW_HIDE;
+        // when the std IO is redirected, we don't show the (console) process
+        // window by default, but this can be overridden by the caller by
+        // specifying wxEXEC_NOHIDE flag
+        if ( !(flags & wxEXEC_NOHIDE) )
+        {
+            si.dwFlags |= STARTF_USESHOWWINDOW;
+            si.wShowWindow = SW_HIDE;
+        }
 
         // we must duplicate the handle to the write side of stdin pipe to make
         // it non inheritable: indeed, we must close hpipeStdin[1] before
@@ -543,7 +593,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
 
         wxLogSysError(_("Execution of command '%s' failed"), command.c_str());
 
-        return sync ? -1 : 0;
+        return flags & wxEXEC_SYNC ? -1 : 0;
     }
 
 #if wxUSE_STREAMS
@@ -588,8 +638,8 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
     data->hProcess    = pi.hProcess;
     data->dwProcessId = pi.dwProcessId;
     data->hWnd        = hwnd;
-    data->state       = sync;
-    if ( sync )
+    data->state       = (flags & wxEXEC_SYNC) != 0;
+    if ( flags & wxEXEC_SYNC )
     {
         // handler may be !NULL for capturing program output, but we don't use
         // it wxExecuteData struct in this case
@@ -604,7 +654,7 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
     DWORD tid;
     HANDLE hThread = ::CreateThread(NULL,
                                     0,
-                                    (LPTHREAD_START_ROUTINE)wxExecuteThread,
+                                    wxExecuteThread,
                                     (void *)data,
                                     0,
                                     &tid);
@@ -637,45 +687,38 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
 #if wxUSE_IPC
     // second part of DDE hack: now establish the DDE conversation with the
     // just launched process
-    if ( !!ddeServer )
+    if ( !ddeServer.empty() )
     {
-        wxDDEClient client;
-        wxConnectionBase *conn;
-
+        bool ok;
+
+        // give the process the time to init itself
+        //
+        // we use a very big timeout hoping that WaitForInputIdle() will return
+        // much sooner, but not INFINITE just in case the process hangs
+        // completely - like this we will regain control sooner or later
+        switch ( ::WaitForInputIdle(pi.hProcess, 10000 /* 10 seconds */) )
         {
-            // try doing it the first time without error messages
-            wxLogNull nolog;
+            default:
+                wxFAIL_MSG( _T("unexpected WaitForInputIdle() return code") );
+                // fall through
 
-            conn = client.MakeConnection(_T(""), ddeServer, ddeTopic);
-        }
+            case -1:
+                wxLogLastError(_T("WaitForInputIdle() in wxExecute"));
 
-        if ( !conn )
-        {
-            // give the app some time to initialize itself: in fact, a common
-            // reason for failure is that we tried to open DDE conversation too
-            // soon (before the app had time to setup its DDE server), so wait
-            // a bit and try again
-            ::Sleep(2000);
-
-            wxConnectionBase *conn = client.MakeConnection(_T(""),
-                                                           ddeServer,
-                                                           ddeTopic);
-            if ( !conn )
-            {
-                wxLogError(_("Couldn't launch DDE server '%s'."), command.c_str());
-            }
-        }
+            case WAIT_TIMEOUT:
+                wxLogDebug(_T("Timeout too small in WaitForInputIdle"));
 
-        if ( conn )
-        {
-            // FIXME just as above we don't check Execute() return code
-            wxLogNull nolog;
-            (void)conn->Execute(ddeCommand);
+                ok = FALSE;
+                break;
+
+            case 0:
+                // ok, process ready to accept DDE requests
+                ok = wxExecuteDDE(ddeServer, ddeTopic, ddeCommand);
         }
     }
 #endif // wxUSE_IPC
 
-    if ( !sync )
+    if ( !(flags & wxEXEC_SYNC) )
     {
         // clean up will be done when the process terminates
 
@@ -692,7 +735,11 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
 #endif // wxUSE_GUI
 
     while ( data->state )
+    {
+        // don't take 100% of the CPU
+        ::Sleep(500);
         wxYield();
+    }
 
 #if wxUSE_GUI
     }
@@ -705,21 +752,24 @@ long wxExecute(const wxString& cmd, bool sync, wxProcess *handler)
     return dwExitCode;
 #else // Win16
     long instanceID = WinExec((LPCSTR) WXSTRINGCAST command, SW_SHOW);
-    if (instanceID < 32) return(0);
+    if (instanceID < 32)
+        return flags & wxEXEC_SYNC ? -1 : 0;
 
-    if (sync) {
+    if ( flags & wxEXEC_SYNC )
+    {
         int running;
-        do {
+        do
+        {
             wxYield();
             running = GetModuleUsage((HINSTANCE)instanceID);
         } while (running);
     }
 
-    return(instanceID);
+    return instanceID;
 #endif // Win16/32
 }
 
-long wxExecute(char **argv, bool sync, wxProcess *handler)
+long wxExecute(char **argv, int flags, wxProcess *handler)
 {
     wxString command;
 
@@ -730,43 +780,6 @@ long wxExecute(char **argv, bool sync, wxProcess *handler)
 
     command.RemoveLast();
 
-    return wxExecute(command, sync, handler);
+    return wxExecute(command, flags, handler);
 }
 
-#if wxUSE_GUI
-
-// ----------------------------------------------------------------------------
-// Metafile helpers
-// ----------------------------------------------------------------------------
-
-extern void PixelToHIMETRIC(LONG *x, LONG *y)
-{
-    ScreenHDC hdcRef;
-
-    int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
-        iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
-        iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
-        iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
-
-    *x *= (iWidthMM * 100);
-    *x /= iWidthPels;
-    *y *= (iHeightMM * 100);
-    *y /= iHeightPels;
-}
-
-extern void HIMETRICToPixel(LONG *x, LONG *y)
-{
-    ScreenHDC hdcRef;
-
-    int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
-        iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
-        iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
-        iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
-
-    *x *= iWidthPels;
-    *x /= (iWidthMM * 100);
-    *y *= iHeightPels;
-    *y /= (iHeightMM * 100);
-}
-
-#endif // wxUSE_GUI