cleanup
[platform/upstream/glib.git] / glib / gspawn-win32-helper.c
index 40108bb..76191f9 100644 (file)
 
 #include <fcntl.h>
 
+/* For _CrtSetReportMode, we don't want Windows CRT (2005 and later)
+ * to terminate the process if a bad file descriptor is passed into
+ * _get_osfhandle().  This is necessary because we use _get_osfhandle()
+ * to check the validity of the fd before we try to call close() on
+ * it as attempting to close an invalid fd will cause the Windows CRT
+ * to abort() this program internally.
+ *
+ * Please see http://msdn.microsoft.com/zh-tw/library/ks2530z6%28v=vs.80%29.aspx
+ * for an explanation on this.
+ */
+#if (defined (_MSC_VER) && _MSC_VER >= 1400)
+#include <crtdbg.h>
+#endif
+
 #undef G_LOG_DOMAIN
 #include "glib.h"
 #define GSPAWN_HELPER
@@ -50,8 +64,7 @@ write_err_and_exit (gint    fd,
 /* We build gspawn-win32-helper.exe as a Windows GUI application
  * to avoid any temporarily flashing console windows in case
  * the gspawn function is invoked by a GUI program. Thus, no main()
- * but a WinMain(). We do, however, still use argc and argv tucked
- * away in the global __argc and __argv by the C runtime startup code.
+ * but a WinMain().
  */
 
 /* Info peeked from mingw runtime's source code. __wgetmainargs() is a
@@ -147,6 +160,34 @@ protect_wargv (wchar_t  **wargv,
   return argc;
 }
 
+#if (defined (_MSC_VER) && _MSC_VER >= 1400)
+/*
+ * This is the (empty) invalid parameter handler
+ * that is used for Visual C++ 2005 (and later) builds
+ * so that we can use this instead of the system automatically
+ * aborting the process.
+ *
+ * This is necessary as we use _get_oshandle() to check the validity
+ * of the file descriptors as we close them, so when an invalid file
+ * descriptor is passed into that function as we check on it, we get
+ * -1 as the result, instead of the gspawn helper program aborting.
+ *
+ * Please see http://msdn.microsoft.com/zh-tw/library/ks2530z6%28v=vs.80%29.aspx
+ * for an explanation on this.
+ */
+void myInvalidParameterHandler(
+   const wchar_t * expression,
+   const wchar_t * function,
+   const wchar_t * file,
+   unsigned int line,
+   uintptr_t pReserved
+)
+{
+  return;
+}
+#endif
+
+
 #ifndef HELPER_CONSOLE
 int _stdcall
 WinMain (struct HINSTANCE__ *hInstance,
@@ -169,31 +210,42 @@ main (int ignored_argc, char **ignored_argv)
   gint argv_zero_offset = ARG_PROGRAM;
   wchar_t **new_wargv;
   int argc;
+  char **argv;
   wchar_t **wargv, **wenvp;
   _startupinfo si = { 0 };
   char c;
 
-  g_assert (__argc >= ARG_COUNT);
+#if (defined (_MSC_VER) && _MSC_VER >= 1400)
+  /* set up our empty invalid parameter handler */
+  _invalid_parameter_handler oldHandler, newHandler;
+  newHandler = myInvalidParameterHandler;
+  oldHandler = _set_invalid_parameter_handler(newHandler);
+
+  /* Disable the message box for assertions. */
+  _CrtSetReportMode(_CRT_ASSERT, 0);
+#endif
 
   /* Fetch the wide-char argument vector */
   __wgetmainargs (&argc, &wargv, &wenvp, 0, &si);
 
-  /* We still have the system codepage args in __argv. We can look
-   * at the first args in which gspawn-win32.c passes us flags and
-   * fd numbers in __argv, as we know those are just ASCII anyway.
-   */
-  g_assert (argc == __argc);
+  g_assert (argc >= ARG_COUNT);
+
+  /* Convert unicode wargs to utf8 */
+  argv = g_new(char *, argc + 1);
+  for (i = 0; i < argc; i++)
+    argv[i] = g_utf16_to_utf8(wargv[i], -1, NULL, NULL, NULL);
+  argv[i] = NULL;
 
   /* argv[ARG_CHILD_ERR_REPORT] is the file descriptor number onto
    * which write error messages.
    */
-  child_err_report_fd = atoi (__argv[ARG_CHILD_ERR_REPORT]);
+  child_err_report_fd = atoi (argv[ARG_CHILD_ERR_REPORT]);
 
   /* Hack to implement G_SPAWN_FILE_AND_ARGV_ZERO. If
    * argv[ARG_CHILD_ERR_REPORT] is suffixed with a '#' it means we get
    * the program to run and its argv[0] separately.
    */
-  if (__argv[ARG_CHILD_ERR_REPORT][strlen (__argv[ARG_CHILD_ERR_REPORT]) - 1] == '#')
+  if (argv[ARG_CHILD_ERR_REPORT][strlen (argv[ARG_CHILD_ERR_REPORT]) - 1] == '#')
     argv_zero_offset++;
 
   /* argv[ARG_HELPER_SYNC] is the file descriptor number we read a
@@ -202,16 +254,16 @@ main (int ignored_argc, char **ignored_argv)
    * duplicate the process handle we sent it. Duplicating a handle
    * from another process works only if that other process exists.
    */
-  helper_sync_fd = atoi (__argv[ARG_HELPER_SYNC]);
+  helper_sync_fd = atoi (argv[ARG_HELPER_SYNC]);
 
   /* argv[ARG_STDIN..ARG_STDERR] are the file descriptor numbers 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:.
    */
-  if (__argv[ARG_STDIN][0] == '-')
+  if (argv[ARG_STDIN][0] == '-')
     ; /* Nothing */
-  else if (__argv[ARG_STDIN][0] == 'z')
+  else if (argv[ARG_STDIN][0] == 'z')
     {
       fd = open ("NUL:", O_RDONLY);
       if (fd != 0)
@@ -222,7 +274,7 @@ main (int ignored_argc, char **ignored_argv)
     }
   else
     {
-      fd = atoi (__argv[ARG_STDIN]);
+      fd = atoi (argv[ARG_STDIN]);
       if (fd != 0)
        {
          dup2 (fd, 0);
@@ -230,9 +282,9 @@ main (int ignored_argc, char **ignored_argv)
        }
     }
 
-  if (__argv[ARG_STDOUT][0] == '-')
+  if (argv[ARG_STDOUT][0] == '-')
     ; /* Nothing */
-  else if (__argv[ARG_STDOUT][0] == 'z')
+  else if (argv[ARG_STDOUT][0] == 'z')
     {
       fd = open ("NUL:", O_WRONLY);
       if (fd != 1)
@@ -243,7 +295,7 @@ main (int ignored_argc, char **ignored_argv)
     }
   else
     {
-      fd = atoi (__argv[ARG_STDOUT]);
+      fd = atoi (argv[ARG_STDOUT]);
       if (fd != 1)
        {
          dup2 (fd, 1);
@@ -251,9 +303,9 @@ main (int ignored_argc, char **ignored_argv)
        }
     }
 
-  if (__argv[ARG_STDERR][0] == '-')
+  if (argv[ARG_STDERR][0] == '-')
     ; /* Nothing */
-  else if (__argv[ARG_STDERR][0] == 'z')
+  else if (argv[ARG_STDERR][0] == 'z')
     {
       fd = open ("NUL:", O_WRONLY);
       if (fd != 2)
@@ -264,7 +316,7 @@ main (int ignored_argc, char **ignored_argv)
     }
   else
     {
-      fd = atoi (__argv[ARG_STDERR]);
+      fd = atoi (argv[ARG_STDERR]);
       if (fd != 2)
        {
          dup2 (fd, 2);
@@ -272,22 +324,23 @@ main (int ignored_argc, char **ignored_argv)
        }
     }
 
-  /* __argv[ARG_WORKING_DIRECTORY] is the directory in which to run the
+  /* argv[ARG_WORKING_DIRECTORY] is the directory in which to run the
    * process.  If "-", don't change directory.
    */
-  if (__argv[ARG_WORKING_DIRECTORY][0] == '-' &&
-      __argv[ARG_WORKING_DIRECTORY][1] == 0)
+  if (argv[ARG_WORKING_DIRECTORY][0] == '-' &&
+      argv[ARG_WORKING_DIRECTORY][1] == 0)
     ; /* Nothing */
   else if (_wchdir (wargv[ARG_WORKING_DIRECTORY]) < 0)
     write_err_and_exit (child_err_report_fd, CHILD_CHDIR_FAILED);
 
-  /* __argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
+  /* argv[ARG_CLOSE_DESCRIPTORS] is "y" if file descriptors from 3
    *  upwards should be closed
    */
-  if (__argv[ARG_CLOSE_DESCRIPTORS][0] == 'y')
+  if (argv[ARG_CLOSE_DESCRIPTORS][0] == 'y')
     for (i = 3; i < 1000; i++) /* FIXME real limit? */
       if (i != child_err_report_fd && i != helper_sync_fd)
-       close (i);
+        if (_get_osfhandle (i) != -1)
+          close (i);
 
   /* We don't want our child to inherit the error report and
    * helper sync fds.
@@ -295,16 +348,16 @@ main (int ignored_argc, char **ignored_argv)
   child_err_report_fd = dup_noninherited (child_err_report_fd, _O_WRONLY);
   helper_sync_fd = dup_noninherited (helper_sync_fd, _O_RDONLY);
 
-  /* __argv[ARG_WAIT] is "w" to wait for the program to exit */
-  if (__argv[ARG_WAIT][0] == 'w')
+  /* argv[ARG_WAIT] is "w" to wait for the program to exit */
+  if (argv[ARG_WAIT][0] == 'w')
     mode = P_WAIT;
   else
     mode = P_NOWAIT;
 
-  /* __argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */
+  /* argv[ARG_USE_PATH] is "y" to use PATH, otherwise not */
 
-  /* __argv[ARG_PROGRAM] is executable file to run,
-   * __argv[argv_zero_offset]... is its argv. argv_zero_offset equals
+  /* argv[ARG_PROGRAM] is executable file to run,
+   * argv[argv_zero_offset]... is its argv. argv_zero_offset equals
    * ARG_PROGRAM unless G_SPAWN_FILE_AND_ARGV_ZERO was used, in which
    * case we have a separate executable name and argv[0].
    */
@@ -314,7 +367,7 @@ main (int ignored_argc, char **ignored_argv)
    */
   protect_wargv (wargv + argv_zero_offset, &new_wargv);
 
-  if (__argv[ARG_USE_PATH][0] == 'y')
+  if (argv[ARG_USE_PATH][0] == 'y')
     handle = _wspawnvp (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv);
   else
     handle = _wspawnv (mode, wargv[ARG_PROGRAM], (const wchar_t **) new_wargv);
@@ -329,5 +382,7 @@ main (int ignored_argc, char **ignored_argv)
 
   read (helper_sync_fd, &c, 1);
 
+  g_strfreev (argv);
+
   return 0;
 }