diff --git a/ChangeLog b/ChangeLog index e8a319e32..3da17ffc6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2002-11-18 Tor Lillqvist + + [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 * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index e8a319e32..3da17ffc6 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,29 @@ +2002-11-18 Tor Lillqvist + + [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 * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index e8a319e32..3da17ffc6 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,29 @@ +2002-11-18 Tor Lillqvist + + [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 * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index e8a319e32..3da17ffc6 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,29 @@ +2002-11-18 Tor Lillqvist + + [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 * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index e8a319e32..3da17ffc6 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,29 @@ +2002-11-18 Tor Lillqvist + + [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 * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index e8a319e32..3da17ffc6 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,29 @@ +2002-11-18 Tor Lillqvist + + [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 * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index e8a319e32..3da17ffc6 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,29 @@ +2002-11-18 Tor Lillqvist + + [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 * glib/gspawn-win32.c (g_spawn_async_with_pipes): Ignore the diff --git a/glib/gspawn-win32-helper.c b/glib/gspawn-win32-helper.c index 357d01415..a289f059f 100644 --- a/glib/gspawn-win32-helper.c +++ b/glib/gspawn-win32-helper.c @@ -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; } diff --git a/glib/gspawn-win32.c b/glib/gspawn-win32.c index e0e9450cf..1ffecffbf 100644 --- a/glib/gspawn-win32.c +++ b/glib/gspawn-win32.c @@ -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]);