Ignore the G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully
authorTor Lillqvist <tml@iki.fi>
Sun, 17 Nov 2002 03:52:55 +0000 (03:52 +0000)
committerTor Lillqvist <tml@src.gnome.org>
Sun, 17 Nov 2002 03:52:55 +0000 (03:52 +0000)
2002-11-17  Tor Lillqvist  <tml@iki.fi>

* glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
on Windows, at least not now. Always pass dont_wait as TRUE to
do_spawn_with_pipes(). The semantics of the dont_wait parameter is
very different from the semantics of the intermediate_child
parameter to fork_exec_with_pipes() in the Unix version. This
fixes a serious bug, g_spawn_async() in fact behaved
synchronously.

(do_spawn_with_pipes, do_spawn): Rename from
fork_exec_with_pipes() and do_exec(), those names were from the
Unix bersion, and misleading.

(close_and_invalidate): Don't try to close invalid fds.

* glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
Windows behaviour. There is no fork(), so the child_setup()
function is in fact called in the parent.

* glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
debugging output.

* tests/spawn-test-win32-gui.c: New file. Test program to be
linked as a GUI application. Behaves differently depending on how
invoked (by spawn-test).

* tests/spawn-test.c (run_tests): On Win32, run the
spawn-test-win32-gui program, too, in several ways, synchronously
and asynchronously.

* tests/Makefile.am: Corresponding change.

13 files changed:
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
glib/gspawn.c
tests/Makefile.am
tests/spawn-test-win32-gui.c [new file with mode: 0644]
tests/spawn-test.c

index 87ceb0f..e8a319e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+2002-11-17  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
+       G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
+       on Windows, at least not now. Always pass dont_wait as TRUE to
+       do_spawn_with_pipes(). The semantics of the dont_wait parameter is
+       very different from the semantics of the intermediate_child
+       parameter to fork_exec_with_pipes() in the Unix version. This
+       fixes a serious bug, g_spawn_async() in fact behaved
+       synchronously.
+
+       (do_spawn_with_pipes, do_spawn): Rename from
+       fork_exec_with_pipes() and do_exec(), those names were from the
+       Unix bersion, and misleading.
+
+       (close_and_invalidate): Don't try to close invalid fds.
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
+       Windows behaviour. There is no fork(), so the child_setup()
+       function is in fact called in the parent.
+       
+       * glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
+       debugging output.
+
+       * tests/spawn-test-win32-gui.c: New file. Test program to be
+       linked as a GUI application. Behaves differently depending on how
+       invoked (by spawn-test).
+
+       * tests/spawn-test.c (run_tests): On Win32, run the
+       spawn-test-win32-gui program, too, in several ways, synchronously
+       and asynchronously.
+
+       * tests/Makefile.am: Corresponding change.
+
 Fri Nov  8 19:44:20 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
 
        * docs/reference/glib/tmpl/arrays.sgml:
index 87ceb0f..e8a319e 100644 (file)
@@ -1,3 +1,37 @@
+2002-11-17  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
+       G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
+       on Windows, at least not now. Always pass dont_wait as TRUE to
+       do_spawn_with_pipes(). The semantics of the dont_wait parameter is
+       very different from the semantics of the intermediate_child
+       parameter to fork_exec_with_pipes() in the Unix version. This
+       fixes a serious bug, g_spawn_async() in fact behaved
+       synchronously.
+
+       (do_spawn_with_pipes, do_spawn): Rename from
+       fork_exec_with_pipes() and do_exec(), those names were from the
+       Unix bersion, and misleading.
+
+       (close_and_invalidate): Don't try to close invalid fds.
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
+       Windows behaviour. There is no fork(), so the child_setup()
+       function is in fact called in the parent.
+       
+       * glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
+       debugging output.
+
+       * tests/spawn-test-win32-gui.c: New file. Test program to be
+       linked as a GUI application. Behaves differently depending on how
+       invoked (by spawn-test).
+
+       * tests/spawn-test.c (run_tests): On Win32, run the
+       spawn-test-win32-gui program, too, in several ways, synchronously
+       and asynchronously.
+
+       * tests/Makefile.am: Corresponding change.
+
 Fri Nov  8 19:44:20 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
 
        * docs/reference/glib/tmpl/arrays.sgml:
