2 * process.c: System.Diagnostics.Process support
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright (c) 2002-2006 Novell, Inc.
16 #include <mono/metadata/object.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/utils/strenc.h>
24 #include <mono/io-layer/io-layer.h>
25 /* FIXME: fix this code to not depend so much on the inetrnals */
26 #include <mono/metadata/class-internals.h>
30 HANDLE ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid)
36 /* GetCurrentProcess returns a pseudo-handle, so use
39 handle=OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid);
42 /* FIXME: Throw an exception */
49 guint32 ves_icall_System_Diagnostics_Process_GetPid_internal (void)
53 return(GetCurrentProcessId ());
56 void ves_icall_System_Diagnostics_Process_Process_free_internal (MonoObject *this,
62 g_message (G_GNUC_PRETTY_FUNCTION ": Closing process %p, handle %p",
66 CloseHandle (process);
69 #define STASH_SYS_ASS(this) \
70 if(system_assembly == NULL) { \
71 system_assembly=this->vtable->klass->image; \
74 static MonoImage *system_assembly=NULL;
76 static guint32 unicode_chars (const gunichar2 *str)
88 static guint32 unicode_bytes (const gunichar2 *str)
94 /* Include the terminators */
102 * compare a null-terminated utf16 string and a normal string.
103 * Can be used only for ascii or latin1 chars.
106 unicode_string_equals (const gunichar2 *str1, const gchar *str2)
108 while (*str1 && *str2) {
114 return *str1 == *str2;
117 static void process_set_field_object (MonoObject *obj, const gchar *fieldname,
120 MonoClassField *field;
123 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to object at %p",
127 field=mono_class_get_field_from_name (mono_object_class (obj),
129 *(MonoObject **)(((char *)obj) + field->offset)=data;
132 static void process_set_field_string (MonoObject *obj, const gchar *fieldname,
133 const gunichar2 *val, guint32 len)
135 MonoClassField *field;
139 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to [%s]",
140 fieldname, g_utf16_to_utf8 (val, len, NULL, NULL, NULL));
143 string=mono_string_new_utf16 (mono_object_domain (obj), val, len);
145 field=mono_class_get_field_from_name (mono_object_class (obj),
147 *(MonoString **)(((char *)obj) + field->offset)=string;
150 static void process_set_field_string_utf8 (MonoObject *obj,
151 const gchar *fieldname,
154 MonoClassField *field;
158 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to [%s]",
162 string=mono_string_new (mono_object_domain (obj), val);
164 field=mono_class_get_field_from_name (mono_object_class (obj),
166 *(MonoString **)(((char *)obj) + field->offset)=string;
169 static void process_set_field_int (MonoObject *obj, const gchar *fieldname,
172 MonoClassField *field;
175 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to %d",
179 field=mono_class_get_field_from_name (mono_object_class (obj),
181 *(guint32 *)(((char *)obj) + field->offset)=val;
184 static void process_set_field_bool (MonoObject *obj, const gchar *fieldname,
187 MonoClassField *field;
190 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to %s",
191 fieldname, val?"TRUE":"FALSE");
194 field=mono_class_get_field_from_name (mono_object_class (obj),
196 *(guint8 *)(((char *)obj) + field->offset)=val;
206 /* Returns a pointer to the value data, because theres no way to know
207 * how big that data is (value_len is set to zero for most blocks :-()
209 static gpointer process_get_versioninfo_block (gpointer data,
212 block->data_len=*((guint16 *)data);
213 data = (char *)data + sizeof(guint16);
214 block->value_len=*((guint16 *)data);
215 data = (char *)data + sizeof(guint16);
217 /* No idea what the type is supposed to indicate */
218 block->type=*((guint16 *)data);
219 data = (char *)data + sizeof(guint16);
220 block->key=((gunichar2 *)data);
222 /* skip over the key (including the terminator) */
223 data=((gunichar2 *)data)+(unicode_chars (block->key)+1);
225 /* align on a 32-bit boundary */
226 data=(gpointer)((char *)data + 3);
227 data=(gpointer)((char *)data - (GPOINTER_TO_INT(data) & 3));
232 /* Returns a pointer to the byte following the Var block */
233 static gpointer process_read_var_block (MonoObject *filever, gpointer data_ptr,
236 /* Not currently interested in the VarFileInfo block. This
237 * might change if language support is needed for file version
238 * strings (VarFileInfo contains lists of supported
243 /* data_ptr is pointing at a Var block of length data_len */
244 data_ptr=process_get_versioninfo_block (data_ptr, &block);
245 data_ptr=((guchar *)data_ptr)+block.value_len;
250 /* Returns a pointer to the byte following the String block, or NULL
251 * if the data read hits padding. We can't recover from this because
252 * the data length does not include padding bytes, so it's not
253 * possible to just return the start position + length.
255 static gpointer process_read_string_block (MonoObject *filever,
261 guint16 string_len=28; /* Length of the StringTable block */
263 /* data_ptr is pointing at an array of one or more String
264 * blocks with total length (not including alignment padding)
267 while(string_len<data_len) {
270 /* align on a 32-bit boundary */
271 data_ptr=(gpointer)((char *)data_ptr + 3);
272 data_ptr=(gpointer)((char *)data_ptr -
273 (GPOINTER_TO_INT(data_ptr) & 3));
275 data_ptr=process_get_versioninfo_block (data_ptr, &block);
276 if(block.data_len==0) {
277 /* We must have hit padding, so give up
281 g_message (G_GNUC_PRETTY_FUNCTION
282 ": Hit 0-length block, giving up");
287 string_len=string_len+block.data_len;
288 value=(gunichar2 *)data_ptr;
289 /* Skip over the value */
290 data_ptr=((gunichar2 *)data_ptr)+block.value_len;
293 if (unicode_string_equals (block.key, "Comments")) {
294 process_set_field_string (filever, "comments", value, unicode_chars (value));
295 } else if (unicode_string_equals (block.key, "CompanyName")) {
296 process_set_field_string (filever, "companyname", value, unicode_chars (value));
297 } else if (unicode_string_equals (block.key, "FileDescription")) {
298 process_set_field_string (filever, "filedescription", value, unicode_chars (value));
299 } else if (unicode_string_equals (block.key, "FileVersion")) {
300 process_set_field_string (filever, "fileversion", value, unicode_chars (value));
301 } else if (unicode_string_equals (block.key, "InternalName")) {
302 process_set_field_string (filever, "internalname", value, unicode_chars (value));
303 } else if (unicode_string_equals (block.key, "LegalCopyright")) {
304 process_set_field_string (filever, "legalcopyright", value, unicode_chars (value));
305 } else if (unicode_string_equals (block.key, "LegalTrademarks")) {
306 process_set_field_string (filever, "legaltrademarks", value, unicode_chars (value));
307 } else if (unicode_string_equals (block.key, "OriginalFilename")) {
308 process_set_field_string (filever, "originalfilename", value, unicode_chars (value));
309 } else if (unicode_string_equals (block.key, "PrivateBuild")) {
310 process_set_field_string (filever, "privatebuild", value, unicode_chars (value));
311 } else if (unicode_string_equals (block.key, "ProductName")) {
312 process_set_field_string (filever, "productname", value, unicode_chars (value));
313 } else if (unicode_string_equals (block.key, "ProductVersion")) {
314 process_set_field_string (filever, "productversion", value, unicode_chars (value));
315 } else if (unicode_string_equals (block.key, "SpecialBuild")) {
316 process_set_field_string (filever, "specialbuild", value, unicode_chars (value));
318 /* Not an error, just not interesting
328 /* returns a pointer to the byte following the Stringtable block, or
329 * NULL if the data read hits padding. We can't recover from this
330 * because the data length does not include padding bytes, so it's not
331 * possible to just return the start position + length
333 static gpointer process_read_stringtable_block (MonoObject *filever,
339 guint16 string_len=36; /* length of the StringFileInfo block */
341 /* data_ptr is pointing at an array of StringTable blocks,
342 * with total length (not including alignment padding) of
346 while(string_len<data_len) {
347 /* align on a 32-bit boundary */
348 data_ptr=(gpointer)((char *)data_ptr + 3);
349 data_ptr=(gpointer)((char *)data_ptr -
350 (GPOINTER_TO_INT(data_ptr) & 3));
352 data_ptr=process_get_versioninfo_block (data_ptr, &block);
353 if(block.data_len==0) {
354 /* We must have hit padding, so give up
358 g_message (G_GNUC_PRETTY_FUNCTION
359 ": Hit 0-length block, giving up");
363 string_len=string_len+block.data_len;
365 language = g_utf16_to_utf8 (block.key, unicode_bytes (block.key), NULL, NULL, NULL);
366 g_strdown (language);
368 /* Kludge: treat en_US as neutral too */
369 if (!strcmp (language, "007f04b0") ||
370 !strcmp (language, "000004b0") ||
371 !strcmp (language, "040904b0")) {
372 /* Got the one we're interested in */
373 process_set_field_string_utf8 (filever, "language",
376 data_ptr=process_read_string_block (filever, data_ptr,
380 /* Some other language. We might want to do
381 * something with this in the future.
383 data_ptr=process_read_string_block (filever, data_ptr,
390 /* Child block hit padding */
392 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
401 static void process_read_fixedfileinfo_block (MonoObject *filever,
402 VS_FIXEDFILEINFO *ffi)
405 g_message (G_GNUC_PRETTY_FUNCTION ": ffi: sig 0x%x, strucver 0x%x, fileverm 0x%x, fileverl 0x%x, prodverm 0x%x, prodverl 0x%x, ffmask 0x%x, ff 0x%x, os 0x%x, type 0x%x, subtype 0x%x, datem 0x%x, datel 0x%x", ffi->dwSignature, ffi->dwStrucVersion, ffi->dwFileVersionMS, ffi->dwFileVersionLS, ffi->dwProductVersionMS, ffi->dwProductVersionLS, ffi->dwFileFlagsMask, ffi->dwFileFlags, ffi->dwFileOS, ffi->dwFileType, ffi->dwFileSubtype, ffi->dwFileDateMS, ffi->dwFileDateLS);
408 process_set_field_int (filever, "filemajorpart",
409 HIWORD (ffi->dwFileVersionMS));
410 process_set_field_int (filever, "fileminorpart",
411 LOWORD (ffi->dwFileVersionMS));
412 process_set_field_int (filever, "filebuildpart",
413 HIWORD (ffi->dwFileVersionLS));
414 process_set_field_int (filever, "fileprivatepart",
415 LOWORD (ffi->dwFileVersionLS));
417 process_set_field_int (filever, "productmajorpart",
418 HIWORD (ffi->dwProductVersionMS));
419 process_set_field_int (filever, "productminorpart",
420 LOWORD (ffi->dwProductVersionMS));
421 process_set_field_int (filever, "productbuildpart",
422 HIWORD (ffi->dwProductVersionLS));
423 process_set_field_int (filever, "productprivatepart",
424 LOWORD (ffi->dwProductVersionLS));
426 process_set_field_bool (filever, "isdebug",
427 ffi->dwFileFlags&VS_FF_DEBUG);
428 process_set_field_bool (filever, "isprerelease",
429 ffi->dwFileFlags&VS_FF_PRERELEASE);
430 process_set_field_bool (filever, "ispatched",
431 ffi->dwFileFlags&VS_FF_PATCHED);
432 process_set_field_bool (filever, "isprivatebuild",
433 ffi->dwFileFlags&VS_FF_PRIVATEBUILD);
434 process_set_field_bool (filever, "isspecialbuild",
435 ffi->dwFileFlags&VS_FF_SPECIALBUILD);
438 static void process_get_fileversion (MonoObject *filever, MonoImage *image)
440 MonoPEResourceDataEntry *version_info;
442 VS_FIXEDFILEINFO *ffi;
445 gint32 data_len; /* signed to guard against underflow */
447 version_info=mono_image_lookup_resource (image,
448 MONO_PE_RESOURCE_ID_VERSION,
451 g_message (G_GNUC_PRETTY_FUNCTION ": image_lookup returned %p",
455 if(version_info==NULL) {
459 data=mono_image_rva_map (image,
460 version_info->rde_data_offset);
465 /* See io-layer/versioninfo.h for the gory details on how this
466 * data is laid out. (data should be pointing to
467 * VS_VERSIONINFO data).
470 data_ptr=process_get_versioninfo_block (data, &block);
472 data_len=block.data_len;
474 if(block.value_len!=sizeof(VS_FIXEDFILEINFO)) {
476 g_message (G_GNUC_PRETTY_FUNCTION
477 ": FIXEDFILEINFO size mismatch");
482 if (!unicode_string_equals (block.key, "VS_VERSION_INFO")) {
484 g_message (G_GNUC_PRETTY_FUNCTION
485 ": VS_VERSION_INFO mismatch");
490 ffi=((VS_FIXEDFILEINFO *)data_ptr);
491 data_ptr = (char *)data_ptr + sizeof(VS_FIXEDFILEINFO);
492 if((ffi->dwSignature!=VS_FFI_SIGNATURE) ||
493 (ffi->dwStrucVersion!=VS_FFI_STRUCVERSION)) {
495 g_message (G_GNUC_PRETTY_FUNCTION
496 ": FIXEDFILEINFO bad signature");
500 process_read_fixedfileinfo_block (filever, ffi);
502 /* Subtract the 92 bytes we've already seen */
505 /* There now follow zero or one StringFileInfo blocks and zero
506 * or one VarFileInfo blocks
508 while(data_len > 0) {
509 /* align on a 32-bit boundary */
510 data_ptr=(gpointer)((char *)data_ptr + 3);
511 data_ptr=(gpointer)((char *)data_ptr -
512 (GPOINTER_TO_INT(data_ptr) & 3));
514 data_ptr=process_get_versioninfo_block (data_ptr, &block);
515 if(block.data_len==0) {
516 /* We must have hit padding, so give up
520 g_message (G_GNUC_PRETTY_FUNCTION
521 ": Hit 0-length block, giving up");
526 data_len=data_len-block.data_len;
528 if (unicode_string_equals (block.key, "VarFileInfo")) {
529 data_ptr=process_read_var_block (filever, data_ptr,
531 } else if (unicode_string_equals (block.key, "StringFileInfo")) {
532 data_ptr=process_read_stringtable_block (filever, data_ptr, block.data_len);
536 g_message (G_GNUC_PRETTY_FUNCTION
537 ": Not a valid VERSIONINFO child block");
543 /* Child block hit padding */
545 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
552 static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
554 MonoClass *proc_class, *filever_class;
555 MonoObject *item, *filever;
556 MonoDomain *domain=mono_domain_get ();
558 const char* filename;
560 /* Build a System.Diagnostics.ProcessModule with the data.
561 * Leave BaseAddress and EntryPointAddress set to NULL,
562 * FileName is ass->image->name, FileVersionInfo is an object
563 * constructed from the PE image data referenced by
564 * ass->image, ModuleMemorySize set to 0, ModuleName the last
565 * component of FileName.
567 proc_class=mono_class_from_name (system_assembly, "System.Diagnostics",
569 item=mono_object_new (domain, proc_class);
571 filever_class=mono_class_from_name (system_assembly,
572 "System.Diagnostics",
574 filever=mono_object_new (domain, filever_class);
577 g_message (G_GNUC_PRETTY_FUNCTION ": recording assembly: FileName [%s] FileVersionInfo [%d.%d.%d.%d], ModuleName [%s]", ass->image->name, ass->aname.major, ass->aname.minor, ass->aname.build, ass->aname.revision, ass->image->name);
580 process_get_fileversion (filever, mono_assembly_get_image (ass));
582 filename = mono_image_get_filename (mono_assembly_get_image (ass));
583 process_set_field_string_utf8 (filever, "filename", filename);
584 process_set_field_string_utf8 (item, "filename", filename);
585 process_set_field_object (item, "version_info", filever);
587 modulename=g_path_get_basename (filename);
588 process_set_field_string_utf8 (item, "modulename", modulename);
591 g_ptr_array_add (modules, item);
594 static void process_scan_modules (gpointer data, gpointer user_data)
596 MonoAssembly *ass=data;
597 GPtrArray *modules=user_data;
599 /* The main assembly is already in the list */
600 if(mono_assembly_get_main () != ass) {
601 process_add_module (modules, ass);
606 /* Returns an array of System.Diagnostics.ProcessModule */
607 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this)
609 /* I was going to use toolhelp for this, but then realised I
610 * was being an idiot :)
612 * (Toolhelp would give shared libraries open by the runtime,
613 * as well as open assemblies. On windows my tests didnt find
614 * the assemblies loaded by mono either.)
616 GPtrArray *modules_list=g_ptr_array_new ();
622 STASH_SYS_ASS (this);
624 /* Make sure the first entry is the main module */
625 process_add_module (modules_list, mono_assembly_get_main ());
627 mono_assembly_foreach (process_scan_modules, modules_list);
629 /* Build a MonoArray out of modules_list */
630 arr=mono_array_new (mono_domain_get (), mono_get_object_class (),
633 for(i=0; i<modules_list->len; i++) {
634 mono_array_setref (arr, i, g_ptr_array_index (modules_list, i));
637 g_ptr_array_free (modules_list, TRUE);
642 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
645 gchar *filename_utf8;
649 STASH_SYS_ASS (this);
651 filename_utf8 = mono_string_to_utf8 (filename);
652 image = mono_pe_file_open (filename_utf8, NULL);
653 g_free (filename_utf8);
656 /* FIXME: an exception might be appropriate here */
658 g_message (G_GNUC_PRETTY_FUNCTION ": Failed to load image");
664 process_get_fileversion (this, image);
665 process_set_field_string_utf8 (this, "filename", mono_image_get_filename (image));
667 mono_image_close (image);
670 /* Only used when UseShellExecute is false */
672 quote_path (const gchar *path)
674 gchar *res = g_shell_quote (path);
675 #ifdef PLATFORM_WIN32
688 /* Only used when UseShellExecute is false */
690 complete_path (const gunichar2 *appname, gchar **completed)
695 utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
696 if (g_path_is_absolute (utf8app)) {
697 *completed = quote_path (utf8app);
702 if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) {
703 *completed = quote_path (utf8app);
708 found = g_find_program_in_path (utf8app);
715 *completed = quote_path (found);
721 MonoBoolean ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoProcessStartInfo *proc_start_info, MonoProcInfo *process_info)
723 SHELLEXECUTEINFO shellex = {0};
726 shellex.cbSize = sizeof(SHELLEXECUTEINFO);
727 shellex.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE;
728 shellex.nShow = SW_SHOWNORMAL;
730 if (proc_start_info->filename != NULL) {
731 shellex.lpFile = mono_string_chars (proc_start_info->filename);
734 if (proc_start_info->arguments != NULL) {
735 shellex.lpParameters = mono_string_chars (proc_start_info->arguments);
738 if (proc_start_info->verb != NULL &&
739 mono_string_length (proc_start_info->verb) != 0) {
740 shellex.lpVerb = mono_string_chars (proc_start_info->verb);
743 if (proc_start_info->working_directory != NULL &&
744 mono_string_length (proc_start_info->working_directory) != 0) {
745 shellex.lpDirectory = mono_string_chars (proc_start_info->working_directory);
748 ret = ShellExecuteEx (&shellex);
750 process_info->pid = -GetLastError ();
752 process_info->process_handle = shellex.hProcess;
753 process_info->thread_handle = NULL;
754 /* It appears that there's no way to get the pid from a
755 * process handle before windows xp. Really.
757 #ifdef HAVE_GETPROCESSID
758 process_info->pid = GetProcessId (shellex.hProcess);
760 process_info->pid = 0;
762 process_info->tid = 0;
768 MonoBoolean ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoProcessStartInfo *proc_start_info, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info)
772 STARTUPINFO startinfo={0};
773 PROCESS_INFORMATION procinfo;
774 gunichar2 *shell_path = NULL;
775 gchar *env_vars = NULL;
776 gboolean free_shell_path = TRUE;
777 #ifdef PLATFORM_WIN32
781 MonoString *cmd = proc_start_info->arguments;
785 startinfo.cb=sizeof(STARTUPINFO);
786 startinfo.dwFlags=STARTF_USESTDHANDLES;
787 startinfo.hStdInput=stdin_handle;
788 startinfo.hStdOutput=stdout_handle;
789 startinfo.hStdError=stderr_handle;
791 shell_path = mono_string_chars (proc_start_info->filename);
792 complete_path (shell_path, &spath);
794 process_info->pid = -ERROR_FILE_NOT_FOUND;
797 #ifdef PLATFORM_WIN32
798 /* Seems like our CreateProcess does not work as the windows one.
799 * This hack is needed to deal with paths containing spaces */
801 free_shell_path = FALSE;
802 tmp = mono_string_to_utf8 (cmd);
803 newcmd = g_strdup_printf ("%s %s", spath, tmp);
804 cmd = mono_string_new_wrapper (newcmd);
808 shell_path = g_utf8_to_utf16 (spath, -1, NULL, NULL, NULL);
812 if (process_info->env_keys != NULL) {
815 MonoString *key, *value;
816 gunichar2 *str, *ptr;
819 for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
820 ms = mono_array_get (process_info->env_values, MonoString *, i);
824 len += mono_string_length (ms) * sizeof (gunichar2);
825 ms = mono_array_get (process_info->env_keys, MonoString *, i);
826 len += mono_string_length (ms) * sizeof (gunichar2);
827 len += 2 * sizeof (gunichar2);
830 equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
831 ptr = str = g_new0 (gunichar2, len + 1);
832 for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
833 value = mono_array_get (process_info->env_values, MonoString *, i);
837 key = mono_array_get (process_info->env_keys, MonoString *, i);
838 memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
839 ptr += mono_string_length (key);
841 memcpy (ptr, equals16, sizeof (gunichar2));
844 memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
845 ptr += mono_string_length (value);
850 env_vars = (gchar *) str;
853 /* The default dir name is "". Turn that into NULL to mean
854 * "current directory"
856 if(mono_string_length (proc_start_info->working_directory)==0) {
859 dir=mono_string_chars (proc_start_info->working_directory);
862 ret=CreateProcess (shell_path, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env_vars, dir, &startinfo, &procinfo);
869 process_info->process_handle=procinfo.hProcess;
870 /*process_info->thread_handle=procinfo.hThread;*/
871 process_info->thread_handle=NULL;
872 if (procinfo.hThread != NULL)
873 CloseHandle(procinfo.hThread);
874 process_info->pid=procinfo.dwProcessId;
875 process_info->tid=procinfo.dwThreadId;
877 process_info->pid = -GetLastError ();
883 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
891 ret=WaitForSingleObjectEx (process, INFINITE, TRUE);
893 ret=WaitForSingleObjectEx (process, ms, TRUE);
895 if(ret==WAIT_OBJECT_0) {
902 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
906 FILETIME create_time, exit_time, kernel_time, user_time;
910 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
913 ticks=((guint64)exit_time.dwHighDateTime << 32) +
914 exit_time.dwLowDateTime;
922 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
926 FILETIME create_time, exit_time, kernel_time, user_time;
930 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
933 ticks=((guint64)create_time.dwHighDateTime << 32) +
934 create_time.dwLowDateTime;
942 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
948 GetExitCodeProcess (process, &code);
951 g_message (G_GNUC_PRETTY_FUNCTION ": process exit code is %d", code);
957 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
962 gunichar2 name[MAX_PATH];
968 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
973 len=GetModuleBaseName (process, mod, name, MAX_PATH);
979 g_message (G_GNUC_PRETTY_FUNCTION ": process name is [%s]",
980 g_utf16_to_utf8 (name, -1, NULL, NULL, NULL));
983 string=mono_string_new_utf16 (mono_domain_get (), name, len);
988 /* Returns an array of pids */
989 MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
993 guint32 needed, count, i;
998 ret=EnumProcesses (pids, sizeof(pids), &needed);
1000 /* FIXME: throw an exception */
1004 count=needed/sizeof(guint32);
1005 procs=mono_array_new (mono_domain_get (), mono_get_int32_class (),
1007 for(i=0; i<count; i++) {
1008 mono_array_set (procs, guint32, i, pids[i]);
1014 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
1017 size_t ws_min, ws_max;
1019 MONO_ARCH_SAVE_REGS;
1021 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1022 *min=(guint32)ws_min;
1023 *max=(guint32)ws_max;
1028 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
1034 MONO_ARCH_SAVE_REGS;
1036 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1047 ret=SetProcessWorkingSetSize (process, ws_min, ws_max);
1053 ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig)
1055 MONO_ARCH_SAVE_REGS;
1057 /* sig == 1 -> Kill, sig == 2 -> CloseMainWindow */
1059 return TerminateProcess (process, -sig);