diff --git a/docs/reference/glib/tmpl/spawn.sgml b/docs/reference/glib/tmpl/spawn.sgml
index baf085e..5c1abac 100644
--- a/docs/reference/glib/tmpl/spawn.sgml
+++ b/docs/reference/glib/tmpl/spawn.sgml
@@ -79,6 +79,11 @@ Flags passed to g_spawn_sync(), g_spawn_async() and g_spawn_async_with_pipes().
   vector to pass to the file. Normally g_spawn_async_with_pipes() uses 
   <literal>argv[0]</literal> as the file to execute, and passes all of 
   <literal>argv</literal> to the child.
+@G_SPAWN_WIN32_HIDDEN_CONSOLE: if the child is a Windows console application,
+  the console window will not be shown. Note that when using this flag, none
+  of the file descriptors will be inherited (except stdin/stdout/stderr),
+  regardless of the flags used. This flag has no effect under any platforms
+  except Windows.
 
 <!-- ##### USER_FUNCTION GSpawnChildSetupFunc ##### -->
 <para>
diff --git a/glib/gspawn-win32-helper.c b/glib/gspawn-win32-helper.c
index 40108bb..0a2e8e5 100644
--- a/glib/gspawn-win32-helper.c
+++ b/glib/gspawn-win32-helper.c
@@ -147,6 +147,16 @@ protect_wargv (wchar_t  **wargv,
   return argc;
 }
 
+static int
+get_file_descriptor (const gchar *arg,
+                     gboolean     is_handle)
+{
+  if (is_handle)
+    return _open_osfhandle (atoi (arg), 0);
+  else
+    return atoi (arg);
+}
+
 #ifndef HELPER_CONSOLE
 int _stdcall
 WinMain (struct HINSTANCE__ *hInstance,
@@ -170,6 +180,7 @@ main (int ignored_argc, char **ignored_argv)
   wchar_t **new_wargv;
   int argc;
   wchar_t **wargv, **wenvp;
+  gboolean handles_in_argv;
   _startupinfo si = { 0 };
   char c;
 
@@ -184,10 +195,17 @@ main (int ignored_argc, char **ignored_argv)
    */
   g_assert (argc == __argc);
 
-  /* argv[ARG_CHILD_ERR_REPORT] is the file descriptor number onto
+  /* argv[ARG_HANDLES_IN_ARGV] is "y" or "n" telling whether
+   * file handle arguments contain HANDLE's or file descriptors.
+   */
+  handles_in_argv = __argv[ARG_HANDLES_IN_ARGV][0] == 'y';
+
+  /* argv[ARG_CHILD_ERR_REPORT] is the pipe handle onto
    * which write error messages.
    */
-  child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]);
+  child_err_report_fd = get_file_descriptor (__argv[ARG_CHILD_ERR_REPORT], handles_in_argv);
+  if (child_err_report_fd < 0)
+    g_error ("child_err_report_fd not set");
 
   /* Hack to implement G_SPAWN_FILE_AND_ARGV_ZERO. If
    * argv[ARG_CHILD_ERR_REPORT] is suffixed with a '#' it means we get
@@ -204,7 +222,7 @@ main (int ignored_argc, char **ignored_argv)
    */
   helper_sync_fd = atoi (__argv[ARG_HELPER_SYNC]);
 