index 87ceb0f..e8a319e 100644 (file)
@@ -1,3 +1,37 @@
+2002-11-17  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
+       G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
+       on Windows, at least not now. Always pass dont_wait as TRUE to
+       do_spawn_with_pipes(). The semantics of the dont_wait parameter is
+       very different from the semantics of the intermediate_child
+       parameter to fork_exec_with_pipes() in the Unix version. This
+       fixes a serious bug, g_spawn_async() in fact behaved
+       synchronously.
+
+       (do_spawn_with_pipes, do_spawn): Rename from
+       fork_exec_with_pipes() and do_exec(), those names were from the
+       Unix bersion, and misleading.
+
+       (close_and_invalidate): Don't try to close invalid fds.
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
+       Windows behaviour. There is no fork(), so the child_setup()
+       function is in fact called in the parent.
+       
+       * glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
+       debugging output.
+
+       * tests/spawn-test-win32-gui.c: New file. Test program to be
+       linked as a GUI application. Behaves differently depending on how
+       invoked (by spawn-test).
+
+       * tests/spawn-test.c (run_tests): On Win32, run the
+       spawn-test-win32-gui program, too, in several ways, synchronously
+       and asynchronously.
+
+       * tests/Makefile.am: Corresponding change.
+
 Fri Nov  8 19:44:20 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
 
        * docs/reference/glib/tmpl/arrays.sgml:
index 87ceb0f..e8a319e 100644 (file)
@@ -1,3 +1,37 @@
+2002-11-17  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
+       G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
+       on Windows, at least not now. Always pass dont_wait as TRUE to
+       do_spawn_with_pipes(). The semantics of the dont_wait parameter is
+       very different from the semantics of the intermediate_child
+       parameter to fork_exec_with_pipes() in the Unix version. This
+       fixes a serious bug, g_spawn_async() in fact behaved
+       synchronously.
+
+       (do_spawn_with_pipes, do_spawn): Rename from
+       fork_exec_with_pipes() and do_exec(), those names were from the
+       Unix bersion, and misleading.
+
+       (close_and_invalidate): Don't try to close invalid fds.
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
+       Windows behaviour. There is no fork(), so the child_setup()
+       function is in fact called in the parent.
+       
+       * glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
+       debugging output.
+
+       * tests/spawn-test-win32-gui.c: New file. Test program to be
+       linked as a GUI application. Behaves differently depending on how
+       invoked (by spawn-test).
+
+       * tests/spawn-test.c (run_tests): On Win32, run the
+       spawn-test-win32-gui program, too, in several ways, synchronously
+       and asynchronously.
+
+       * tests/Makefile.am: Corresponding change.
+
 Fri Nov  8 19:44:20 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
 
        * docs/reference/glib/tmpl/arrays.sgml:
index 87ceb0f..e8a319e 100644 (file)
@@ -1,3 +1,37 @@
+2002-11-17  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
+       G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
+       on Windows, at least not now. Always pass dont_wait as TRUE to
+       do_spawn_with_pipes(). The semantics of the dont_wait parameter is
+       very different from the semantics of the intermediate_child
+       parameter to fork_exec_with_pipes() in the Unix version. This
+       fixes a serious bug, g_spawn_async() in fact behaved
+       synchronously.
+
+       (do_spawn_with_pipes, do_spawn): Rename from
+       fork_exec_with_pipes() and do_exec(), those names were from the
+       Unix bersion, and misleading.
+
+       (close_and_invalidate): Don't try to close invalid fds.
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
+       Windows behaviour. There is no fork(), so the child_setup()
+       function is in fact called in the parent.
+       
+       * glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
+       debugging output.
+
+       * tests/spawn-test-win32-gui.c: New file. Test program to be
+       linked as a GUI application. Behaves differently depending on how
+       invoked (by spawn-test).
+
+       * tests/spawn-test.c (run_tests): On Win32, run the
+       spawn-test-win32-gui program, too, in several ways, synchronously
+       and asynchronously.
+
+       * tests/Makefile.am: Corresponding change.
+
 Fri Nov  8 19:44:20 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
 
        * docs/reference/glib/tmpl/arrays.sgml:
