[Process] Concatenate envirnoment key and value in managed
authorLudovic Henry <ludovic@xamarin.com>
Thu, 1 Dec 2016 18:13:32 +0000 (13:13 -0500)
committerLudovic Henry <ludovic@xamarin.com>
Sat, 3 Dec 2016 23:13:12 +0000 (18:13 -0500)
mcs/class/System/System.Diagnostics/Process.cs
mono/metadata/icall-def.h
mono/metadata/w32process-unix.c
mono/metadata/w32process-win32-internals.h
mono/metadata/w32process-win32-uwp.c
mono/metadata/w32process-win32.c
mono/metadata/w32process.h

index 2cf28e614fecfe92558640a28ef4b48865b675f4..fcdd0c072d87604ab4827eb15eb29944c8988565 100644 (file)
@@ -34,6 +34,7 @@
 
 using System.IO;
 using System.Text;
+using System.Collections;
 using System.ComponentModel;
 using System.ComponentModel.Design;
 using System.Runtime.CompilerServices;
@@ -62,8 +63,7 @@ namespace System.Diagnostics
                        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;
@@ -651,13 +651,29 @@ namespace System.Diagnostics
                        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;
index 6a005a6886b48d2708e413b5b1a001492dd3a690..9a197f7cf1c9112affb6418feb06b2ed62019c4c 100644 (file)
@@ -240,7 +240,7 @@ ICALL(PERFCTRCAT_7, "GetInstanceNames", mono_perfcounter_instance_names)
 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)
index 0462cb2e596ee413af3edef9c43f3c2f695154d6..5739624784945e99f4064d283f488d8f5b5bfa78 100644 (file)
@@ -1586,13 +1586,13 @@ leave:
 }
 
 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;
@@ -1855,7 +1855,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
                        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);
 
@@ -1898,59 +1898,56 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
                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
@@ -2137,7 +2134,7 @@ ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStar
                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)
@@ -2194,7 +2191,7 @@ ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStar
                        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)
@@ -2282,7 +2279,6 @@ ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStart
        gunichar2 *dir;
        StartupHandles startup_handles;
        gunichar2 *shell_path = NULL;
-       gchar *env_vars = NULL;
        MonoString *cmd = NULL;
 
        memset (&startup_handles, 0, sizeof (startup_handles));
@@ -2295,54 +2291,12 @@ ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStart
                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);
 
index a5eb90a8cdd3c6b2d210af2c6c9b54a3e00065ca..e5f115362625e35d01af053201bd6990d2bd5fb3 100644 (file)
@@ -21,7 +21,7 @@ mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle,
 
 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
index cbd46b794aa603a3aec89ba3f55843c19949b6b7..43da61dda2d98425cf4ae620c15e0618a1a953c0 100644 (file)
@@ -130,7 +130,7 @@ mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle, HANDL
 
 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 = "";
index 15cfd4d61a230e8f590535c808aeaed513605e0a..782deff58f8b8590f8277f8c80d21f0b069f4947 100644 (file)
@@ -64,68 +64,6 @@ ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid)
 }
 #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)
@@ -191,12 +129,10 @@ mono_process_init_startup_info (HANDLE stdin_handle, HANDLE stdout_handle, HANDL
        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;
@@ -211,7 +147,7 @@ mono_process_create_process (MonoW32ProcessInfo *mono_process_info, gunichar2 *s
                                                  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 {
 
@@ -221,7 +157,7 @@ mono_process_create_process (MonoW32ProcessInfo *mono_process_info, gunichar2 *s
                                        NULL,
                                        TRUE,
                                        creation_flags,
-                                       env_vars,
+                                       (gchar*) env_vars,
                                        dir,
                                        start_info,
                                        process_info);
@@ -232,8 +168,70 @@ mono_process_create_process (MonoW32ProcessInfo *mono_process_info, gunichar2 *s
 }
 #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;
@@ -242,7 +240,7 @@ mono_process_get_shell_arguments (MonoW32ProcessStartInfo *proc_start_info, guni
        *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 */
@@ -276,7 +274,7 @@ ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStart
        STARTUPINFO startinfo={0};
        PROCESS_INFORMATION procinfo;
        gunichar2 *shell_path = NULL;
-       gchar *env_vars = NULL;
+       gunichar2 *env_vars = NULL;
        MonoString *cmd = NULL;
        guint32 creation_flags;
 
@@ -286,50 +284,38 @@ ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStart
        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
index 7df9caf67f7a05f2df60e4fc78a102a4812897a5..af283182a907617f3ebe9b13482b271dd452e5df 100644 (file)
@@ -36,8 +36,7 @@ typedef struct
        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 */