[Win32] Fix the asynchronous g_spawn* to return the process handle of the
authorTor Lillqvist <tml@iki.fi>
Sun, 17 Nov 2002 23:30:32 +0000 (23:30 +0000)
committerTor Lillqvist <tml@src.gnome.org>
Sun, 17 Nov 2002 23:30:32 +0000 (23:30 +0000)
2002-11-18  Tor Lillqvist  <tml@iki.fi>

[Win32] Fix the asynchronous g_spawn* to return the process handle
of the started program properly. (Note: not the process id. The
spawn*() functions in the C runtime return the created process's
handle. There doesn't seem to be any way to get the process id of
a child process if you have the handle. But then, the process
handle usually is more useful anyway.)

* glib/gspawn-win32-helper.c (WinMain): If the spawning of the
child process succeeded, and if asynchronous spawn (P_NOWAIT),
write the result handle up to the parent process, waiting to read
it in do_spawn_with_pipes().

* glib/gspawn-win32.c (do_spawn): Use return value from spawning
the helper. If it is -1 the helper wasn't found or couldn't be run
for some reason. Otherwise it is the helper's process handle.

(g_spawn_async_with_pipes): Pass the child_pid parameter on to
do_spawn_with_pipes().

(do_spawn_with_pipes): Take also a child_pid parameter. If
do_spawn() returned -1, fail immediately. Otherwise make the
handle passed to us by the helper process into a handle valid in
this process by calling DuplicateHandle().

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
glib/gspawn-win32-helper.c
glib/gspawn-win32.c

index e8a319e..3da17ff 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2002-11-18  Tor Lillqvist  <tml@iki.fi>
+
+       [Win32] Fix the asynchronous g_spawn* to return the process handle
+       of the started program properly. (Note: not the process id. The
+       spawn*() functions in the C runtime return the created process's
+       handle. There doesn't seem to be any way to get the process id of
+       a child process if you have the handle. But then, the process
+       handle usually is more useful anyway.)
+
+       * glib/gspawn-win32-helper.c (WinMain): If the spawning of the
+       child process succeeded, and if asynchronous spawn (P_NOWAIT),
+       write the result handle up to the parent process, waiting to read
+       it in do_spawn_with_pipes().
+
+       * glib/gspawn-win32.c (do_spawn): Use return value from spawning
+       the helper. If it is -1 the helper wasn't found or couldn't be run
+       for some reason. Otherwise it is the helper's process handle.
+
+       (g_spawn_async_with_pipes): Pass the child_pid parameter on to
+       do_spawn_with_pipes().
+
+       (do_spawn_with_pipes): Take also a child_pid parameter. If
+       do_spawn() returned -1, fail immediately. Otherwise make the
+       handle passed to us by the helper process into a handle valid in
+       this process by calling DuplicateHandle().
+
 2002-11-17  Tor Lillqvist  <tml@iki.fi>
 
        * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
index e8a319e..3da17ff 100644 (file)
@@ -1,3 +1,29 @@
+2002-11-18  Tor Lillqvist  <tml@iki.fi>
+
+       [Win32] Fix the asynchronous g_spawn* to return the process handle
+       of the started program properly. (Note: not the process id. The
+       spawn*() functions in the C runtime return the created process's
+       handle. There doesn't seem to be any way to get the process id of
+       a child process if you have the handle. But then, the process
+       handle usually is more useful anyway.)
+
+       * glib/gspawn-win32-helper.c (WinMain): If the spawning of the
+       child process succeeded, and if asynchronous spawn (P_NOWAIT),
+       write the result handle up to the parent process, waiting to read
+       it in do_spawn_with_pipes().
+
+       * glib/gspawn-win32.c (do_spawn): Use return value from spawning
+       the helper. If it is -1 the helper wasn't found or couldn't be run
+       for some reason. Otherwise it is the helper's process handle.
+
+       (g_spawn_async_with_pipes): Pass the child_pid parameter on to
+       do_spawn_with_pipes().
+
+       (do_spawn_with_pipes): Take also a child_pid parameter. If
+       do_spawn() returned -1, fail immediately. Otherwise make the
+       handle passed to us by the helper process into a handle valid in
+       this process by calling DuplicateHandle().
+
 2002-11-17  Tor Lillqvist  <tml@iki.fi>
 
        * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
