2 * process.c: System.Diagnostics.Process support
5 * Dick Porter (dick@ximian.com)
7 * Copyright 2002 Ximian, Inc.
8 * Copyright 2002-2006 Novell, Inc.
16 #include <mono/metadata/object-internals.h>
17 #include <mono/metadata/process.h>
18 #include <mono/metadata/assembly.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/image.h>
21 #include <mono/metadata/cil-coff.h>
22 #include <mono/metadata/exception.h>
23 #include <mono/metadata/threadpool-ms-io.h>
24 #include <mono/utils/strenc.h>
25 #include <mono/utils/mono-proclib.h>
26 #include <mono/io-layer/io-layer.h>
27 /* FIXME: fix this code to not depend so much on the internals */
28 #include <mono/metadata/class-internals.h>
31 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
34 HANDLE ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid)
38 /* GetCurrentProcess returns a pseudo-handle, so use
41 handle=OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid);
44 /* FIXME: Throw an exception */
52 ves_icall_System_Diagnostics_Process_GetPid_internal (void)
54 return mono_process_current_pid ();
57 void ves_icall_System_Diagnostics_Process_Process_free_internal (MonoObject *this,
61 g_message ("%s: Closing process %p, handle %p", __func__, this, process);
64 #if defined(TARGET_WIN32) || defined(HOST_WIN32)
65 CloseHandle (process);
67 CloseProcess (process);
71 #define STASH_SYS_ASS(this) \
72 if(system_assembly == NULL) { \
73 system_assembly=this->vtable->klass->image; \
76 static MonoImage *system_assembly=NULL;
78 static guint32 unicode_chars (const gunichar2 *str)
90 static void process_set_field_object (MonoObject *obj, const gchar *fieldname,
93 MonoClassField *field;
95 LOGDEBUG (g_message ("%s: Setting field %s to object at %p", __func__, fieldname, data));
97 field=mono_class_get_field_from_name (mono_object_class (obj),
99 mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, data);
102 static void process_set_field_string (MonoObject *obj, const gchar *fieldname,
103 const gunichar2 *val, guint32 len)
105 MonoClassField *field;
108 LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__, fieldname, g_utf16_to_utf8 (val, len, NULL, NULL, NULL)));
110 string=mono_string_new_utf16 (mono_object_domain (obj), val, len);
112 field=mono_class_get_field_from_name (mono_object_class (obj),
114 mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, (MonoObject*)string);
117 static void process_set_field_string_char (MonoObject *obj, const gchar *fieldname,
120 MonoClassField *field;
123 LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__, fieldname, val));
125 string=mono_string_new (mono_object_domain (obj), val);
127 field=mono_class_get_field_from_name (mono_object_class (obj), fieldname);
128 mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, (MonoObject*)string);
131 static void process_set_field_int (MonoObject *obj, const gchar *fieldname,
134 MonoClassField *field;
136 LOGDEBUG (g_message ("%s: Setting field %s to %d", __func__,fieldname, val));
138 field=mono_class_get_field_from_name (mono_object_class (obj),
140 *(guint32 *)(((char *)obj) + field->offset)=val;
143 static void process_set_field_intptr (MonoObject *obj, const gchar *fieldname,
146 MonoClassField *field;
148 LOGDEBUG (g_message ("%s: Setting field %s to %p", __func__, fieldname, val));
150 field=mono_class_get_field_from_name (mono_object_class (obj),
152 *(gpointer *)(((char *)obj) + field->offset)=val;
155 static void process_set_field_bool (MonoObject *obj, const gchar *fieldname,
158 MonoClassField *field;
160 LOGDEBUG (g_message ("%s: Setting field %s to %s", __func__, fieldname, val?"TRUE":"FALSE"));
162 field=mono_class_get_field_from_name (mono_object_class (obj),
164 *(guint8 *)(((char *)obj) + field->offset)=val;
167 #define SFI_COMMENTS "\\StringFileInfo\\%02X%02X%02X%02X\\Comments"
168 #define SFI_COMPANYNAME "\\StringFileInfo\\%02X%02X%02X%02X\\CompanyName"
169 #define SFI_FILEDESCRIPTION "\\StringFileInfo\\%02X%02X%02X%02X\\FileDescription"
170 #define SFI_FILEVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion"
171 #define SFI_INTERNALNAME "\\StringFileInfo\\%02X%02X%02X%02X\\InternalName"
172 #define SFI_LEGALCOPYRIGHT "\\StringFileInfo\\%02X%02X%02X%02X\\LegalCopyright"
173 #define SFI_LEGALTRADEMARKS "\\StringFileInfo\\%02X%02X%02X%02X\\LegalTrademarks"
174 #define SFI_ORIGINALFILENAME "\\StringFileInfo\\%02X%02X%02X%02X\\OriginalFilename"
175 #define SFI_PRIVATEBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\PrivateBuild"
176 #define SFI_PRODUCTNAME "\\StringFileInfo\\%02X%02X%02X%02X\\ProductName"
177 #define SFI_PRODUCTVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion"
178 #define SFI_SPECIALBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\SpecialBuild"
179 #define EMPTY_STRING (gunichar2*)"\000\000"
181 static void process_module_string_read (MonoObject *filever, gpointer data,
182 const gchar *fieldname,
183 guchar lang_hi, guchar lang_lo,
186 gchar *lang_key_utf8;
187 gunichar2 *lang_key, *buffer;
190 lang_key_utf8 = g_strdup_printf (key, lang_lo, lang_hi, 0x04, 0xb0);
192 LOGDEBUG (g_message ("%s: asking for [%s]", __func__, lang_key_utf8));
194 lang_key = g_utf8_to_utf16 (lang_key_utf8, -1, NULL, NULL, NULL);
196 if (VerQueryValue (data, lang_key, (gpointer *)&buffer, &chars) && chars > 0) {
197 LOGDEBUG (g_message ("%s: found %d chars of [%s]", __func__, chars, g_utf16_to_utf8 (buffer, chars, NULL, NULL, NULL)));
198 /* chars includes trailing null */
199 process_set_field_string (filever, fieldname, buffer, chars - 1);
201 process_set_field_string (filever, fieldname, EMPTY_STRING, 0);
205 g_free (lang_key_utf8);
208 static void process_module_stringtable (MonoObject *filever, gpointer data,
209 guchar lang_hi, guchar lang_lo)
211 process_module_string_read (filever, data, "comments", lang_hi, lang_lo,
213 process_module_string_read (filever, data, "companyname", lang_hi,
214 lang_lo, SFI_COMPANYNAME);
215 process_module_string_read (filever, data, "filedescription", lang_hi,
216 lang_lo, SFI_FILEDESCRIPTION);
217 process_module_string_read (filever, data, "fileversion", lang_hi,
218 lang_lo, SFI_FILEVERSION);
219 process_module_string_read (filever, data, "internalname", lang_hi,
220 lang_lo, SFI_INTERNALNAME);
221 process_module_string_read (filever, data, "legalcopyright", lang_hi,
222 lang_lo, SFI_LEGALCOPYRIGHT);
223 process_module_string_read (filever, data, "legaltrademarks", lang_hi,
224 lang_lo, SFI_LEGALTRADEMARKS);
225 process_module_string_read (filever, data, "originalfilename", lang_hi,
226 lang_lo, SFI_ORIGINALFILENAME);
227 process_module_string_read (filever, data, "privatebuild", lang_hi,
228 lang_lo, SFI_PRIVATEBUILD);
229 process_module_string_read (filever, data, "productname", lang_hi,
230 lang_lo, SFI_PRODUCTNAME);
231 process_module_string_read (filever, data, "productversion", lang_hi,
232 lang_lo, SFI_PRODUCTVERSION);
233 process_module_string_read (filever, data, "specialbuild", lang_hi,
234 lang_lo, SFI_SPECIALBUILD);
237 static void process_get_fileversion (MonoObject *filever, gunichar2 *filename)
240 VS_FIXEDFILEINFO *ffi;
245 UINT ffi_size, trans_size;
247 gunichar2 lang_buf[128];
248 guint32 lang, lang_count;
250 datalen = GetFileVersionInfoSize (filename, &verinfohandle);
252 data = g_malloc0 (datalen);
253 ok = GetFileVersionInfo (filename, verinfohandle, datalen,
256 query = g_utf8_to_utf16 ("\\", -1, NULL, NULL, NULL);
262 if (VerQueryValue (data, query, (gpointer *)&ffi,
264 LOGDEBUG (g_message ("%s: recording assembly: FileName [%s] FileVersionInfo [%d.%d.%d.%d]", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), HIWORD (ffi->dwFileVersionMS), LOWORD (ffi->dwFileVersionMS), HIWORD (ffi->dwFileVersionLS), LOWORD (ffi->dwFileVersionLS)));
266 process_set_field_int (filever, "filemajorpart", HIWORD (ffi->dwFileVersionMS));
267 process_set_field_int (filever, "fileminorpart", LOWORD (ffi->dwFileVersionMS));
268 process_set_field_int (filever, "filebuildpart", HIWORD (ffi->dwFileVersionLS));
269 process_set_field_int (filever, "fileprivatepart", LOWORD (ffi->dwFileVersionLS));
271 process_set_field_int (filever, "productmajorpart", HIWORD (ffi->dwProductVersionMS));
272 process_set_field_int (filever, "productminorpart", LOWORD (ffi->dwProductVersionMS));
273 process_set_field_int (filever, "productbuildpart", HIWORD (ffi->dwProductVersionLS));
274 process_set_field_int (filever, "productprivatepart", LOWORD (ffi->dwProductVersionLS));
276 process_set_field_bool (filever, "isdebug", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_DEBUG) != 0);
277 process_set_field_bool (filever, "isprerelease", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0);
278 process_set_field_bool (filever, "ispatched", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PATCHED) != 0);
279 process_set_field_bool (filever, "isprivatebuild", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PRIVATEBUILD) != 0);
280 process_set_field_bool (filever, "isspecialbuild", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_SPECIALBUILD) != 0);
284 query = g_utf8_to_utf16 ("\\VarFileInfo\\Translation", -1, NULL, NULL, NULL);
290 if (VerQueryValue (data, query,
291 (gpointer *)&trans_data,
293 /* use the first language ID we see
295 if (trans_size >= 4) {
296 LOGDEBUG (g_message("%s: %s has 0x%0x 0x%0x 0x%0x 0x%0x", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), trans_data[0], trans_data[1], trans_data[2], trans_data[3]));
297 lang = (trans_data[0]) |
298 (trans_data[1] << 8) |
299 (trans_data[2] << 16) |
300 (trans_data[3] << 24);
301 /* Only give the lower 16 bits
302 * to VerLanguageName, as
303 * Windows gets confused
306 lang_count = VerLanguageName (lang & 0xFFFF, lang_buf, 128);
308 process_set_field_string (filever, "language", lang_buf, lang_count);
310 process_module_stringtable (filever, data, trans_data[0], trans_data[1]);
313 /* No strings, so set every field to
316 process_set_field_string (filever,
319 process_set_field_string (filever,
322 process_set_field_string (filever,
325 process_set_field_string (filever,
328 process_set_field_string (filever,
331 process_set_field_string (filever,
334 process_set_field_string (filever,
337 process_set_field_string (filever,
340 process_set_field_string (filever,
343 process_set_field_string (filever,
346 process_set_field_string (filever,
349 process_set_field_string (filever,
353 /* And language seems to be set to
354 * en_US according to bug 374600
356 lang_count = VerLanguageName (0x0409, lang_buf, 128);
358 process_set_field_string (filever, "language", lang_buf, lang_count);
368 static void process_get_assembly_fileversion (MonoObject *filever, MonoAssembly *assembly)
370 process_set_field_int (filever, "filemajorpart", assembly->aname.major);
371 process_set_field_int (filever, "fileminorpart", assembly->aname.minor);
372 process_set_field_int (filever, "filebuildpart", assembly->aname.build);
375 static MonoObject* get_process_module (MonoAssembly *assembly, MonoClass *proc_class)
377 static MonoClass *filever_class = NULL;
378 MonoObject *item, *filever;
379 MonoDomain *domain = mono_domain_get ();
380 char filename [80] = "[In Memory] ";
381 const char *modulename = assembly->aname.name;
383 strncat (filename, modulename, 80);
385 /* Build a System.Diagnostics.ProcessModule with the data.
387 item = mono_object_new (domain, proc_class);
390 filever_class = mono_class_from_name (system_assembly,
391 "System.Diagnostics",
394 filever = mono_object_new (domain, filever_class);
396 process_get_assembly_fileversion (filever, assembly);
397 process_set_field_string_char (filever, "filename", filename);
398 process_set_field_object (item, "version_info", filever);
400 process_set_field_intptr (item, "baseaddr", assembly->image->raw_data);
401 process_set_field_int (item, "memory_size", assembly->image->raw_data_len);
402 process_set_field_string_char (item, "filename", filename);
403 process_set_field_string_char (item, "modulename", modulename);
408 static MonoObject* process_add_module (HANDLE process, HMODULE mod, gunichar2 *filename, gunichar2 *modulename, MonoClass *proc_class)
410 static MonoClass *filever_class = NULL;
411 MonoObject *item, *filever;
412 MonoDomain *domain=mono_domain_get ();
416 /* Build a System.Diagnostics.ProcessModule with the data.
418 item=mono_object_new (domain, proc_class);
421 filever_class=mono_class_from_name (system_assembly,
422 "System.Diagnostics",
425 filever=mono_object_new (domain, filever_class);
427 process_get_fileversion (filever, filename);
429 process_set_field_string (filever, "filename", filename,
430 unicode_chars (filename));
432 ok = GetModuleInformation (process, mod, &modinfo, sizeof(MODULEINFO));
434 process_set_field_intptr (item, "baseaddr",
435 modinfo.lpBaseOfDll);
436 process_set_field_intptr (item, "entryaddr",
438 process_set_field_int (item, "memory_size",
439 modinfo.SizeOfImage);
441 process_set_field_string (item, "filename", filename,
442 unicode_chars (filename));
443 process_set_field_string (item, "modulename", modulename,
444 unicode_chars (modulename));
445 process_set_field_object (item, "version_info", filever);
450 static GPtrArray* get_domain_assemblies (MonoDomain *domain)
453 GPtrArray *assemblies;
456 * Make a copy of the list of assemblies because we can't hold the assemblies
457 * lock while creating objects etc.
459 assemblies = g_ptr_array_new ();
460 mono_domain_assemblies_lock (domain);
461 for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
462 MonoAssembly *ass = tmp->data;
463 if (ass->image->fileio_used)
465 g_ptr_array_add (assemblies, ass);
467 mono_domain_assemblies_unlock (domain);
472 /* Returns an array of System.Diagnostics.ProcessModule */
473 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this, HANDLE process)
475 MonoArray *temp_arr = NULL;
478 gunichar2 filename[MAX_PATH];
479 gunichar2 modname[MAX_PATH];
481 guint32 count = 0, module_count = 0, assembly_count = 0;
482 guint32 i, num_added = 0;
483 static MonoClass *proc_class = NULL;
484 GPtrArray *assemblies = NULL;
485 static HANDLE current_process = 0;
487 if (current_process == 0) {
488 int pid = mono_process_current_pid ();
489 current_process = ves_icall_System_Diagnostics_Process_GetProcess_internal (pid);
492 STASH_SYS_ASS (this);
494 if (process == current_process) {
495 assemblies = get_domain_assemblies (mono_domain_get ());
496 assembly_count = assemblies->len;
499 if (EnumProcessModules (process, mods, sizeof(mods), &needed)) {
500 module_count += needed / sizeof(HMODULE);
503 count = module_count + assembly_count;
505 proc_class = mono_class_from_name (system_assembly, "System.Diagnostics", "ProcessModule");
507 temp_arr = mono_array_new (mono_domain_get (), proc_class, count);
509 for (i = 0; i < module_count; i++) {
510 if (GetModuleBaseName (process, mods[i], modname, MAX_PATH) &&
511 GetModuleFileNameEx (process, mods[i], filename, MAX_PATH)) {
512 MonoObject *module = process_add_module (process, mods[i],
513 filename, modname, proc_class);
514 mono_array_setref (temp_arr, num_added++, module);
519 for (i = 0; i < assembly_count; i++) {
520 MonoAssembly *ass = g_ptr_array_index (assemblies, i);
521 MonoObject *module = get_process_module (ass, proc_class);
522 mono_array_setref (temp_arr, num_added++, module);
524 g_ptr_array_free (assemblies, TRUE);
527 if (count == num_added) {
530 /* shorter version of the array */
531 arr = mono_array_new (mono_domain_get (), proc_class, num_added);
533 for (i = 0; i < num_added; i++)
534 mono_array_setref (arr, i, mono_array_get (temp_arr, MonoObject*, i));
537 if (count == num_added) {
540 /* shorter version of the array */
541 arr = mono_array_new (mono_domain_get (), proc_class, num_added);
543 for (i = 0; i < num_added; i++)
544 mono_array_setref (arr, i, mono_array_get (temp_arr, MonoObject*, i));
550 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
552 STASH_SYS_ASS (this);
554 process_get_fileversion (this, mono_string_chars (filename));
555 process_set_field_string (this, "filename",
556 mono_string_chars (filename),
557 mono_string_length (filename));
560 /* Only used when UseShellExecute is false */
562 quote_path (const gchar *path)
564 gchar *res = g_shell_quote (path);
578 /* Only used when UseShellExecute is false */
580 complete_path (const gunichar2 *appname, gchar **completed)
582 gchar *utf8app, *utf8appmemory;
585 utf8appmemory = utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
586 #ifdef TARGET_WIN32 // Should this happen on all platforms?
588 // remove the quotes around utf8app.
590 len = strlen (utf8app);
592 if (utf8app[len-1] == '\"')
593 utf8app[len-1] = '\0';
594 if (utf8app[0] == '\"')
600 if (g_path_is_absolute (utf8app)) {
601 *completed = quote_path (utf8app);
602 g_free (utf8appmemory);
606 if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) {
607 *completed = quote_path (utf8app);
608 g_free (utf8appmemory);
612 found = g_find_program_in_path (utf8app);
615 g_free (utf8appmemory);
619 *completed = quote_path (found);
621 g_free (utf8appmemory);
625 MonoBoolean ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_info)
627 SHELLEXECUTEINFO shellex = {0};
630 shellex.cbSize = sizeof(SHELLEXECUTEINFO);
631 shellex.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE;
632 shellex.nShow = proc_start_info->window_style;
633 shellex.nShow = (shellex.nShow == 0) ? 1 : (shellex.nShow == 1 ? 0 : shellex.nShow);
636 if (proc_start_info->filename != NULL) {
637 shellex.lpFile = mono_string_chars (proc_start_info->filename);
640 if (proc_start_info->arguments != NULL) {
641 shellex.lpParameters = mono_string_chars (proc_start_info->arguments);
644 if (proc_start_info->verb != NULL &&
645 mono_string_length (proc_start_info->verb) != 0) {
646 shellex.lpVerb = mono_string_chars (proc_start_info->verb);
649 if (proc_start_info->working_directory != NULL &&
650 mono_string_length (proc_start_info->working_directory) != 0) {
651 shellex.lpDirectory = mono_string_chars (proc_start_info->working_directory);
654 if (proc_start_info->error_dialog) {
655 shellex.hwnd = proc_start_info->error_dialog_parent_handle;
657 shellex.fMask |= SEE_MASK_FLAG_NO_UI;
660 ret = ShellExecuteEx (&shellex);
662 process_info->pid = -GetLastError ();
664 process_info->process_handle = shellex.hProcess;
665 process_info->thread_handle = NULL;
666 /* It appears that there's no way to get the pid from a
667 * process handle before windows xp. Really.
669 #if defined(HAVE_GETPROCESSID) && !defined(MONO_CROSS_COMPILE)
670 process_info->pid = GetProcessId (shellex.hProcess);
672 process_info->pid = 0;
674 process_info->tid = 0;
680 MonoBoolean ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoProcessStartInfo *proc_start_info, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info)
684 STARTUPINFO startinfo={0};
685 PROCESS_INFORMATION procinfo;
686 gunichar2 *shell_path = NULL;
687 gchar *env_vars = NULL;
688 gboolean free_shell_path = TRUE;
690 MonoString *cmd = proc_start_info->arguments;
691 guint32 creation_flags, logon_flags;
693 startinfo.cb=sizeof(STARTUPINFO);
694 startinfo.dwFlags=STARTF_USESTDHANDLES;
695 startinfo.hStdInput=stdin_handle;
696 startinfo.hStdOutput=stdout_handle;
697 startinfo.hStdError=stderr_handle;
699 creation_flags = CREATE_UNICODE_ENVIRONMENT;
700 if (proc_start_info->create_no_window)
701 creation_flags |= CREATE_NO_WINDOW;
703 shell_path = mono_string_chars (proc_start_info->filename);
704 complete_path (shell_path, &spath);
706 process_info->pid = -ERROR_FILE_NOT_FOUND;
710 /* Seems like our CreateProcess does not work as the windows one.
711 * This hack is needed to deal with paths containing spaces */
713 free_shell_path = FALSE;
716 tmp = mono_string_to_utf8 (cmd);
717 newcmd = g_strdup_printf ("%s %s", spath, tmp);
718 cmd = mono_string_new_wrapper (newcmd);
723 cmd = mono_string_new_wrapper (spath);
726 shell_path = g_utf8_to_utf16 (spath, -1, NULL, NULL, NULL);
730 if (process_info->env_keys != NULL) {
733 MonoString *key, *value;
734 gunichar2 *str, *ptr;
737 for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
738 ms = mono_array_get (process_info->env_values, MonoString *, i);
742 len += mono_string_length (ms) * sizeof (gunichar2);
743 ms = mono_array_get (process_info->env_keys, MonoString *, i);
744 len += mono_string_length (ms) * sizeof (gunichar2);
745 len += 2 * sizeof (gunichar2);
748 equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
749 ptr = str = g_new0 (gunichar2, len + 1);
750 for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
751 value = mono_array_get (process_info->env_values, MonoString *, i);
755 key = mono_array_get (process_info->env_keys, MonoString *, i);
756 memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
757 ptr += mono_string_length (key);
759 memcpy (ptr, equals16, sizeof (gunichar2));
762 memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
763 ptr += mono_string_length (value);
768 env_vars = (gchar *) str;
771 /* The default dir name is "". Turn that into NULL to mean
772 * "current directory"
774 if(proc_start_info->working_directory == NULL || mono_string_length (proc_start_info->working_directory)==0) {
777 dir=mono_string_chars (proc_start_info->working_directory);
780 if (process_info->username) {
781 logon_flags = process_info->load_user_profile ? LOGON_WITH_PROFILE : 0;
782 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);
784 ret=CreateProcess (shell_path, cmd? mono_string_chars (cmd): NULL, NULL, NULL, TRUE, creation_flags, env_vars, dir, &startinfo, &procinfo);
792 process_info->process_handle=procinfo.hProcess;
793 /*process_info->thread_handle=procinfo.hThread;*/
794 process_info->thread_handle=NULL;
795 if (procinfo.hThread != NULL && procinfo.hThread != INVALID_HANDLE_VALUE)
796 CloseHandle(procinfo.hThread);
797 process_info->pid=procinfo.dwProcessId;
798 process_info->tid=procinfo.dwThreadId;
800 process_info->pid = -GetLastError ();
806 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
810 MONO_PREPARE_BLOCKING
813 ret=WaitForSingleObjectEx (process, INFINITE, TRUE);
815 ret=WaitForSingleObjectEx (process, ms, TRUE);
819 if(ret==WAIT_OBJECT_0) {
826 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForInputIdle_internal (MonoObject *this, HANDLE process, gint32 ms)
832 ret=WaitForInputIdle (process, INFINITE);
834 ret=WaitForInputIdle (process, ms);
837 return (ret) ? FALSE : TRUE;
841 file_time_to_guint64 (FILETIME *time)
843 return ((guint64)time->dwHighDateTime << 32) | ((guint64)time->dwLowDateTime);
846 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
849 FILETIME create_time, exit_time, kernel_time, user_time;
851 ret = GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
854 return file_time_to_guint64 (&exit_time);
859 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
862 FILETIME create_time, exit_time, kernel_time, user_time;
864 ret = GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
867 return file_time_to_guint64 (&create_time);
872 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
876 GetExitCodeProcess (process, &code);
878 LOGDEBUG (g_message ("%s: process exit code is %d", __func__, code));
883 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
888 gunichar2 name[MAX_PATH];
892 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
897 len=GetModuleBaseName (process, mod, name, MAX_PATH);
902 LOGDEBUG (g_message ("%s: process name is [%s]", __func__, g_utf16_to_utf8 (name, -1, NULL, NULL, NULL)));
904 string=mono_string_new_utf16 (mono_domain_get (), name, len);
909 /* Returns an array of pids */
911 ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
913 #if !defined(HOST_WIN32)
918 pidarray = mono_process_list (&count);
920 mono_set_pending_exception (mono_get_exception_not_supported ("This system does not support EnumProcesses"));
923 procs = mono_array_new (mono_domain_get (), mono_get_int32_class (), count);
924 if (sizeof (guint32) == sizeof (gpointer)) {
925 memcpy (mono_array_addr (procs, guint32, 0), pidarray, count * sizeof (gint32));
927 for (i = 0; i < count; ++i)
928 *(mono_array_addr (procs, guint32, i)) = GPOINTER_TO_UINT (pidarray [i]);
942 pids = g_new0 (guint32, count);
943 ret = EnumProcesses (pids, count * sizeof (guint32), &needed);
949 exc = mono_get_exception_not_supported ("This system does not support EnumProcesses");
950 mono_set_pending_exception (exc);
953 if (needed < (count * sizeof (guint32)))
957 count = (count * 3) / 2;
960 count = needed / sizeof (guint32);
961 procs = mono_array_new (mono_domain_get (), mono_get_int32_class (), count);
962 memcpy (mono_array_addr (procs, guint32, 0), pids, needed);
970 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
973 SIZE_T ws_min, ws_max;
975 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
976 *min=(guint32)ws_min;
977 *max=(guint32)ws_max;
982 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
988 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
999 ret=SetProcessWorkingSetSize (process, ws_min, ws_max);
1005 ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig)
1007 /* sig == 1 -> Kill, sig == 2 -> CloseMainWindow */
1009 return TerminateProcess (process, -sig);
1013 ves_icall_System_Diagnostics_Process_Times (HANDLE process, gint32 type)
1015 FILETIME create_time, exit_time, kernel_time, user_time;
1017 if (GetProcessTimes (process, &create_time, &exit_time, &kernel_time, &user_time)) {
1018 guint64 ktime = file_time_to_guint64 (&kernel_time);
1019 guint64 utime = file_time_to_guint64 (&user_time);
1026 return ktime + utime;
1032 ves_icall_System_Diagnostics_Process_GetPriorityClass (HANDLE process, gint32 *error)
1034 gint32 ret = GetPriorityClass (process);
1035 *error = ret == 0 ? GetLastError () : 0;
1040 ves_icall_System_Diagnostics_Process_SetPriorityClass (HANDLE process, gint32 priority_class, gint32 *error)
1042 gboolean ret = SetPriorityClass (process, priority_class);
1043 *error = ret == 0 ? GetLastError () : 0;
1048 ves_icall_System_Diagnostics_Process_ProcessHandle_duplicate (HANDLE process)
1052 LOGDEBUG (g_message ("%s: Duplicating process handle %p", __func__, process));
1054 DuplicateHandle (GetCurrentProcess (), process, GetCurrentProcess (),
1055 &ret, THREAD_ALL_ACCESS, TRUE, 0);
1061 ves_icall_System_Diagnostics_Process_ProcessHandle_close (HANDLE process)
1063 LOGDEBUG (g_message ("%s: Closing process handle %p", __func__, process));
1065 CloseHandle (process);
1069 ves_icall_System_Diagnostics_Process_GetProcessData (int pid, gint32 data_type, gint32 *error)
1071 MonoProcessError perror;
1074 res = mono_process_get_data_with_error (GINT_TO_POINTER (pid), data_type, &perror);
1081 ves_icall_System_Diagnostics_Process_ProcessAsyncReader_RemoveFromIOThreadPool (HANDLE handle)
1083 mono_threadpool_ms_io_remove_socket (GPOINTER_TO_INT (handle));