using System.IO;
using System.Text;
+using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime.CompilerServices;
public IntPtr thread_handle;
public int pid; // Contains -GetLastError () on failure.
public int tid;
- public string [] envKeys;
- public string [] envValues;
+ public string[] envVariables;
public string UserName;
public string Domain;
public IntPtr Password;
var procInfo = new ProcInfo ();
if (startInfo.HaveEnvVars) {
- string [] strs = new string [startInfo.EnvironmentVariables.Count];
- startInfo.EnvironmentVariables.Keys.CopyTo (strs, 0);
- procInfo.envKeys = strs;
+ List<string> envVariables = null;
+ StringBuilder sb = null;
- strs = new string [startInfo.EnvironmentVariables.Count];
- startInfo.EnvironmentVariables.Values.CopyTo (strs, 0);
- procInfo.envValues = strs;
+ foreach (DictionaryEntry de in startInfo.EnvironmentVariables) {
+ if (de.Value == null)
+ continue;
+
+ if (envVariables == null)
+ envVariables = new List<string> ();
+
+ if (sb == null)
+ sb = new StringBuilder ();
+ else
+ sb.Clear ();
+
+ sb.Append ((string) de.Key);
+ sb.Append ('=');
+ sb.Append ((string) de.Value);
+
+ envVariables.Add (sb.ToString ());
+ }
+
+ procInfo.envVariables = envVariables?.ToArray ();
}
MonoIOError error;
ICALL(PERFCTRCAT_8, "InstanceExistsInternal", mono_perfcounter_instance_exists)
ICALL_TYPE(PROCESS, "System.Diagnostics.Process", PROCESS_1)
-ICALL(PROCESS_1, "CreateProcess_internal(System.Diagnostics.ProcessStartInfo,intptr,intptr,intptr,System.Diagnostics.Process/ProcInfo&)", ves_icall_System_Diagnostics_Process_CreateProcess_internal)
+ICALL(PROCESS_1, "CreateProcess_internal", ves_icall_System_Diagnostics_Process_CreateProcess_internal)
ICALL(PROCESS_4, "GetModules_internal(intptr)", ves_icall_System_Diagnostics_Process_GetModules_internal)
ICALL(PROCESS_5H, "GetProcessData", ves_icall_System_Diagnostics_Process_GetProcessData)
ICALL(PROCESS_6, "GetProcess_internal(int)", ves_icall_System_Diagnostics_Process_GetProcess_internal)
}
static gboolean
-process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new_environ,
+process_create (const gunichar2 *appname, const gunichar2 *cmdline,
const gunichar2 *cwd, StartupHandles *startup_handles, MonoW32ProcessInfo *process_info)
{
#if defined (HAVE_FORK) && defined (HAVE_EXECVE)
char *cmd = NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL;
char *dir = NULL, **env_strings = NULL, **argv = NULL;
- guint32 i, env_count = 0;
+ guint32 i;
gboolean ret = FALSE;
gpointer handle = NULL;
GError *gerr = NULL;
g_free (newapp);
if (newcmd) {
- ret = process_create (NULL, newcmd, new_environ, cwd, startup_handles, process_info);
+ ret = process_create (NULL, newcmd, cwd, startup_handles, process_info);
g_free (newcmd);
err_fd = GPOINTER_TO_UINT (GetStdHandle (STD_ERROR_HANDLE));
}
- /* new_environ is a block of NULL-terminated strings, which
- * is itself NULL-terminated. Of course, passing an array of
- * string pointers would have made things too easy :-(
+ /*
+ * process->env_variables is a an array of MonoString*
*
* If new_environ is not NULL it specifies the entire set of
* environment variables in the new process. Otherwise the
* new process inherits the same environment.
*/
- if (new_environ) {
- gunichar2 *new_environp;
+ if (process_info->env_variables) {
+ gint i, str_length, var_length;
+ MonoString *var;
+ gunichar2 *str;
- /* Count the number of strings */
- for (new_environp = (gunichar2 *)new_environ; *new_environp; new_environp++) {
- env_count++;
- while (*new_environp)
- new_environp++;
- }
+ /* +2: one for the process handle value, and the last one is NULL */
+ env_strings = g_new0 (gchar*, mono_array_length (process_info->env_variables) + 2);
- /* +2: one for the process handle value, and the last
- * one is NULL
- */
- env_strings = g_new0 (char *, env_count + 2);
+ str = NULL;
+ str_length = 0;
- /* Copy each environ string into 'strings' turning it
- * into utf8 (or the requested encoding) at the same
- * time
- */
- env_count = 0;
- for (new_environp = (gunichar2 *)new_environ; *new_environp; new_environp++) {
- env_strings[env_count] = mono_unicode_to_external (new_environp);
- env_count++;
- while (*new_environp) {
- new_environp++;
+ /* Copy each environ string into 'strings' turning it into utf8 (or the requested encoding) at the same time */
+ for (i = 0; i < mono_array_length (process_info->env_variables); ++i) {
+ var = mono_array_get (process_info->env_variables, MonoString*, i);
+ var_length = mono_string_length (var);
+
+ /* str is a null-terminated copy of var */
+
+ if (var_length + 1 > str_length) {
+ str_length = var_length + 1;
+ str = g_renew (gunichar2, str, str_length);
}
+
+ memcpy (str, mono_string_chars (var), var_length * sizeof (gunichar2));
+ str [var_length] = '\0';
+
+ env_strings [i] = mono_unicode_to_external (str);
}
+
+ g_free (str);
} else {
+ guint32 env_count;
+
+ env_count = 0;
for (i = 0; environ[i] != NULL; i++)
env_count++;
- /* +2: one for the process handle value, and the last
- * one is NULL
- */
- env_strings = g_new0 (char *, env_count + 2);
+ /* +2: one for the process handle value, and the last one is NULL */
+ env_strings = g_new0 (gchar*, env_count + 2);
- /* Copy each environ string into 'strings' turning it
- * into utf8 (or the requested encoding) at the same
- * time
- */
- env_count = 0;
- for (i = 0; environ[i] != NULL; i++) {
- env_strings[env_count] = g_strdup (environ[i]);
- env_count++;
- }
+ /* Copy each environ string into 'strings' turning it into utf8 (or the requested encoding) at the same time */
+ for (i = 0; i < env_count; i++)
+ env_strings [i] = g_strdup (environ[i]);
}
/* Create a pipe to make sure the child doesn't exit before
ret = FALSE;
goto done;
}
- ret = process_create (NULL, args, NULL, lpDirectory, NULL, process_info);
+ ret = process_create (NULL, args, lpDirectory, NULL, process_info);
g_free (args);
if (!ret && GetLastError () == ERROR_OUTOFMEMORY)
ret = FALSE;
goto done;
}
- ret = process_create (NULL, args, NULL, lpDirectory, NULL, process_info);
+ ret = process_create (NULL, args, lpDirectory, NULL, process_info);
g_free (args);
if (!ret) {
if (GetLastError () != ERROR_OUTOFMEMORY)
gunichar2 *dir;
StartupHandles startup_handles;
gunichar2 *shell_path = NULL;
- gchar *env_vars = NULL;
MonoString *cmd = NULL;
memset (&startup_handles, 0, sizeof (startup_handles));
return FALSE;
}
- if (process_info->env_keys) {
- gint i, len;
- MonoString *ms;
- MonoString *key, *value;
- gunichar2 *str, *ptr;
- gunichar2 *equals16;
-
- for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
- ms = mono_array_get (process_info->env_values, MonoString *, i);
- if (ms == NULL)
- continue;
-
- len += mono_string_length (ms) * sizeof (gunichar2);
- ms = mono_array_get (process_info->env_keys, MonoString *, i);
- len += mono_string_length (ms) * sizeof (gunichar2);
- len += 2 * sizeof (gunichar2);
- }
-
- equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
- ptr = str = g_new0 (gunichar2, len + 1);
- for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
- value = mono_array_get (process_info->env_values, MonoString *, i);
- if (value == NULL)
- continue;
-
- key = mono_array_get (process_info->env_keys, MonoString *, i);
- memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
- ptr += mono_string_length (key);
-
- memcpy (ptr, equals16, sizeof (gunichar2));
- ptr++;
-
- memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
- ptr += mono_string_length (value);
- ptr++;
- }
-
- g_free (equals16);
- env_vars = (gchar *) str;
- }
-
/* The default dir name is "". Turn that into NULL to mean "current directory" */
dir = proc_start_info->working_directory && mono_string_length (proc_start_info->working_directory) > 0 ?
mono_string_chars (proc_start_info->working_directory) : NULL;
- ret = process_create (shell_path, cmd ? mono_string_chars (cmd): NULL, env_vars, dir, &startup_handles, process_info);
+ ret = process_create (shell_path, cmd ? mono_string_chars (cmd): NULL, dir, &startup_handles, process_info);
- g_free (env_vars);
if (shell_path != NULL)
g_free (shell_path);
gboolean
mono_process_create_process (MonoW32ProcessInfo *mono_process_info, gunichar2 *shell_path, MonoString *cmd,
- guint32 creation_flags, gchar *env_vars, gunichar2 *dir, STARTUPINFO *start_info,
+ guint32 creation_flags, gunichar2 *env_vars, gunichar2 *dir, STARTUPINFO *start_info,
PROCESS_INFORMATION *process_info);
MonoBoolean
gboolean
mono_process_create_process (MonoW32ProcessInfo *mono_process_info, gunichar2 *shell_path, MonoString *cmd, guint32 creation_flags,
- gchar *env_vars, gunichar2 *dir, STARTUPINFO *start_info, PROCESS_INFORMATION *process_info)
+ gunichar2 *env_vars, gunichar2 *dir, STARTUPINFO *start_info, PROCESS_INFORMATION *process_info)
{
MonoError mono_error;
gchar *api_name = "";
}
#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
-static gchar*
-mono_process_unquote_application_name (gchar *appname)
-{
- size_t len = strlen (appname);
- if (len) {
- if (appname[len-1] == '\"')
- appname[len-1] = '\0';
- if (appname[0] == '\"')
- appname++;
- }
-
- return appname;
-}
-
-static gchar*
-mono_process_quote_path (const gchar *path)
-{
- gchar *res = g_shell_quote (path);
- gchar *q = res;
- while (*q) {
- if (*q == '\'')
- *q = '\"';
- q++;
- }
- return res;
-}
-
-/* Only used when UseShellExecute is false */
-static gboolean
-mono_process_complete_path (const gunichar2 *appname, gchar **completed)
-{
- gchar *utf8app, *utf8appmemory;
- gchar *found;
-
- utf8appmemory = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
- utf8app = mono_process_unquote_application_name (utf8appmemory);
-
- if (g_path_is_absolute (utf8app)) {
- *completed = mono_process_quote_path (utf8app);
- g_free (utf8appmemory);
- return TRUE;
- }
-
- if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) {
- *completed = mono_process_quote_path (utf8app);
- g_free (utf8appmemory);
- return TRUE;
- }
-
- found = g_find_program_in_path (utf8app);
- if (found == NULL) {
- *completed = NULL;
- g_free (utf8appmemory);
- return FALSE;
- }
-
- *completed = mono_process_quote_path (found);
- g_free (found);
- g_free (utf8appmemory);
- return TRUE;
-}
-
#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
MonoBoolean
ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStartInfo *proc_start_info, MonoW32ProcessInfo *process_info)
startinfo->hStdError = stderr_handle;
return;
}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
static gboolean
mono_process_create_process (MonoW32ProcessInfo *mono_process_info, gunichar2 *shell_path,
- MonoString *cmd, guint32 creation_flags, gchar *env_vars,
+ MonoString *cmd, guint32 creation_flags, gunichar2 *env_vars,
gunichar2 *dir, STARTUPINFO *start_info, PROCESS_INFORMATION *process_info)
{
gboolean result = FALSE;
shell_path,
cmd ? mono_string_chars (cmd) : NULL,
creation_flags,
- env_vars, dir, start_info, process_info);
+ (gchar*) env_vars, dir, start_info, process_info);
} else {
NULL,
TRUE,
creation_flags,
- env_vars,
+ (gchar*) env_vars,
dir,
start_info,
process_info);
}
#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
+static gchar*
+process_unquote_application_name (gchar *appname)
+{
+ size_t len = strlen (appname);
+ if (len) {
+ if (appname[len-1] == '\"')
+ appname[len-1] = '\0';
+ if (appname[0] == '\"')
+ appname++;
+ }
+
+ return appname;
+}
+
+static gchar*
+process_quote_path (const gchar *path)
+{
+ gchar *res = g_shell_quote (path);
+ gchar *q = res;
+ while (*q) {
+ if (*q == '\'')
+ *q = '\"';
+ q++;
+ }
+ return res;
+}
+
+/* Only used when UseShellExecute is false */
+static gboolean
+process_complete_path (const gunichar2 *appname, gchar **completed)
+{
+ gchar *utf8app, *utf8appmemory;
+ gchar *found;
+
+ utf8appmemory = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
+ utf8app = process_unquote_application_name (utf8appmemory);
+
+ if (g_path_is_absolute (utf8app)) {
+ *completed = process_quote_path (utf8app);
+ g_free (utf8appmemory);
+ return TRUE;
+ }
+
+ if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) {
+ *completed = process_quote_path (utf8app);
+ g_free (utf8appmemory);
+ return TRUE;
+ }
+
+ found = g_find_program_in_path (utf8app);
+ if (found == NULL) {
+ *completed = NULL;
+ g_free (utf8appmemory);
+ return FALSE;
+ }
+
+ *completed = process_quote_path (found);
+ g_free (found);
+ g_free (utf8appmemory);
+ return TRUE;
+}
+
static gboolean
-mono_process_get_shell_arguments (MonoW32ProcessStartInfo *proc_start_info, gunichar2 **shell_path, MonoString **cmd)
+process_get_shell_arguments (MonoW32ProcessStartInfo *proc_start_info, gunichar2 **shell_path, MonoString **cmd)
{
gchar *spath = NULL;
gchar *new_cmd, *cmd_utf8;
*shell_path = NULL;
*cmd = proc_start_info->arguments;
- mono_process_complete_path (mono_string_chars (proc_start_info->filename), &spath);
+ process_complete_path (mono_string_chars (proc_start_info->filename), &spath);
if (spath != NULL) {
/* Seems like our CreateProcess does not work as the windows one.
* This hack is needed to deal with paths containing spaces */
STARTUPINFO startinfo={0};
PROCESS_INFORMATION procinfo;
gunichar2 *shell_path = NULL;
- gchar *env_vars = NULL;
+ gunichar2 *env_vars = NULL;
MonoString *cmd = NULL;
guint32 creation_flags;
if (proc_start_info->create_no_window)
creation_flags |= CREATE_NO_WINDOW;
- if (mono_process_get_shell_arguments (proc_start_info, &shell_path, &cmd) == FALSE) {
+ if (process_get_shell_arguments (proc_start_info, &shell_path, &cmd) == FALSE) {
process_info->pid = -ERROR_FILE_NOT_FOUND;
return FALSE;
}
- if (process_info->env_keys) {
- gint i, len;
- MonoString *ms;
- MonoString *key, *value;
+ if (process_info->env_variables) {
+ gint i, len;
+ MonoString *var;
gunichar2 *str, *ptr;
- gunichar2 *equals16;
- for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
- ms = mono_array_get (process_info->env_values, MonoString *, i);
- if (ms == NULL)
- continue;
+ len = 0;
+
+ for (i = 0; i < mono_array_length (process_info->env_variables); i++) {
+ var = mono_array_get (process_info->env_variables, MonoString*, i);
+
+ len += mono_string_length (var) * sizeof (gunichar2);
- len += mono_string_length (ms) * sizeof (gunichar2);
- ms = mono_array_get (process_info->env_keys, MonoString *, i);
- len += mono_string_length (ms) * sizeof (gunichar2);
- len += 2 * sizeof (gunichar2);
+ /* it's null-separated and null-terminated */
+ len += sizeof (gunichar2);
}
- equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
- ptr = str = g_new0 (gunichar2, len + 1);
- for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
- value = mono_array_get (process_info->env_values, MonoString *, i);
- if (value == NULL)
- continue;
+ env_vars = ptr = g_new (gunichar2, len);
- key = mono_array_get (process_info->env_keys, MonoString *, i);
- memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
- ptr += mono_string_length (key);
+ for (i = 0; i < mono_array_length (process_info->env_variables); i++) {
+ var = mono_array_get (process_info->env_variables, MonoString*, i);
- memcpy (ptr, equals16, sizeof (gunichar2));
- ptr++;
+ memcpy (ptr, mono_string_chars (var), mono_string_length (var) * sizeof (gunichar2));
+ ptr += mono_string_length (key);
- memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
- ptr += mono_string_length (value);
- ptr++;
+ memset (ptr, 0, sizeof (gunichar2));
+ ptr += 1;
}
-
- g_free (equals16);
- env_vars = (gchar *) str;
}
/* The default dir name is "". Turn that into NULL to mean
gpointer thread_handle;
guint32 pid; /* Contains GetLastError () on failure */
guint32 tid;
- MonoArray *env_keys;
- MonoArray *env_values;
+ MonoArray *env_variables;
MonoString *username;
MonoString *domain;
gpointer password; /* BSTR from SecureString in 2.0 profile */