index e8a319e..3da17ff 100644 (file)
@@ -1,3 +1,29 @@
+2002-11-18  Tor Lillqvist  <tml@iki.fi>
+
+       [Win32] Fix the asynchronous g_spawn* to return the process handle
+       of the started program properly. (Note: not the process id. The
+       spawn*() functions in the C runtime return the created process's
+       handle. There doesn't seem to be any way to get the process id of
+       a child process if you have the handle. But then, the process
+       handle usually is more useful anyway.)
+
+       * glib/gspawn-win32-helper.c (WinMain): If the spawning of the
+       child process succeeded, and if asynchronous spawn (P_NOWAIT),
+       write the result handle up to the parent process, waiting to read
+       it in do_spawn_with_pipes().
+
+       * glib/gspawn-win32.c (do_spawn): Use return value from spawning
+       the helper. If it is -1 the helper wasn't found or couldn't be run
+       for some reason. Otherwise it is the helper's process handle.
+
+       (g_spawn_async_with_pipes): Pass the child_pid parameter on to
+       do_spawn_with_pipes().
+
+       (do_spawn_with_pipes): Take also a child_pid parameter. If
+       do_spawn() returned -1, fail immediately. Otherwise make the
+       handle passed to us by the helper process into a handle valid in
+       this process by calling DuplicateHandle().
+
 2002-11-17  Tor Lillqvist  <tml@iki.fi>
 
        * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
index e8a319e..3da17ff 100644 (file)
@@ -1,3 +1,29 @@
+2002-11-18  Tor Lillqvist  <tml@iki.fi>
+
+       [Win32] Fix the asynchronous g_spawn* to return the process handle
+       of the started program properly. (Note: not the process id. The
+       spawn*() functions in the C runtime return the created process's
+       handle. There doesn't seem to be any way to get the process id of
+       a child process if you have the handle. But then, the process
+       handle usually is more useful anyway.)
+
+       * glib/gspawn-win32-helper.c (WinMain): If the spawning of the
+       child process succeeded, and if asynchronous spawn (P_NOWAIT),
+       write the result handle up to the parent process, waiting to read
+       it in do_spawn_with_pipes().
+
+       * glib/gspawn-win32.c (do_spawn): Use return value from spawning
+       the helper. If it is -1 the helper wasn't found or couldn't be run
+       for some reason. Otherwise it is the helper's process handle.
+
+       (g_spawn_async_with_pipes): Pass the child_pid parameter on to
+       do_spawn_with_pipes().
+
+       (do_spawn_with_pipes): Take also a child_pid parameter. If
+       do_spawn() returned -1, fail immediately. Otherwise make the
+       handle passed to us by the helper process into a handle valid in
+       this process by calling DuplicateHandle().
+
 2002-11-17  Tor Lillqvist  <tml@iki.fi>
 
        * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
index e8a319e..3da17ff 100644 (file)
@@ -1,3 +1,29 @@
+2002-11-18  Tor Lillqvist  <tml@iki.fi>
+
+       [Win32] Fix the asynchronous g_spawn* to return the process handle
+       of the started program properly. (Note: not the process id. The
+       spawn*() functions in the C runtime return the created process's
+       handle. There doesn't seem to be any way to get the process id of
+       a child process if you have the handle. But then, the process
+       handle usually is more useful anyway.)
+
+       * glib/gspawn-win32-helper.c (WinMain): If the spawning of the
+       child process succeeded, and if asynchronous spawn (P_NOWAIT),
+       write the result handle up to the parent process, waiting to read
+       it in do_spawn_with_pipes().
+
+       * glib/gspawn-win32.c (do_spawn): Use return value from spawning
+       the helper. If it is -1 the helper wasn't found or couldn't be run
+       for some reason. Otherwise it is the helper's process handle.
+
+       (g_spawn_async_with_pipes): Pass the child_pid parameter on to
+       do_spawn_with_pipes().
+
+       (do_spawn_with_pipes): Take also a child_pid parameter. If
+       do_spawn() returned -1, fail immediately. Otherwise make the
+       handle passed to us by the helper process into a handle valid in
+       this process by calling DuplicateHandle().
+
 2002-11-17  Tor Lillqvist  <tml@iki.fi>
 
        * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
