#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
/* 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
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,
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
* 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)
}
else
{
- fd = atoi (__argv[ARG_STDIN]);
+ fd = atoi (argv[ARG_STDIN]);
if (fd != 0)
{
dup2 (fd, 0);
}
}
- 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)
}
else
{
- fd = atoi (__argv[ARG_STDOUT]);
+ fd = atoi (argv[ARG_STDOUT]);
if (fd != 1)
{
dup2 (fd, 1);
}
}
- 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)
}
else
{
- fd = atoi (__argv[ARG_STDERR]);
+ fd = atoi (argv[ARG_STDERR]);
if (fd != 2)
{
dup2 (fd, 2);
}
}
- /* __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.
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].
*/
*/
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);
read (helper_sync_fd, &c, 1);
+ g_strfreev (argv);
+
return 0;
}