-  /* argv[ARG_STDIN..ARG_STDERR] are the file descriptor numbers that
+  /* argv[ARG_STDIN..ARG_STDERR] are the pipe handles that
    * should be dup2'd to 0, 1 and 2. '-' if the corresponding fd
    * should be left alone, and 'z' if it should be connected to the
    * bit bucket NUL:.
@@ -222,7 +240,9 @@ main (int ignored_argc, char **ignored_argv)
     }
   else
     {
-      fd = atoi (__argv[ARG_STDIN]);
+      fd = get_file_descriptor (__argv[ARG_STDIN], handles_in_argv);
+      if (fd < 0)
+        g_error ("could not open stdin pipe");
       if (fd != 0)
 	{
 	  dup2 (fd, 0);
@@ -243,7 +263,9 @@ main (int ignored_argc, char **ignored_argv)
     }
   else
     {
-      fd = atoi (__argv[ARG_STDOUT]);
+      fd = get_file_descriptor (__argv[ARG_STDOUT], handles_in_argv);
+      if (fd < 0)
+        g_error ("could not open stdout pipe");
       if (fd != 1)
 	{
 	  dup2 (fd, 1);
@@ -264,7 +286,9 @@ main (int ignored_argc, char **ignored_argv)
     }
   else
     {
-      fd = atoi (__argv[ARG_STDERR]);
+      fd = get_file_descriptor (__argv[ARG_STDERR], handles_in_argv);
+      if (fd < 0)
+        g_error ("could not open stderr pipe");
       if (fd != 2)
 	{
 	  dup2 (fd, 2);
diff --git a/glib/gspawn-win32.c b/glib/gspawn-win32.c
index dc48a25..c2adc30 100644
--- a/glib/gspawn-win32.c
+++ b/glib/gspawn-win32.c
@@ -88,7 +88,8 @@ enum
 };
 
 enum {
-  ARG_CHILD_ERR_REPORT = 1,
+  ARG_HANDLES_IN_ARGV = 1,
+  ARG_CHILD_ERR_REPORT,
   ARG_HELPER_SYNC,
   ARG_STDIN,
   ARG_STDOUT,
@@ -353,7 +354,11 @@ read_helper_report (int      fd,
     }
 
   if (bytes < sizeof(gintptr)*2)
-    return FALSE;
+    {
+      g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
+                    _("Failed to read from child pipe"));
+      return FALSE;
+    }
 
   return TRUE;
 }
@@ -514,6 +519,77 @@ do_spawn_directly (gint                 *exit_status,
   return TRUE;
 }
 
+static int
+spawn_with_hidden_console (wchar_t **wargv,
+			   wchar_t **wenvp,
+                           GError  **error)
+{
+  GArray *cmd_line;
+  STARTUPINFOW sinfo;
+  PROCESS_INFORMATION pinfo;
+  wchar_t **p;
+  wchar_t *env_string = NULL;
+  int rc = -1;
+  guint flags;
+
+  cmd_line = g_array_new (FALSE, FALSE, sizeof (wchar_t));
+  for (p = wargv; *p; p++)
+  {
+    if (p > wargv)
+      g_array_append_vals (cmd_line, L" ", 1);
+    g_array_append_vals (cmd_line, *p, wcslen (*p));
+  }
+  g_array_append_vals (cmd_line, L"", 1);
+
+  memset (&sinfo, 0, sizeof sinfo);
+  sinfo.cb = sizeof (STARTUPINFO);
+  sinfo.dwFlags = STARTF_USESHOWWINDOW;
+  sinfo.wShowWindow = SW_HIDE;
+  flags = CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP;
+
+  if (wenvp)
+    {
+      GArray *tmp;
+
+      flags |= CREATE_UNICODE_ENVIRONMENT;
+
+      /* format is "var=value\0var=value\0\0" */
+      tmp = g_array_new (FALSE, FALSE, sizeof (wchar_t));
+      for (p = wenvp; p && *p; p++)
+        g_array_append_vals (tmp, *p, wcslen (*p) + 1);
+      g_array_append_vals (tmp, L"", 1);
+      env_string = (wchar_t*) g_array_free (tmp, FALSE);
+    }
+
+  if (CreateProcessW (NULL, (wchar_t*) cmd_line->data, NULL, NULL, TRUE,
+		      flags, env_string, NULL, &sinfo, &pinfo))
+    {
+      rc = (int) pinfo.hProcess;
+      CloseHandle (pinfo.hThread);
+    }
+  else
+    {
+      g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
+		   _("Failed to execute helper program (%s)"),
+		   g_win32_error_message (GetLastError ()));
+    }
+
+  g_free (env_string);
+  g_array_free (cmd_line, TRUE);
+  return rc;
+}
+
+static void
+sprintf_file_descriptor (gchar   *dest,
+                         gint     fd,
+                         gboolean print_handle)
+{
+  if (print_handle)
+    _g_sprintf (dest, "%ld", _get_osfhandle (fd));
+  else
+    _g_sprintf (dest, "%d", fd);
+}
+
 static gboolean
 do_spawn_with_pipes (gint                 *exit_status,
 		     gboolean		   do_return_handle,
@@ -550,6 +626,8 @@ do_spawn_with_pipes (gint                 *exit_status,
   wchar_t *whelper, **wargv, **wenvp;
   extern gchar *_glib_get_dll_directory (void);
   gchar *glib_dll_directory;
+  gboolean error_set = FALSE;
+  gboolean handles_in_argv = FALSE;
 
   if (child_setup && !warned_about_child_setup)
     {
@@ -560,6 +638,7 @@ do_spawn_with_pipes (gint                 *exit_status,
   argc = protect_argv (argv, &protected_argv);
 
   if (!standard_input && !standard_output && !standard_error &&
+      !(flags & G_SPAWN_WIN32_HIDDEN_CONSOLE) &&
       (flags & G_SPAWN_CHILD_INHERITS_STDIN) &&
       !(flags & G_SPAWN_STDOUT_TO_DEV_NULL) &&
       !(flags & G_SPAWN_STDERR_TO_DEV_NULL) &&
@@ -591,7 +670,8 @@ do_spawn_with_pipes (gint                 *exit_status,
     goto cleanup_and_fail;
   
   new_argv = g_new (char *, argc + 1 + ARG_COUNT);
-  if (GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info))
+  if ((flags & G_SPAWN_WIN32_HIDDEN_CONSOLE) ||
+      GetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cursor_info))
     helper_process = HELPER_PROCESS "-console.exe";
   else
     helper_process = HELPER_PROCESS ".exe";
@@ -607,9 +687,16 @@ do_spawn_with_pipes (gint                 *exit_status,
 
   new_argv[0] = protect_argv_string (helper_process);
 
-  _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]);
+  if (flags & G_SPAWN_WIN32_HIDDEN_CONSOLE)
+    handles_in_argv = TRUE;
+
+  strcpy (args[ARG_HANDLES_IN_ARGV], handles_in_argv ? "y" : "n");
+  new_argv[ARG_HANDLES_IN_ARGV] = args[ARG_HANDLES_IN_ARGV];
+
+  sprintf_file_descriptor (args[ARG_CHILD_ERR_REPORT],
+                           child_err_report_pipe[1], handles_in_argv);
   new_argv[ARG_CHILD_ERR_REPORT] = args[ARG_CHILD_ERR_REPORT];
-  
+
   /* Make the read end of the child error report pipe
    * noninherited. Otherwise it will needlessly be inherited by the
    * helper process, and the started actual user process. As such that
@@ -638,7 +725,7 @@ do_spawn_with_pipes (gint                 *exit_status,
 
   if (standard_input)
     {
-      _g_sprintf (args[ARG_STDIN], "%d", stdin_pipe[0]);
+      sprintf_file_descriptor (args[ARG_STDIN], stdin_pipe[0], handles_in_argv);
       new_argv[ARG_STDIN] = args[ARG_STDIN];
     }
   else if (flags & G_SPAWN_CHILD_INHERITS_STDIN)
@@ -654,7 +741,7 @@ do_spawn_with_pipes (gint                 *exit_status,
   
   if (standard_output)
     {
-      _g_sprintf (args[ARG_STDOUT], "%d", stdout_pipe[1]);
+      sprintf_file_descriptor (args[ARG_STDOUT], stdout_pipe[1], handles_in_argv);
       new_argv[ARG_STDOUT] = args[ARG_STDOUT];
     }
   else if (flags & G_SPAWN_STDOUT_TO_DEV_NULL)
@@ -668,7 +755,7 @@ do_spawn_with_pipes (gint                 *exit_status,
   
   if (standard_error)
     {
-      _g_sprintf (args[ARG_STDERR], "%d", stderr_pipe[1]);
+      sprintf_file_descriptor (args[ARG_STDERR], stderr_pipe[1], handles_in_argv);
       new_argv[ARG_STDERR] = args[ARG_STDERR];
     }
   else if (flags & G_SPAWN_STDERR_TO_DEV_NULL)
@@ -751,7 +838,13 @@ do_spawn_with_pipes (gint                 *exit_status,
   whelper = g_utf8_to_utf16 (helper_process, -1, NULL, NULL, NULL);
   g_free (helper_process);
 
-  if (wenvp != NULL)
+  if (flags & G_SPAWN_WIN32_HIDDEN_CONSOLE)
+    {
+      rc = spawn_with_hidden_console (wargv, wenvp, error);
+      if (rc == -1)
+        error_set = TRUE;
+    }
+  else if (wenvp != NULL)
     rc = _wspawnvpe (P_NOWAIT, whelper, (const wchar_t **) wargv, (const wchar_t **) wenvp);
   else
     rc = _wspawnvp (P_NOWAIT, whelper, (const wchar_t **) wargv);
@@ -778,11 +871,12 @@ do_spawn_with_pipes (gint                 *exit_status,
   g_free (new_argv);
 
   /* Check if gspawn-win32-helper couldn't be run */
-  if (rc == -1 && saved_errno != 0)
+  if (rc == -1 && (saved_errno != 0 || error_set))
     {
-      g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
-		   _("Failed to execute helper program (%s)"),
-		   g_strerror (saved_errno));
+      if (!error_set)
+        g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
+		     _("Failed to execute helper program (%s)"),
+		     g_strerror (saved_errno));
       goto cleanup_and_fail;
     }
 
diff --git a/glib/gspawn.h b/glib/gspawn.h
index 9836b34..10d98ff 100644
--- a/glib/gspawn.h
+++ b/glib/gspawn.h
@@ -70,7 +70,8 @@ typedef enum
   G_SPAWN_STDOUT_TO_DEV_NULL     = 1 << 3,
   G_SPAWN_STDERR_TO_DEV_NULL     = 1 << 4,
   G_SPAWN_CHILD_INHERITS_STDIN   = 1 << 5,
-  G_SPAWN_FILE_AND_ARGV_ZERO     = 1 << 6
+  G_SPAWN_FILE_AND_ARGV_ZERO     = 1 << 6,
+  G_SPAWN_WIN32_HIDDEN_CONSOLE   = 1 << 7
 } GSpawnFlags;
 
 GQuark g_spawn_error_quark (void);