index e8a319e..3da17ff 100644 (file)
@@ -1,3 +1,29 @@
+2002-11-18  Tor Lillqvist  <tml@iki.fi>
+
+       [Win32] Fix the asynchronous g_spawn* to return the process handle
+       of the started program properly. (Note: not the process id. The
+       spawn*() functions in the C runtime return the created process's
+       handle. There doesn't seem to be any way to get the process id of
+       a child process if you have the handle. But then, the process
+       handle usually is more useful anyway.)
+
+       * glib/gspawn-win32-helper.c (WinMain): If the spawning of the
+       child process succeeded, and if asynchronous spawn (P_NOWAIT),
+       write the result handle up to the parent process, waiting to read
+       it in do_spawn_with_pipes().
+
+       * glib/gspawn-win32.c (do_spawn): Use return value from spawning
+       the helper. If it is -1 the helper wasn't found or couldn't be run
+       for some reason. Otherwise it is the helper's process handle.
+
+       (g_spawn_async_with_pipes): Pass the child_pid parameter on to
+       do_spawn_with_pipes().
+
+       (do_spawn_with_pipes): Take also a child_pid parameter. If
+       do_spawn() returned -1, fail immediately. Otherwise make the
+       handle passed to us by the helper process into a handle valid in
+       this process by calling DuplicateHandle().
+
 2002-11-17  Tor Lillqvist  <tml@iki.fi>
 
        * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
index e8a319e..3da17ff 100644 (file)
@@ -1,3 +1,29 @@
+2002-11-18  Tor Lillqvist  <tml@iki.fi>
+
+       [Win32] Fix the asynchronous g_spawn* to return the process handle
+       of the started program properly. (Note: not the process id. The
+       spawn*() functions in the C runtime return the created process's
+       handle. There doesn't seem to be any way to get the process id of
+       a child process if you have the handle. But then, the process
+       handle usually is more useful anyway.)
+
+       * glib/gspawn-win32-helper.c (WinMain): If the spawning of the
+       child process succeeded, and if asynchronous spawn (P_NOWAIT),
+       write the result handle up to the parent process, waiting to read
+       it in do_spawn_with_pipes().
+
+       * glib/gspawn-win32.c (do_spawn): Use return value from spawning
+       the helper. If it is -1 the helper wasn't found or couldn't be run
+       for some reason. Otherwise it is the helper's process handle.
+
+       (g_spawn_async_with_pipes): Pass the child_pid parameter on to
+       do_spawn_with_pipes().
+
+       (do_spawn_with_pipes): Take also a child_pid parameter. If
+       do_spawn() returned -1, fail immediately. Otherwise make the
+       handle passed to us by the helper process into a handle valid in
+       this process by calling DuplicateHandle().
+
 2002-11-17  Tor Lillqvist  <tml@iki.fi>
 
        * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