index 87ceb0f..e8a319e 100644 (file)
@@ -1,3 +1,37 @@
+2002-11-17  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
+       G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
+       on Windows, at least not now. Always pass dont_wait as TRUE to
+       do_spawn_with_pipes(). The semantics of the dont_wait parameter is
+       very different from the semantics of the intermediate_child
+       parameter to fork_exec_with_pipes() in the Unix version. This
+       fixes a serious bug, g_spawn_async() in fact behaved
+       synchronously.
+
+       (do_spawn_with_pipes, do_spawn): Rename from
+       fork_exec_with_pipes() and do_exec(), those names were from the
+       Unix bersion, and misleading.
+
+       (close_and_invalidate): Don't try to close invalid fds.
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
+       Windows behaviour. There is no fork(), so the child_setup()
+       function is in fact called in the parent.
+       
+       * glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
+       debugging output.
+
+       * tests/spawn-test-win32-gui.c: New file. Test program to be
+       linked as a GUI application. Behaves differently depending on how
+       invoked (by spawn-test).
+
+       * tests/spawn-test.c (run_tests): On Win32, run the
+       spawn-test-win32-gui program, too, in several ways, synchronously
+       and asynchronously.
+
+       * tests/Makefile.am: Corresponding change.
+
 Fri Nov  8 19:44:20 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
 
        * docs/reference/glib/tmpl/arrays.sgml:
index 87ceb0f..e8a319e 100644 (file)
@@ -1,3 +1,37 @@
+2002-11-17  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the
+       G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully implemented
+       on Windows, at least not now. Always pass dont_wait as TRUE to
+       do_spawn_with_pipes(). The semantics of the dont_wait parameter is
+       very different from the semantics of the intermediate_child
+       parameter to fork_exec_with_pipes() in the Unix version. This
+       fixes a serious bug, g_spawn_async() in fact behaved
+       synchronously.
+
+       (do_spawn_with_pipes, do_spawn): Rename from
+       fork_exec_with_pipes() and do_exec(), those names were from the
+       Unix bersion, and misleading.
+
+       (close_and_invalidate): Don't try to close invalid fds.
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Add warning about
+       Windows behaviour. There is no fork(), so the child_setup()
+       function is in fact called in the parent.
+       
+       * glib/gspawn-win32-helper.c (WinMain): Insert spaces in argv
+       debugging output.
+
+       * tests/spawn-test-win32-gui.c: New file. Test program to be
+       linked as a GUI application. Behaves differently depending on how
+       invoked (by spawn-test).
+
+       * tests/spawn-test.c (run_tests): On Win32, run the
+       spawn-test-win32-gui program, too, in several ways, synchronously
+       and asynchronously.
+
+       * tests/Makefile.am: Corresponding change.
+
 Fri Nov  8 19:44:20 2002  Soeren Sandmann  <sandmann@daimi.au.dk>
 
        * docs/reference/glib/tmpl/arrays.sgml:
index 1a06ed1..357d014 100644 (file)
@@ -209,7 +209,11 @@ WinMain (struct HINSTANCE__ *hInstance,
                                        __argv[ARG_PROGRAM]));
       i = ARG_PROGRAM+1;
       while (__argv[i])
-       g_string_append (debugstring, __argv[i++]);
+       {
+         g_string_append (debugstring, __argv[i++]);
+         if (__argv[i])
+           g_string_append (debugstring, " ");
+       }
       MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
     }
 
