From 1f04f2cce236311e79fef775890a5114123ced37 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Sun, 17 Nov 2002 03:52:55 +0000 Subject: [PATCH] Ignore the G_SPAWN_DO_NOT_REAP_CHILD flag, can't be meaninfully 2002-11-17 Tor Lillqvist * 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. --- ChangeLog | 34 +++++++ ChangeLog.pre-2-10 | 34 +++++++ ChangeLog.pre-2-12 | 34 +++++++ ChangeLog.pre-2-2 | 34 +++++++ ChangeLog.pre-2-4 | 34 +++++++ ChangeLog.pre-2-6 | 34 +++++++ ChangeLog.pre-2-8 | 34 +++++++ glib/gspawn-win32-helper.c | 6 +- glib/gspawn-win32.c | 169 ++++++++++++++++++----------------- glib/gspawn.c | 21 +++-- tests/Makefile.am | 6 ++ tests/spawn-test-win32-gui.c | 99 ++++++++++++++++++++ tests/spawn-test.c | 149 +++++++++++++++++++++++++++++- 13 files changed, 597 insertions(+), 91 deletions(-) create mode 100644 tests/spawn-test-win32-gui.c diff --git a/ChangeLog b/ChangeLog index 87ceb0f1e..e8a319e32 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2002-11-17 Tor Lillqvist + + * 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 * docs/reference/glib/tmpl/arrays.sgml: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 87ceb0f1e..e8a319e32 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,37 @@ +2002-11-17 Tor Lillqvist + + * 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 * docs/reference/glib/tmpl/arrays.sgml: diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 87ceb0f1e..e8a319e32 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,37 @@ +2002-11-17 Tor Lillqvist + + * 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 * docs/reference/glib/tmpl/arrays.sgml: diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 87ceb0f1e..e8a319e32 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,37 @@ +2002-11-17 Tor Lillqvist + + * 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 * docs/reference/glib/tmpl/arrays.sgml: diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 87ceb0f1e..e8a319e32 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,37 @@ +2002-11-17 Tor Lillqvist + + * 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 * docs/reference/glib/tmpl/arrays.sgml: diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 87ceb0f1e..e8a319e32 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,37 @@ +2002-11-17 Tor Lillqvist + + * 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 * docs/reference/glib/tmpl/arrays.sgml: diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 87ceb0f1e..e8a319e32 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,37 @@ +2002-11-17 Tor Lillqvist + + * 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 * docs/reference/glib/tmpl/arrays.sgml: diff --git a/glib/gspawn-win32-helper.c b/glib/gspawn-win32-helper.c index 1a06ed19a..357d01415 100644 --- a/glib/gspawn-win32-helper.c +++ b/glib/gspawn-win32-helper.c @@ -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); } diff --git a/glib/gspawn-win32.c b/glib/gspawn-win32.c index 6f6d8fc5e..e0e9450cf 100644 --- a/glib/gspawn-win32.c +++ b/glib/gspawn-win32.c @@ -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, diff --git a/glib/gspawn.c b/glib/gspawn.c index e1eb2ab7b..de353ac9d 100644 --- a/glib/gspawn.c +++ b/glib/gspawn.c @@ -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 exec(). That is, - * @child_setup is called just before calling exec() - * 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 + * exec(). That is, @child_setup is called just + * before calling exec() in the child. Obviously + * actions taken in this function will only affect the child, not the + * parent. On Windows, there is no separate + * fork() and exec() + * functionality. Child processes are created and run right away with + * one API call, CreateProcess(). @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 diff --git a/tests/Makefile.am b/tests/Makefile.am index 59d08313e..010b96f827 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 index 000000000..8622d4411 --- /dev/null +++ b/tests/spawn-test-win32-gui.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include + +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; +} diff --git a/tests/spawn-test.c b/tests/spawn-test.c index 1234df01f..628126cf6 100644 --- a/tests/spawn-test.c +++ b/tests/spawn-test.c @@ -32,12 +32,21 @@ #include #include +#ifdef G_OS_WIN32 +#include +#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 }