index 357d014..a289f05 100644 (file)
@@ -70,7 +70,9 @@ WinMain (struct HINSTANCE__ *hInstance,
   int i;
   int fd;
   int mode;
-  gint zero = 0;
+  int handle;
+  int no_error = CHILD_NO_ERROR;
+  int zero = 0;
 
   SETUP_DEBUG();
 
@@ -203,10 +205,12 @@ WinMain (struct HINSTANCE__ *hInstance,
     {
       debugstring = g_string_new ("");
       g_string_append (debugstring,
-                      g_strdup_printf ("calling %s on program %s, __argv: ",
+                      g_strdup_printf ("calling %s %s mode=%s argv: ",
                                        (__argv[ARG_USE_PATH][0] == 'y' ?
                                         "spawnvp" : "spawnv"),
-                                       __argv[ARG_PROGRAM]));
+                                       __argv[ARG_PROGRAM],
+                                       (mode == P_WAIT ?
+                                        "P_WAIT" : "P_NOWAIT")));
       i = ARG_PROGRAM+1;
       while (__argv[i])
        {
@@ -218,17 +222,29 @@ WinMain (struct HINSTANCE__ *hInstance,
     }
 
   if (__argv[ARG_USE_PATH][0] == 'y')
-    {
-      if (spawnvp (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM) < 0)
-       write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
-    }
+    handle = spawnvp (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM);
   else
+    handle = spawnv (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM);
+
+  if (debug)
     {
-      if (spawnv (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM) < 0)
-       write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
+      debugstring = g_string_new ("");
+      g_string_append (debugstring,
+                      g_strdup_printf ("%s returned %#x",
+                                       (__argv[ARG_USE_PATH][0] == 'y' ?
+                                        "spawnvp" : "spawnv"),
+                                       handle));
+      MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
     }
-  write (child_err_report_fd, &zero, sizeof (zero));
-  write (child_err_report_fd, &zero, sizeof (zero));
+
+  if (handle < 0)
+    write_err_and_exit (child_err_report_fd, CHILD_SPAWN_FAILED);
+
+  write (child_err_report_fd, &no_error, sizeof (no_error));
+  if (mode == P_NOWAIT)
+    write (child_err_report_fd, &handle, sizeof (handle));
+  else
+    write (child_err_report_fd, &zero, sizeof (zero));
   return 0;
 }
 
index e0e9450..1ffecff 100644 (file)
@@ -109,6 +109,7 @@ static gboolean do_spawn_with_pipes  (gboolean              dont_wait,
                                       gboolean              child_inherits_stdin,
                                       GSpawnChildSetupFunc  child_setup,
                                       gpointer              user_data,
+                                      gint                 *child_pid,
                                       gint                 *standard_input,
                                       gint                 *standard_output,
                                       gint                 *standard_error,
@@ -222,6 +223,7 @@ g_spawn_sync (const gchar          *working_directory,
 {
   gint outpipe = -1;
   gint errpipe = -1;
+  gint pid;
   GIOChannel *outchannel = NULL;
   GIOChannel *errchannel = NULL;
   GPollFD outfd, errfd;
@@ -262,6 +264,7 @@ g_spawn_sync (const gchar          *working_directory,
                            (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
                            child_setup,
                            user_data,
+                           &pid,
                            NULL,
                            standard_output ? &outpipe : NULL,
                            standard_error ? &errpipe : NULL,
@@ -451,6 +454,7 @@ g_spawn_async_with_pipes (const gchar          *working_directory,
                              (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
                              child_setup,
                              user_data,
+                             child_pid,
                              standard_input,
                              standard_output,
                              standard_error,
@@ -537,6 +541,7 @@ do_spawn (gboolean              dont_wait,
   gchar **new_argv;
   gchar args[ARG_COUNT][10];
   gint i;
+  int rc;
   int argc = 0;
 
   SETUP_DEBUG();
@@ -595,7 +600,7 @@ do_spawn (gboolean              dont_wait,
     }
 
   if (working_directory && *working_directory)
-    new_argv[ARG_WORKING_DIRECTORY] = working_directory;
+    new_argv[ARG_WORKING_DIRECTORY] = g_strdup (working_directory);
   else
     new_argv[ARG_WORKING_DIRECTORY] = "-";
 
@@ -638,11 +643,9 @@ do_spawn (gboolean              dont_wait,
     /* Let's hope envp hasn't mucked with PATH so that
      * gspawn-win32-helper.exe isn't found.
      */
-    spawnvpe (P_NOWAIT, "gspawn-win32-helper", new_argv, envp);
+    rc = spawnvpe (P_NOWAIT, "gspawn-win32-helper", new_argv, envp);
   else
-    spawnvp (P_NOWAIT, "gspawn-win32-helper", new_argv);
-
-  /* FIXME: What if gspawn-win32-helper.exe isn't found? */
+    rc = spawnvp (P_NOWAIT, "gspawn-win32-helper", new_argv);
 
   /* Close the child_err_report_fd and the other process's ends of the
    * pipes in this process, otherwise the reader will never get
@@ -656,9 +659,10 @@ do_spawn (gboolean              dont_wait,
   if (stderr_fd >= 0)
     close (stderr_fd);
 
+  g_free (new_argv[ARG_WORKING_DIRECTORY]);
   g_free (new_argv);
 
-  return 0;
+  return rc;
 }
 
 static gboolean
@@ -720,6 +724,7 @@ do_spawn_with_pipes (gboolean              dont_wait,
                     gboolean              child_inherits_stdin,
                     GSpawnChildSetupFunc  child_setup,
                     gpointer              user_data,
+                    gint                 *child_pid,
                     gint                 *standard_input,
                     gint                 *standard_output,
                     gint                 *standard_error,
@@ -730,7 +735,7 @@ do_spawn_with_pipes (gboolean              dont_wait,
   gint stdout_pipe[2] = { -1, -1 };
   gint stderr_pipe[2] = { -1, -1 };
   gint child_err_report_pipe[2] = { -1, -1 };
-  gint status;
+  gint helper = -1;
   gint buf[2];
   gint n_ints = 0;
   
@@ -746,7 +751,7 @@ do_spawn_with_pipes (gboolean              dont_wait,
   if (standard_error && !make_pipe (stderr_pipe, error))
     goto cleanup_and_fail;
 
-  status = do_spawn (dont_wait,
+  helper = do_spawn (dont_wait,
                     child_err_report_pipe[1],
                     stdin_pipe[0],
                     stdout_pipe[1],
@@ -762,37 +767,57 @@ do_spawn_with_pipes (gboolean              dont_wait,
                     child_setup,
                     user_data);
       
+  /* do_spawn() returns -1 if gspawn-win32-helper couldn't be run */
+  if (helper == -1)
+    {
+      g_set_error (error,
+                  G_SPAWN_ERROR,
+                  G_SPAWN_ERROR_FAILED,
+                  _("Failed to execute helper program"));
+      goto cleanup_and_fail;
+    }
+
   if (!read_ints (child_err_report_pipe[0],
                  buf, 2, &n_ints,
-                 error))
+                 error) ||
+      n_ints != 2)
     goto cleanup_and_fail;
         
-  if (n_ints == 2)
+  /* Error code from gspawn-win32-helper. */
+  switch (buf[0])
     {
-      /* Error from the child. */
-      
-      switch (buf[0])
+    case CHILD_NO_ERROR:
+      if (child_pid && dont_wait)
        {
-       case CHILD_NO_ERROR:
-         break;
-         
-       case CHILD_CHDIR_FAILED:
-         g_set_error (error,
-                      G_SPAWN_ERROR,
-                      G_SPAWN_ERROR_CHDIR,
-                      _("Failed to change to directory '%s' (%s)"),
-                      working_directory,
-                      g_strerror (buf[1]));
-         goto cleanup_and_fail;
-         
-       case CHILD_SPAWN_FAILED:
-         g_set_error (error,
-                      G_SPAWN_ERROR,
-                      G_SPAWN_ERROR_FAILED,
-                      _("Failed to execute child process (%s)"),
-                      g_strerror (buf[1]));
-         goto cleanup_and_fail;
+         /* helper is our HANDLE for gspawn-win32-helper. It has
+          * told us the HANDLE of its child. Duplicate that into
+          * a HANDLE valid in this process.
+          */
+         if (!DuplicateHandle ((HANDLE) helper, (HANDLE) buf[1],
+                               GetCurrentProcess (), (LPHANDLE) child_pid,
+                               0, TRUE, DUPLICATE_SAME_ACCESS))
+           *child_pid = 0;
        }
+      else if (child_pid)
+       *child_pid = 0;
+      break;
+      
+    case CHILD_CHDIR_FAILED:
+      g_set_error (error,
+                  G_SPAWN_ERROR,
+                  G_SPAWN_ERROR_CHDIR,
+                  _("Failed to change to directory '%s' (%s)"),
+                  working_directory,
+                  g_strerror (buf[1]));
+      goto cleanup_and_fail;
+      
+    case CHILD_SPAWN_FAILED:
+      g_set_error (error,
+                  G_SPAWN_ERROR,
+                  G_SPAWN_ERROR_FAILED,
+                  _("Failed to execute child process (%s)"),
+                  g_strerror (buf[1]));
+      goto cleanup_and_fail;
     }
 
   /* Success against all odds! return the information */
@@ -804,11 +829,13 @@ do_spawn_with_pipes (gboolean              dont_wait,
   if (standard_error)
     *standard_error = stderr_pipe[0];
   if (exit_status)
-    *exit_status = status;
+    *exit_status = buf[1];
   
   return TRUE;
 
  cleanup_and_fail:
+  if (helper != -1)
+    CloseHandle ((HANDLE) helper);
   close_and_invalidate (&child_err_report_pipe[0]);
   close_and_invalidate (&child_err_report_pipe[1]);
   close_and_invalidate (&stdin_pipe[0]);