index 6f6d8fc..e0e9450 100644 (file)
@@ -98,7 +98,7 @@ enum {
 
 static gboolean make_pipe            (gint                  p[2],
                                       GError              **error);
-static gboolean fork_exec_with_pipes (gboolean              dont_wait,
+static gboolean do_spawn_with_pipes  (gboolean              dont_wait,
                                      const gchar          *working_directory,
                                       gchar               **argv,
                                       gchar               **envp,
@@ -155,8 +155,13 @@ close_and_invalidate (gint *fd)
 {
   gint ret;
 
-  ret = close (*fd);
-  *fd = -1;
+  if (*fd < 0)
+    return -1;
+  else
+    {
+      ret = close (*fd);
+      *fd = -1;
+    }
 
   return ret;
 }
@@ -174,7 +179,7 @@ read_data (GString     *str,
            GError     **error)
 {
   GIOStatus giostatus;
-  gint bytes;
+  gssize bytes;
   gchar buf[4096];
 
  again:
@@ -246,22 +251,22 @@ g_spawn_sync (const gchar          *working_directory,
   if (standard_error)
     *standard_error = NULL;
   
-  if (!fork_exec_with_pipes (FALSE,
-                             working_directory,
-                             argv,
-                             envp,
-                             !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
-                             (flags & G_SPAWN_SEARCH_PATH) != 0,
-                             (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
-                             (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
-                             (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
-                             child_setup,
-                             user_data,
-                             NULL,
-                             standard_output ? &outpipe : NULL,
-                             standard_error ? &errpipe : NULL,
-                            &status,
-                             error))
+  if (!do_spawn_with_pipes (FALSE,
+                           working_directory,
+                           argv,
+                           envp,
+                           !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
+                           (flags & G_SPAWN_SEARCH_PATH) != 0,
+                           (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
+                           (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
+                           (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
+                           child_setup,
+                           user_data,
+                           NULL,
+                           standard_output ? &outpipe : NULL,
+                           standard_error ? &errpipe : NULL,
+                           &status,
+                           error))
     return FALSE;
 
   /* Read data from child. */
@@ -435,22 +440,22 @@ g_spawn_async_with_pipes (const gchar          *working_directory,
   g_return_val_if_fail (standard_input == NULL ||
                         !(flags & G_SPAWN_CHILD_INHERITS_STDIN), FALSE);
   
-  return fork_exec_with_pipes (!(flags & G_SPAWN_DO_NOT_REAP_CHILD),
-                               working_directory,
-                               argv,
-                               envp,
-                               !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
-                               (flags & G_SPAWN_SEARCH_PATH) != 0,
-                               (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
-                               (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
-                               (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
-                               child_setup,
-                               user_data,
-                               standard_input,
-                               standard_output,
-                               standard_error,
-                              NULL,
-                               error);
+  return do_spawn_with_pipes (TRUE,
+                             working_directory,
+                             argv,
+                             envp,
+                             !(flags & G_SPAWN_LEAVE_DESCRIPTORS_OPEN),
+                             (flags & G_SPAWN_SEARCH_PATH) != 0,
+                             (flags & G_SPAWN_STDOUT_TO_DEV_NULL) != 0,
+                             (flags & G_SPAWN_STDERR_TO_DEV_NULL) != 0,
+                             (flags & G_SPAWN_CHILD_INHERITS_STDIN) != 0,
+                             child_setup,
+                             user_data,
+                             standard_input,
+                             standard_output,
+                             standard_error,
+                             NULL,
+                             error);
 }
 
 gboolean
@@ -513,21 +518,21 @@ g_spawn_command_line_async (const gchar *command_line,
 }
 
 static gint
-do_exec (gboolean              dont_wait,
-        gint                  child_err_report_fd,
-         gint                  stdin_fd,
-         gint                  stdout_fd,
-         gint                  stderr_fd,
-         const gchar          *working_directory,
-         gchar               **argv,
-         gchar               **envp,
-         gboolean              close_descriptors,
-         gboolean              search_path,
-         gboolean              stdout_to_null,
-         gboolean              stderr_to_null,
-         gboolean              child_inherits_stdin,
-         GSpawnChildSetupFunc  child_setup,
-         gpointer              user_data)
+do_spawn (gboolean              dont_wait,
+         gint                  child_err_report_fd,
+         gint                  stdin_fd,
+         gint                  stdout_fd,
+         gint                  stderr_fd,
+         const gchar          *working_directory,
+         gchar               **argv,
+         gchar               **envp,
+         gboolean              close_descriptors,
+         gboolean              search_path,
+         gboolean              stdout_to_null,
+         gboolean              stderr_to_null,
+         gboolean              child_inherits_stdin,
+         GSpawnChildSetupFunc  child_setup,
+         gpointer              user_data)
 {
   gchar **new_argv;
   gchar args[ARG_COUNT][10];
@@ -704,22 +709,22 @@ read_ints (int      fd,
 }
 
 static gboolean
-fork_exec_with_pipes (gboolean              dont_wait,
-                      const gchar          *working_directory,
-                      gchar               **argv,
-                      gchar               **envp,
-                      gboolean              close_descriptors,
-                      gboolean              search_path,
-                      gboolean              stdout_to_null,
-                      gboolean              stderr_to_null,
-                     gboolean              child_inherits_stdin,
-                      GSpawnChildSetupFunc  child_setup,
-                      gpointer              user_data,
-                      gint                 *standard_input,
-                      gint                 *standard_output,
-                      gint                 *standard_error,
-                     gint                 *exit_status,
-                      GError              **error)     
+do_spawn_with_pipes (gboolean              dont_wait,
+                    const gchar          *working_directory,
+                    gchar               **argv,
+                    gchar               **envp,
+                    gboolean              close_descriptors,
+                    gboolean              search_path,
+                    gboolean              stdout_to_null,
+                    gboolean              stderr_to_null,
+                    gboolean              child_inherits_stdin,
+                    GSpawnChildSetupFunc  child_setup,
+                    gpointer              user_data,
+                    gint                 *standard_input,
+                    gint                 *standard_output,
+                    gint                 *standard_error,
+                    gint                 *exit_status,
+                    GError              **error)     
 {
   gint stdin_pipe[2] = { -1, -1 };
   gint stdout_pipe[2] = { -1, -1 };
@@ -741,21 +746,21 @@ fork_exec_with_pipes (gboolean              dont_wait,
   if (standard_error && !make_pipe (stderr_pipe, error))
     goto cleanup_and_fail;
 
-  status = do_exec (dont_wait,
-                   child_err_report_pipe[1],
-                   stdin_pipe[0],
-                   stdout_pipe[1],
-                   stderr_pipe[1],
-                   working_directory,
-                   argv,
-                   envp,
-                   close_descriptors,
-                   search_path,
-                   stdout_to_null,
-                   stderr_to_null,
-                   child_inherits_stdin,
-                   child_setup,
-                   user_data);
+  status = do_spawn (dont_wait,
+                    child_err_report_pipe[1],
+                    stdin_pipe[0],
+                    stdout_pipe[1],
+                    stderr_pipe[1],
+                    working_directory,
+                    argv,
+                    envp,
+                    close_descriptors,
+                    search_path,
+                    stdout_to_null,
+                    stderr_to_null,
+                    child_inherits_stdin,
+                    child_setup,
+                    user_data);
       
   if (!read_ints (child_err_report_pipe[0],
                  buf, 2, &n_ints,
index e1eb2ab..de353ac 100644 (file)
@@ -462,13 +462,20 @@ g_spawn_sync (const gchar          *working_directory,
  * g_spawn_async_with_pipes() uses @argv[0] as the file to execute, and
  * passes all of @argv to the child.
  *
- * @child_setup and @user_data are a function and user data to be
- * called in the child after GLib has performed all the setup it plans
- * to perform (including creating pipes, closing file descriptors,
- * etc.) but before calling <function>exec()</function>. That is, 
- * @child_setup is called just before calling <function>exec()</function> 
- * in the child. Obviously actions taken in this function will only affect 
- * the child, not the parent. 
+ * @child_setup and @user_data are a function and user data. On POSIX
+ * platforms, the function is called in the child after GLib has
+ * performed all the setup it plans to perform (including creating
+ * pipes, closing file descriptors, etc.) but before calling
+ * <function>exec()</function>. That is, @child_setup is called just
+ * before calling <function>exec()</function> in the child. Obviously
+ * actions taken in this function will only affect the child, not the
+ * parent. On Windows, there is no separate
+ * <function>fork()</function> and <function>exec()</function>
+ * functionality. Child processes are created and run right away with
+ * one API call, <function>CreateProcess()</function>. @child_setup is
+ * called in the parent process just before creating the child
+ * process. You should carefully consider what you do in @child_setup
+ * if you intend your software to be portable to Windows.
  *
  * If non-%NULL, @child_pid will be filled with the child's process
  * ID. You can use the process ID to send signals to the child, or
index 59d0831..010b96f 100644 (file)
@@ -16,6 +16,11 @@ module_test_exp = module-test.exp
 
 module-test.exp: module-test.o
        dlltool --output-exp module-test.exp module-test.o
+
+spawn_test_win32_gui = spawn-test-win32-gui
+
+spawn_test_win32_gui_LDFLAGS = -mwindows
+
 endif
 
 EXTRA_DIST =                                   \
@@ -75,6 +80,7 @@ test_programs =                                       \
        shell-test                              \
        slist-test                              \
        spawn-test                              \
+       $(spawn_test_win32_gui)                 \
        strfunc-test                            \
        string-test                             \
        strtod-test                             \
diff --git a/tests/spawn-test-win32-gui.c b/tests/spawn-test-win32-gui.c
new file mode 100644 (file)
index 0000000..8622d44
--- /dev/null
@@ -0,0 +1,99 @@
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+int _stdcall
+WinMain (struct HINSTANCE__ *hInstance,
+       struct HINSTANCE__ *hPrevInstance,
+       char *lpszCmdLine,
+       int   nCmdShow)
+{
+  if (__argc <= 2)
+    {
+      MessageBox (NULL, "spawn-test-win32-gui: Will write to stdout",
+                 lpszCmdLine, MB_ICONINFORMATION|MB_SYSTEMMODAL);
+      
+      printf ("This is stdout\n");
+      fflush (stdout);
+      
+      MessageBox (NULL, "spawn-test-win32-gui: Will write to stderr",
+                 lpszCmdLine, MB_ICONINFORMATION|MB_SYSTEMMODAL);
+      
+      fprintf (stderr, "This is stderr\n");
+      fflush (stderr);
+    }
+  else if (__argc == 4 && strcmp (__argv[1], "pipes") == 0)
+    {
+      int infd = atoi (__argv[2]);
+      int outfd = atoi (__argv[3]);
+      int k, n;
+      char buf[100];
+
+      if (infd < 0 || outfd < 0)
+       {
+         MessageBox (NULL, "spawn-test-win32-gui: illegal fds on command line",
+                     lpszCmdLine, MB_ICONERROR|MB_SYSTEMMODAL);
+         exit (1);
+       }
+
+      MessageBox (NULL, "spawn-test-win32-gui: Will write to parent",
+                 lpszCmdLine, MB_ICONINFORMATION|MB_SYSTEMMODAL);
+
+      n = strlen ("Hello there");
+      if (write (outfd, &n, sizeof (n)) == -1 ||
+         write (outfd, "Hello there", n) == -1)
+       {
+         sprintf (buf, "spawn-test-win32-gui: Write: %s", strerror (errno));
+         MessageBox (NULL, buf, lpszCmdLine, MB_ICONERROR|MB_SYSTEMMODAL);
+         exit (1);
+       }
+
+      MessageBox (NULL, "spawn-test-win32-gui: Will read from parent",
+                 lpszCmdLine, MB_ICONINFORMATION|MB_SYSTEMMODAL);
+
+      if ((k = read (infd, &n, sizeof (n))) != sizeof (n))
+       {
+         sprintf (buf, "spawn-test-win32-gui: Got only %d bytes, wanted %d",
+                  k, sizeof (n));
+         MessageBox (NULL, buf, lpszCmdLine, MB_ICONERROR|MB_SYSTEMMODAL);
+         exit (1);
+       }
+
+      sprintf (buf, "spawn-test-win32-gui: Parent says %d bytes to read", n);
+      MessageBox (NULL, buf, lpszCmdLine, MB_ICONINFORMATION|MB_SYSTEMMODAL);
+
+      if ((k = read (infd, buf, n)) != n)
+       {
+         if (k == -1)
+           sprintf (buf, "spawn-test-win32-gui: Read: %s", strerror (errno));
+         else
+           sprintf (buf, "spawn-test-win32-gui: Got only %d bytes", k);
+         MessageBox (NULL, buf, lpszCmdLine, MB_ICONERROR|MB_SYSTEMMODAL);
+         exit (1);
+       }
+
+      MessageBox (NULL, "spawn-test-win32-gui: Will write more to parent",
+                 lpszCmdLine, MB_ICONINFORMATION|MB_SYSTEMMODAL);
+
+      n = strlen ("See ya");
+      if (write (outfd, &n, sizeof (n)) == -1 ||
+         write (outfd, "See ya", n) == -1)
+       {
+         sprintf (buf, "spawn-test-win32-gui: Write: %s", strerror (errno));
+         MessageBox (NULL, buf, lpszCmdLine, MB_ICONERROR|MB_SYSTEMMODAL);
+         exit (1);
+       }
+    }
+
+  MessageBox (NULL, "spawn-test-win32-gui: Sleeping a bit.",
+             lpszCmdLine, MB_ICONINFORMATION|MB_SYSTEMMODAL);
+  
+  Sleep (2000);
+  
+  MessageBox (NULL, "spawn-test-win32-gui: Done, exiting.",
+             lpszCmdLine, MB_ICONINFORMATION|MB_SYSTEMMODAL);
+
+  return 0;
+}
index 1234df0..628126c 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 
+#ifdef G_OS_WIN32
+#include <fcntl.h>
+#endif
+
 
 static void
 run_tests (void)
 {
   GError *err;
   gchar *output = NULL;
+#ifdef G_OS_WIN32
+  gchar *erroutput = NULL;
+  int pipedown[2], pipeup[2];
+  gchar **argv = 0;
+#endif
   
   printf ("The following errors are supposed to occur:\n");
 
@@ -86,8 +95,10 @@ run_tests (void)
     }
 #else
 #ifdef G_OS_WIN32
+  printf ("Running ipconfig synchronously, collecting its output\n");
+
   if (!g_spawn_command_line_sync ("ipconfig /all",
-                                  &output, NULL, NULL,
+                                  &output, &erroutput, NULL,
                                   &err))
     {
       fprintf (stderr, "Error: %s\n", err->message);
@@ -97,6 +108,7 @@ run_tests (void)
   else
     {
       g_assert (output != NULL);
+      g_assert (erroutput != NULL);
       
       if (strstr (output, "IP Configuration") == 0)
         {
@@ -105,10 +117,145 @@ run_tests (void)
 
           exit (1);
         }
+      if (erroutput[0] != '\0')
+       {
+         printf ("error output was '%s', should have been empty\n",
+                 erroutput);
+         exit (1);
+       }
+
+      g_free (output);
+      output = NULL;
+      g_free (erroutput);
+      erroutput = NULL;
+    }
+
+  printf ("Starting spawn-test-win32-gui asynchronously (without wait).\n"
+         "Click on the OK buttons.\n");
+
+  if (!g_spawn_command_line_async ("'.\\spawn-test-win32-gui.exe' 1", &err))
+    {
+      fprintf (stderr, "Error: %s\n", err->message);
+      g_error_free (err);
+      exit (1);
+    }
+
+  printf ("Running spawn-test-win32-gui synchronously,\n"
+         "collecting its output. Click on the OK buttons.\n");
+  if (!g_spawn_command_line_sync ("'.\\spawn-test-win32-gui.exe' 2",
+                                 &output, &erroutput, NULL,
+                                 &err))
+    {
+      fprintf (stderr, "Error: %s\n", err->message);
+      g_error_free (err);
+      exit (1);
+    }
+  else
+    {
+      g_assert (output != NULL);
+      g_assert (erroutput != NULL);
+      
+      if (strcmp (output, "This is stdout\r\n") != 0)
+        {
+          printf ("output was '%s', should have been 'This is stdout'\n",
+                  g_strescape (output, NULL));
+
+          exit (1);
+        }
+      if (strcmp (erroutput, "This is stderr\r\n") != 0)
+       {
+         printf ("error output was '%s', should have been 'This is stderr'\n",
+                 g_strescape (erroutput, NULL));
+         exit (1);
+       }
 
       g_free (output);
+      g_free (erroutput);
+    }
+
+  printf ("Running spawn-test-win32-gui asynchronously again.\n"
+         "This time talking to it through pipes. Click on the OK buttons.\n");
+
+  if (pipe (pipedown) < 0 ||
+      pipe (pipeup) < 0)
+    {
+      fprintf (stderr, "Could not create pipes\n");
+      exit (1);
     }
 
+  if (!g_shell_parse_argv (g_strdup_printf ("'.\\spawn-test-win32-gui.exe' pipes %d %d",
+                                           pipedown[0], pipeup[1]),
+                           NULL, &argv,
+                           &err))
+    {
+      fprintf (stderr, "Error parsing command line? %s\n", err->message);
+      g_error_free (err);
+      exit (1);
+    }
+  
+  if (!g_spawn_async (NULL, argv, NULL,
+                     G_SPAWN_LEAVE_DESCRIPTORS_OPEN |
+                     G_SPAWN_DO_NOT_REAP_CHILD,
+                     NULL, NULL, NULL,
+                     &err))
+    {
+      fprintf (stderr, "Error: %s\n", err->message);
+      g_error_free (err);
+      exit (1);
+    }
+  else
+    {
+      int k, n;
+      char buf[100];
+
+      if ((k = read (pipeup[0], &n, sizeof (n))) != sizeof (n))
+       {
+         if (k == -1)
+           fprintf (stderr, "Read error: %s\n", g_strerror (errno));
+         else
+           fprintf (stderr, "Wanted to read %d bytes, got %d\n",
+                    sizeof (n), k);
+         exit (1);
+       }
+
+      if ((k = read (pipeup[0], buf, n)) != n)
+       {
+         if (k == -1)
+           fprintf (stderr, "Read error: %s\n", g_strerror (errno));
+         else
+           fprintf (stderr, "Wanted to read %d bytes, got %d\n",
+                    n, k);
+         exit (1);
+       }
+
+      n = strlen ("Bye then");
+      if (write (pipedown[1], &n, sizeof (n)) == -1 ||
+         write (pipedown[1], "Bye then", n) == -1)
+       {
+         fprintf (stderr, "Write error: %s\n", g_strerror (errno));
+         exit (1);
+       }
+
+      if ((k = read (pipeup[0], &n, sizeof (n))) != sizeof (n))
+       {
+         if (k == -1)
+           fprintf (stderr, "Read error: %s\n", g_strerror (errno));
+         else
+           fprintf (stderr, "Wanted to read %d bytes, got %d\n",
+                    sizeof (n), k);
+         exit (1);
+       }
+
+      if ((k = read (pipeup[0], buf, n)) != n)
+       {
+         if (k == -1)
+           fprintf (stderr, "Read error: %s\n", g_strerror (errno));
+         else
+           fprintf (stderr, "Wanted to read %d bytes, got %d\n",
+                    n, k);
+         exit (1);
+       }
+    }
 #endif
 #endif
 }