X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fprocess.c;h=1d08c7f481397d5a4175c83f1e4826f0cdc9bbdb;hb=ba6dad488203bdacecee7f23ef35f576ad94f04d;hp=b0aced955acb505f130732aa8bd69e795c08f6f5;hpb=234225d112c4b018b8d1796f4c06a15812137500;p=mono.git diff --git a/mono/metadata/process.c b/mono/metadata/process.c index b0aced955ac..1d08c7f4813 100644 --- a/mono/metadata/process.c +++ b/mono/metadata/process.c @@ -5,6 +5,7 @@ * Dick Porter (dick@ximian.com) * * (C) 2002 Ximian, Inc. + * Copyright (c) 2002-2006 Novell, Inc. */ #include @@ -97,15 +98,32 @@ static guint32 unicode_bytes (const gunichar2 *str) } while(1); } +static gunichar2* +unicode_get (const gunichar2 *str) +{ + gunichar2 *swapped; + int i, len; + + len = unicode_bytes (str); + swapped = g_malloc0 (len); + i = 0; + while (str [i]) { + swapped [i] = GUINT16_FROM_LE (str [i]); + i ++; + } + + return swapped; +} + /* - * compare a null-terminated utf16 string and a normal string. + * compare a little-endian null-terminated utf16 string and a normal string. * Can be used only for ascii or latin1 chars. */ static gboolean -unicode_string_equals (const gunichar2 *str1, const guchar *str2) +unicode_string_equals (const gunichar2 *str1, const gchar *str2) { while (*str1 && *str2) { - if (*str1 != *str2) + if (GUINT16_TO_LE (*str1) != *str2) return FALSE; ++str1; ++str2; @@ -113,7 +131,7 @@ unicode_string_equals (const gunichar2 *str1, const guchar *str2) return *str1 == *str2; } -static void process_set_field_object (MonoObject *obj, const guchar *fieldname, +static void process_set_field_object (MonoObject *obj, const gchar *fieldname, MonoObject *data) { MonoClassField *field; @@ -125,10 +143,11 @@ static void process_set_field_object (MonoObject *obj, const guchar *fieldname, field=mono_class_get_field_from_name (mono_object_class (obj), fieldname); + /* FIXME: moving GC */ *(MonoObject **)(((char *)obj) + field->offset)=data; } -static void process_set_field_string (MonoObject *obj, const guchar *fieldname, +static void process_set_field_string (MonoObject *obj, const gchar *fieldname, const gunichar2 *val, guint32 len) { MonoClassField *field; @@ -143,12 +162,13 @@ static void process_set_field_string (MonoObject *obj, const guchar *fieldname, field=mono_class_get_field_from_name (mono_object_class (obj), fieldname); + /* FIXME: moving GC */ *(MonoString **)(((char *)obj) + field->offset)=string; } static void process_set_field_string_utf8 (MonoObject *obj, - const guchar *fieldname, - const guchar *val) + const gchar *fieldname, + const gchar *val) { MonoClassField *field; MonoString *string; @@ -162,10 +182,11 @@ static void process_set_field_string_utf8 (MonoObject *obj, field=mono_class_get_field_from_name (mono_object_class (obj), fieldname); + /* FIXME: moving GC */ *(MonoString **)(((char *)obj) + field->offset)=string; } -static void process_set_field_int (MonoObject *obj, const guchar *fieldname, +static void process_set_field_int (MonoObject *obj, const gchar *fieldname, guint32 val) { MonoClassField *field; @@ -180,7 +201,7 @@ static void process_set_field_int (MonoObject *obj, const guchar *fieldname, *(guint32 *)(((char *)obj) + field->offset)=val; } -static void process_set_field_bool (MonoObject *obj, const guchar *fieldname, +static void process_set_field_bool (MonoObject *obj, const gchar *fieldname, gboolean val) { MonoClassField *field; @@ -208,13 +229,13 @@ typedef struct { static gpointer process_get_versioninfo_block (gpointer data, version_data *block) { - block->data_len=*((guint16 *)data); + block->data_len=GUINT16_TO_LE (*((guint16 *)data)); data = (char *)data + sizeof(guint16); - block->value_len=*((guint16 *)data); + block->value_len=GUINT16_TO_LE (*((guint16 *)data)); data = (char *)data + sizeof(guint16); /* No idea what the type is supposed to indicate */ - block->type=*((guint16 *)data); + block->type=GUINT16_TO_LE (*((guint16 *)data)); data = (char *)data + sizeof(guint16); block->key=((gunichar2 *)data); @@ -284,7 +305,7 @@ static gpointer process_read_string_block (MonoObject *filever, } string_len=string_len+block.data_len; - value=(gunichar2 *)data_ptr; + value=unicode_get ((gunichar2 *)data_ptr); /* Skip over the value */ data_ptr=((gunichar2 *)data_ptr)+block.value_len; @@ -319,6 +340,7 @@ static gpointer process_read_string_block (MonoObject *filever, */ } } + g_free (value); } return(data_ptr); @@ -334,6 +356,7 @@ static gpointer process_read_stringtable_block (MonoObject *filever, guint16 data_len) { version_data block; + gunichar2 *value; gchar *language; guint16 string_len=36; /* length of the StringFileInfo block */ @@ -361,7 +384,8 @@ static gpointer process_read_stringtable_block (MonoObject *filever, } string_len=string_len+block.data_len; - language = g_utf16_to_utf8 (block.key, unicode_bytes (block.key), NULL, NULL, NULL); + value = unicode_get (block.key); + language = g_utf16_to_utf8 (value, unicode_bytes (block.key), NULL, NULL, NULL); g_strdown (language); /* Kludge: treat en_US as neutral too */ @@ -384,7 +408,8 @@ static gpointer process_read_stringtable_block (MonoObject *filever, FALSE); } g_free (language); - + g_free (value); + if(data_ptr==NULL) { /* Child block hit padding */ #ifdef DEBUG @@ -457,6 +482,7 @@ static void process_get_fileversion (MonoObject *filever, MonoImage *image) data=mono_image_rva_map (image, version_info->rde_data_offset); + g_free (version_info); if(data==NULL) { return; } @@ -587,6 +613,7 @@ static void process_add_module (GPtrArray *modules, MonoAssembly *ass) process_set_field_string_utf8 (item, "modulename", modulename); g_free (modulename); + /* FIXME: moving GC */ g_ptr_array_add (modules, item); } @@ -630,11 +657,10 @@ MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject modules_list->len); for(i=0; ilen; i++) { - mono_array_set (arr, MonoObject *, i, - g_ptr_array_index (modules_list, i)); + mono_array_setref (arr, i, g_ptr_array_index (modules_list, i)); } - g_ptr_array_free (modules_list, FALSE); + g_ptr_array_free (modules_list, TRUE); return(arr); } @@ -642,7 +668,7 @@ MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename) { MonoImage *image; - guchar *filename_utf8; + gchar *filename_utf8; MONO_ARCH_SAVE_REGS; @@ -718,7 +744,54 @@ complete_path (const gunichar2 *appname, gchar **completed) return TRUE; } -MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *appname, MonoString *cmd, MonoString *dirname, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info) +MonoBoolean ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_info) +{ + SHELLEXECUTEINFO shellex = {0}; + gboolean ret; + + shellex.cbSize = sizeof(SHELLEXECUTEINFO); + shellex.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE; + shellex.nShow = SW_SHOWNORMAL; + + if (proc_start_info->filename != NULL) { + shellex.lpFile = mono_string_chars (proc_start_info->filename); + } + + if (proc_start_info->arguments != NULL) { + shellex.lpParameters = mono_string_chars (proc_start_info->arguments); + } + + if (proc_start_info->verb != NULL && + mono_string_length (proc_start_info->verb) != 0) { + shellex.lpVerb = mono_string_chars (proc_start_info->verb); + } + + if (proc_start_info->working_directory != NULL && + mono_string_length (proc_start_info->working_directory) != 0) { + shellex.lpDirectory = mono_string_chars (proc_start_info->working_directory); + } + + ret = ShellExecuteEx (&shellex); + if (ret == FALSE) { + process_info->pid = -GetLastError (); + } else { + process_info->process_handle = shellex.hProcess; + process_info->thread_handle = NULL; + /* It appears that there's no way to get the pid from a + * process handle before windows xp. Really. + */ +#ifdef HAVE_GETPROCESSID + process_info->pid = GetProcessId (shellex.hProcess); +#else + process_info->pid = 0; +#endif + process_info->tid = 0; + } + + return (ret); +} + +MonoBoolean ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoProcessStartInfo *proc_start_info, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info) { gboolean ret; gunichar2 *dir; @@ -727,72 +800,46 @@ MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *app gunichar2 *shell_path = NULL; gchar *env_vars = NULL; gboolean free_shell_path = TRUE; - gchar *newcmd, *tmp; + gchar *spath = NULL; + MonoString *cmd = proc_start_info->arguments; + guint32 creation_flags, logon_flags; - MONO_ARCH_SAVE_REGS; - startinfo.cb=sizeof(STARTUPINFO); startinfo.dwFlags=STARTF_USESTDHANDLES; startinfo.hStdInput=stdin_handle; startinfo.hStdOutput=stdout_handle; startinfo.hStdError=stderr_handle; - - if (process_info->use_shell) { - const gchar *spath; - const gchar *shell_args; -#ifdef PLATFORM_WIN32 - spath = g_getenv ("COMSPEC"); - shell_args = "/c %s"; -#else - spath = g_getenv ("SHELL"); - shell_args = "-c %s"; -#endif - if (spath != NULL) { - gsize dummy; - gchar *quoted; - shell_path = mono_unicode_from_external (spath, &dummy); - tmp = mono_string_to_utf8 (cmd); - quoted = g_shell_quote (tmp); -#ifdef PLATFORM_WIN32 - { - gchar *q = quoted; - while (*q) { - if (*q == '\'') - *q = '\"'; - q++; - } - } -#endif - newcmd = g_strdup_printf (shell_args, quoted); - g_free (quoted); - g_free (tmp); - cmd = mono_string_new (mono_domain_get (), newcmd); - g_free (newcmd); - } - } else { - gchar *spath = NULL; - shell_path = mono_string_chars (appname); - complete_path (shell_path, &spath); - if (spath == NULL) { - process_info->pid = -ERROR_FILE_NOT_FOUND; - return FALSE; - } + creation_flags = CREATE_UNICODE_ENVIRONMENT; + if (proc_start_info->create_no_window) + creation_flags |= CREATE_NO_WINDOW; + + shell_path = mono_string_chars (proc_start_info->filename); + complete_path (shell_path, &spath); + if (spath == NULL) { + process_info->pid = -ERROR_FILE_NOT_FOUND; + return FALSE; + } #ifdef PLATFORM_WIN32 - /* Seems like our CreateProcess does not work as the windows one. - * This hack is needed to deal with paths containing spaces */ - shell_path = NULL; - free_shell_path = FALSE; + /* Seems like our CreateProcess does not work as the windows one. + * This hack is needed to deal with paths containing spaces */ + shell_path = NULL; + free_shell_path = FALSE; + if (cmd) { + gchar *newcmd, *tmp; tmp = mono_string_to_utf8 (cmd); newcmd = g_strdup_printf ("%s %s", spath, tmp); cmd = mono_string_new_wrapper (newcmd); - g_free (newcmd); g_free (tmp); + g_free (newcmd); + } + else { + cmd = mono_string_new_wrapper (spath); + } #else - shell_path = g_utf8_to_utf16 (spath, -1, NULL, NULL, NULL); + shell_path = g_utf8_to_utf16 (spath, -1, NULL, NULL, NULL); #endif - g_free (spath); - } + g_free (spath); if (process_info->env_keys != NULL) { gint i, len; @@ -838,13 +885,18 @@ MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *app /* The default dir name is "". Turn that into NULL to mean * "current directory" */ - if(mono_string_length (dirname)==0) { + if(mono_string_length (proc_start_info->working_directory)==0) { dir=NULL; } else { - dir=mono_string_chars (dirname); + dir=mono_string_chars (proc_start_info->working_directory); + } + + if (process_info->username) { + logon_flags = process_info->load_user_profile ? LOGON_WITH_PROFILE : 0; + ret=CreateProcessWithLogonW (mono_string_chars (process_info->username), process_info->domain ? mono_string_chars (process_info->domain) : NULL, process_info->password, logon_flags, shell_path, cmd? mono_string_chars (cmd): NULL, creation_flags, env_vars, dir, &startinfo, &procinfo); + } else { + ret=CreateProcess (shell_path, cmd? mono_string_chars (cmd): NULL, NULL, NULL, TRUE, creation_flags, env_vars, dir, &startinfo, &procinfo); } - - ret=CreateProcess (shell_path, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env_vars, dir, &startinfo, &procinfo); g_free (env_vars); if (free_shell_path) @@ -854,7 +906,8 @@ MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *app process_info->process_handle=procinfo.hProcess; /*process_info->thread_handle=procinfo.hThread;*/ process_info->thread_handle=NULL; - CloseHandle(procinfo.hThread); + if (procinfo.hThread != NULL && procinfo.hThread != INVALID_HANDLE_VALUE) + CloseHandle(procinfo.hThread); process_info->pid=procinfo.dwProcessId; process_info->tid=procinfo.dwThreadId; } else { @@ -1043,3 +1096,34 @@ ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig) return TerminateProcess (process, -sig); } +gint64 +ves_icall_System_Diagnostics_Process_Times (HANDLE process, gint32 type) +{ + FILETIME create_time, exit_time, kernel_time, user_time; + + if (GetProcessTimes (process, &create_time, &exit_time, &kernel_time, &user_time)) { + if (type == 0) + return *(gint64*)&user_time; + else if (type == 1) + return *(gint64*)&kernel_time; + /* system + user time: FILETIME can be (memory) cast to a 64 bit int */ + return *(gint64*)&kernel_time + *(gint64*)&user_time; + } + return 0; +} + +gint32 +ves_icall_System_Diagnostics_Process_GetPriorityClass (HANDLE process, gint32 *error) +{ + gint32 ret = GetPriorityClass (process); + *error = ret == 0 ? GetLastError () : 0; + return ret; +} + +MonoBoolean +ves_icall_System_Diagnostics_Process_SetPriorityClass (HANDLE process, gint32 priority_class, gint32 *error) +{ + gboolean ret = SetPriorityClass (process, priority_class); + *error = ret == 0 ? GetLastError () : 0; + return ret; +}