2 * process.c: System.Diagnostics.Process support
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
15 #include <mono/metadata/object.h>
16 #include <mono/metadata/process.h>
17 #include <mono/metadata/assembly.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/image.h>
20 #include <mono/metadata/cil-coff.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/utils/strenc.h>
23 #include <mono/io-layer/io-layer.h>
24 /* FIXME: fix this code to not depend so much on the inetrnals */
25 #include <mono/metadata/class-internals.h>
29 HANDLE ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid)
35 /* GetCurrentProcess returns a pseudo-handle, so use
38 handle=OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid);
41 /* FIXME: Throw an exception */
48 guint32 ves_icall_System_Diagnostics_Process_GetPid_internal (void)
52 return(GetCurrentProcessId ());
55 void ves_icall_System_Diagnostics_Process_Process_free_internal (MonoObject *this,
61 g_message (G_GNUC_PRETTY_FUNCTION ": Closing process %p, handle %p",
65 CloseHandle (process);
68 #define STASH_SYS_ASS(this) \
69 if(system_assembly == NULL) { \
70 system_assembly=this->vtable->klass->image; \
73 static MonoImage *system_assembly=NULL;
75 static guint32 unicode_chars (const gunichar2 *str)
87 static guint32 unicode_bytes (const gunichar2 *str)
93 /* Include the terminators */
100 static void process_set_field_object (MonoObject *obj, const guchar *fieldname,
103 MonoClassField *field;
106 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to object at %p",
110 field=mono_class_get_field_from_name (mono_object_class (obj),
112 *(MonoObject **)(((char *)obj) + field->offset)=data;
115 static void process_set_field_string (MonoObject *obj, const guchar *fieldname,
116 const gunichar2 *val, guint32 len)
118 MonoClassField *field;
122 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to [%s]",
123 fieldname, g_utf16_to_utf8 (val, len, NULL, NULL, NULL));
126 string=mono_string_new_utf16 (mono_object_domain (obj), val, len);
128 field=mono_class_get_field_from_name (mono_object_class (obj),
130 *(MonoString **)(((char *)obj) + field->offset)=string;
133 static void process_set_field_string_utf8 (MonoObject *obj,
134 const guchar *fieldname,
137 MonoClassField *field;
141 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to [%s]",
145 string=mono_string_new (mono_object_domain (obj), val);
147 field=mono_class_get_field_from_name (mono_object_class (obj),
149 *(MonoString **)(((char *)obj) + field->offset)=string;
152 static void process_set_field_int (MonoObject *obj, const guchar *fieldname,
155 MonoClassField *field;
158 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to %d",
162 field=mono_class_get_field_from_name (mono_object_class (obj),
164 *(guint32 *)(((char *)obj) + field->offset)=val;
167 static void process_set_field_bool (MonoObject *obj, const guchar *fieldname,
170 MonoClassField *field;
173 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to %s",
174 fieldname, val?"TRUE":"FALSE");
177 field=mono_class_get_field_from_name (mono_object_class (obj),
179 *(guint8 *)(((char *)obj) + field->offset)=val;
189 /* Returns a pointer to the value data, because theres no way to know
190 * how big that data is (value_len is set to zero for most blocks :-()
192 static gpointer process_get_versioninfo_block (gpointer data,
195 block->data_len=*((guint16 *)data);
196 data = (char *)data + sizeof(guint16);
197 block->value_len=*((guint16 *)data);
198 data = (char *)data + sizeof(guint16);
200 /* No idea what the type is supposed to indicate */
201 block->type=*((guint16 *)data);
202 data = (char *)data + sizeof(guint16);
203 block->key=((gunichar2 *)data);
205 /* skip over the key (including the terminator) */
206 data=((gunichar2 *)data)+(unicode_chars (block->key)+1);
208 /* align on a 32-bit boundary */
209 data=(gpointer)((char *)data + 3);
210 data=(gpointer)((char *)data - (GPOINTER_TO_INT(data) & 3));
215 /* Returns a pointer to the byte following the Var block */
216 static gpointer process_read_var_block (MonoObject *filever, gpointer data_ptr,
219 /* Not currently interested in the VarFileInfo block. This
220 * might change if language support is needed for file version
221 * strings (VarFileInfo contains lists of supported
226 /* data_ptr is pointing at a Var block of length data_len */
227 data_ptr=process_get_versioninfo_block (data_ptr, &block);
228 data_ptr=((guchar *)data_ptr)+block.value_len;
233 /* Returns a pointer to the byte following the String block, or NULL
234 * if the data read hits padding. We can't recover from this because
235 * the data length does not include padding bytes, so it's not
236 * possible to just return the start position + length.
238 static gpointer process_read_string_block (MonoObject *filever,
244 guint16 string_len=0;
245 guchar comments_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
246 'm', '\0', 'e', '\0', 'n', '\0',
247 't', '\0', 's', '\0', '\0', '\0'};
248 guchar compname_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
249 'p', '\0', 'a', '\0', 'n', '\0',
250 'y', '\0', 'N', '\0', 'a', '\0',
251 'm', '\0', 'e', '\0', '\0', '\0'};
252 guchar filedesc_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
253 'e', '\0', 'D', '\0', 'e', '\0',
254 's', '\0', 'c', '\0', 'r', '\0',
255 'i', '\0', 'p', '\0', 't', '\0',
256 'i', '\0', 'o', '\0', 'n', '\0',
258 guchar filever_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
259 'e', '\0', 'V', '\0', 'e', '\0',
260 'r', '\0', 's', '\0', 'i', '\0',
261 'o', '\0', 'n', '\0', '\0', '\0'};
262 guchar internal_key[]= {'I', '\0', 'n', '\0', 't', '\0',
263 'e', '\0', 'r', '\0', 'n', '\0',
264 'a', '\0', 'l', '\0', 'N', '\0',
265 'a', '\0', 'm', '\0', 'e', '\0',
267 guchar legalcpy_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
268 'a', '\0', 'l', '\0', 'C', '\0',
269 'o', '\0', 'p', '\0', 'y', '\0',
270 'r', '\0', 'i', '\0', 'g', '\0',
271 'h', '\0', 't', '\0', '\0', '\0'};
272 guchar legaltrade_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
273 'a', '\0', 'l', '\0', 'T', '\0',
274 'r', '\0', 'a', '\0', 'd', '\0',
275 'e', '\0', 'm', '\0', 'a', '\0',
276 'r', '\0', 'k', '\0', 's', '\0',
278 guchar origfile_key[]= {'O', '\0', 'r', '\0', 'i', '\0',
279 'g', '\0', 'i', '\0', 'n', '\0',
280 'a', '\0', 'l', '\0', 'F', '\0',
281 'i', '\0', 'l', '\0', 'e', '\0',
282 'n', '\0', 'a', '\0', 'm', '\0',
283 'e', '\0', '\0', '\0'};
284 guchar privbuild_key[]= {'P', '\0', 'r', '\0', 'i', '\0',
285 'v', '\0', 'a', '\0', 't', '\0',
286 'e', '\0', 'B', '\0', 'u', '\0',
287 'i', '\0', 'l', '\0', 'd', '\0',
289 guchar prodname_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
290 'd', '\0', 'u', '\0', 'c', '\0',
291 't', '\0', 'N', '\0', 'a', '\0',
292 'm', '\0', 'e', '\0', '\0', '\0'};
293 guchar prodver_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
294 'd', '\0', 'u', '\0', 'c', '\0',
295 't', '\0', 'V', '\0', 'e', '\0',
296 'r', '\0', 's', '\0', 'i', '\0',
297 'o', '\0', 'n', '\0', '\0', '\0'};
298 guchar specbuild_key[]= {'S', '\0', 'p', '\0', 'e', '\0',
299 'c', '\0', 'i', '\0', 'a', '\0',
300 'l', '\0', 'B', '\0', 'u', '\0',
301 'i', '\0', 'l', '\0', 'd', '\0',
304 /* data_ptr is pointing at an array of one or more String
305 * blocks with total length (not including alignment padding)
308 while(string_len<data_len) {
311 /* align on a 32-bit boundary */
312 data_ptr=(gpointer)((char *)data_ptr + 3);
313 data_ptr=(gpointer)((char *)data_ptr -
314 (GPOINTER_TO_INT(data_ptr) & 3));
316 data_ptr=process_get_versioninfo_block (data_ptr, &block);
317 if(block.data_len==0) {
318 /* We must have hit padding, so give up
322 g_message (G_GNUC_PRETTY_FUNCTION
323 ": Hit 0-length block, giving up");
328 string_len=string_len+block.data_len;
329 value=(gunichar2 *)data_ptr;
330 /* Skip over the value */
331 data_ptr=((gunichar2 *)data_ptr)+block.value_len;
334 if(!memcmp (block.key, &comments_key,
335 unicode_bytes (block.key))) {
337 process_set_field_string (filever, "comments", value, unicode_chars (value));
338 } else if (!memcmp (block.key, &compname_key,
339 unicode_bytes (block.key))) {
340 process_set_field_string (filever, "companyname", value, unicode_chars (value));
341 } else if (!memcmp (block.key, &filedesc_key,
342 unicode_bytes (block.key))) {
343 process_set_field_string (filever, "filedescription", value, unicode_chars (value));
344 } else if (!memcmp (block.key, &filever_key,
345 unicode_bytes (block.key))) {
346 process_set_field_string (filever, "fileversion", value, unicode_chars (value));
347 } else if (!memcmp (block.key, &internal_key,
348 unicode_bytes (block.key))) {
349 process_set_field_string (filever, "internalname", value, unicode_chars (value));
350 } else if (!memcmp (block.key, &legalcpy_key,
351 unicode_bytes (block.key))) {
352 process_set_field_string (filever, "legalcopyright", value, unicode_chars (value));
353 } else if (!memcmp (block.key, &legaltrade_key,
354 unicode_bytes (block.key))) {
355 process_set_field_string (filever, "legaltrademarks", value, unicode_chars (value));
356 } else if (!memcmp (block.key, &origfile_key,
357 unicode_bytes (block.key))) {
358 process_set_field_string (filever, "originalfilename", value, unicode_chars (value));
359 } else if (!memcmp (block.key, &privbuild_key,
360 unicode_bytes (block.key))) {
361 process_set_field_string (filever, "privatebuild", value, unicode_chars (value));
362 } else if (!memcmp (block.key, &prodname_key,
363 unicode_bytes (block.key))) {
364 process_set_field_string (filever, "productname", value, unicode_chars (value));
365 } else if (!memcmp (block.key, &prodver_key,
366 unicode_bytes (block.key))) {
367 process_set_field_string (filever, "productversion", value, unicode_chars (value));
368 } else if (!memcmp (block.key, &specbuild_key,
369 unicode_bytes (block.key))) {
370 process_set_field_string (filever, "specialbuild", value, unicode_chars (value));
372 /* Not an error, just not interesting
382 /* returns a pointer to the byte following the Stringtable block, or
383 * NULL if the data read hits padding. We can't recover from this
384 * because the data length does not include padding bytes, so it's not
385 * possible to just return the start position + length
387 static gpointer process_read_stringtable_block (MonoObject *filever,
393 guint16 string_len=36; /* length of the StringFileInfo block */
395 /* data_ptr is pointing at an array of StringTable blocks,
396 * with total length (not including alignment padding) of
400 while(string_len<data_len) {
401 /* align on a 32-bit boundary */
402 data_ptr=(gpointer)((char *)data_ptr + 3);
403 data_ptr=(gpointer)((char *)data_ptr -
404 (GPOINTER_TO_INT(data_ptr) & 3));
406 data_ptr=process_get_versioninfo_block (data_ptr, &block);
407 if(block.data_len==0) {
408 /* We must have hit padding, so give up
412 g_message (G_GNUC_PRETTY_FUNCTION
413 ": Hit 0-length block, giving up");
417 string_len=string_len+block.data_len;
419 language = g_utf16_to_utf8 (block.key, unicode_bytes (block.key), NULL, NULL, NULL);
420 g_strdown (language);
421 if (!strcmp (language, "007f04b0") || !strcmp (language, "000004b0")) {
422 /* Got the one we're interested in */
423 process_set_field_string_utf8 (filever, "language",
426 data_ptr=process_read_string_block (filever, data_ptr,
430 /* Some other language. We might want to do
431 * something with this in the future.
433 data_ptr=process_read_string_block (filever, data_ptr,
440 /* Child block hit padding */
442 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
451 static void process_read_fixedfileinfo_block (MonoObject *filever,
452 VS_FIXEDFILEINFO *ffi)
455 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);
458 process_set_field_int (filever, "filemajorpart",
459 HIWORD (ffi->dwFileVersionMS));
460 process_set_field_int (filever, "fileminorpart",
461 LOWORD (ffi->dwFileVersionMS));
462 process_set_field_int (filever, "filebuildpart",
463 HIWORD (ffi->dwFileVersionLS));
464 process_set_field_int (filever, "fileprivatepart",
465 LOWORD (ffi->dwFileVersionLS));
467 process_set_field_int (filever, "productmajorpart",
468 HIWORD (ffi->dwProductVersionMS));
469 process_set_field_int (filever, "productminorpart",
470 LOWORD (ffi->dwProductVersionMS));
471 process_set_field_int (filever, "productbuildpart",
472 HIWORD (ffi->dwProductVersionLS));
473 process_set_field_int (filever, "productprivatepart",
474 LOWORD (ffi->dwProductVersionLS));
476 process_set_field_bool (filever, "isdebug",
477 ffi->dwFileFlags&VS_FF_DEBUG);
478 process_set_field_bool (filever, "isprerelease",
479 ffi->dwFileFlags&VS_FF_PRERELEASE);
480 process_set_field_bool (filever, "ispatched",
481 ffi->dwFileFlags&VS_FF_PATCHED);
482 process_set_field_bool (filever, "isprivatebuild",
483 ffi->dwFileFlags&VS_FF_PRIVATEBUILD);
484 process_set_field_bool (filever, "isspecialbuild",
485 ffi->dwFileFlags&VS_FF_SPECIALBUILD);
488 static void process_get_fileversion (MonoObject *filever, MonoImage *image)
490 MonoPEResourceDataEntry *version_info;
492 VS_FIXEDFILEINFO *ffi;
495 gint32 data_len; /* signed to guard against underflow */
496 guchar vs_key[]= {'V', '\0', 'S', '\0', '_', '\0', 'V', '\0',
497 'E', '\0', 'R', '\0', 'S', '\0', 'I', '\0',
498 'O', '\0', 'N', '\0', '_', '\0', 'I', '\0',
499 'N', '\0', 'F', '\0', 'O', '\0', '\0', '\0'
501 guchar var_key[]= {'V', '\0', 'a', '\0', 'r', '\0', 'F', '\0',
502 'i', '\0', 'l', '\0', 'e', '\0', 'I', '\0',
503 'n', '\0', 'f', '\0', 'o', '\0', '\0', '\0',
505 guchar str_key[]= {'S', '\0', 't', '\0', 'r', '\0', 'i', '\0',
506 'n', '\0', 'g', '\0', 'F', '\0', 'i', '\0',
507 'l', '\0', 'e', '\0', 'I', '\0', 'n', '\0',
508 'f', '\0', 'o', '\0', '\0', '\0',
511 version_info=mono_image_lookup_resource (image,
512 MONO_PE_RESOURCE_ID_VERSION,
515 g_message (G_GNUC_PRETTY_FUNCTION ": image_lookup returned %p",
519 if(version_info==NULL) {
523 data=mono_image_rva_map (image,
524 version_info->rde_data_offset);
529 /* See io-layer/versioninfo.h for the gory details on how this
530 * data is laid out. (data should be pointing to
531 * VS_VERSIONINFO data).
534 data_ptr=process_get_versioninfo_block (data, &block);
536 data_len=block.data_len;
538 if(block.value_len!=sizeof(VS_FIXEDFILEINFO)) {
540 g_message (G_GNUC_PRETTY_FUNCTION
541 ": FIXEDFILEINFO size mismatch");
546 if(memcmp (block.key, &vs_key, unicode_bytes (block.key))) {
548 g_message (G_GNUC_PRETTY_FUNCTION
549 ": VS_VERSION_INFO mismatch");
554 ffi=((VS_FIXEDFILEINFO *)data_ptr);
555 data_ptr = (char *)data_ptr + sizeof(VS_FIXEDFILEINFO);
556 if((ffi->dwSignature!=VS_FFI_SIGNATURE) ||
557 (ffi->dwStrucVersion!=VS_FFI_STRUCVERSION)) {
559 g_message (G_GNUC_PRETTY_FUNCTION
560 ": FIXEDFILEINFO bad signature");
564 process_read_fixedfileinfo_block (filever, ffi);
566 /* Subtract the 92 bytes we've already seen */
569 /* There now follow zero or one StringFileInfo blocks and zero
570 * or one VarFileInfo blocks
572 while(data_len > 0) {
573 /* align on a 32-bit boundary */
574 data_ptr=(gpointer)((char *)data_ptr + 3);
575 data_ptr=(gpointer)((char *)data_ptr -
576 (GPOINTER_TO_INT(data_ptr) & 3));
578 data_ptr=process_get_versioninfo_block (data_ptr, &block);
579 if(block.data_len==0) {
580 /* We must have hit padding, so give up
584 g_message (G_GNUC_PRETTY_FUNCTION
585 ": Hit 0-length block, giving up");
590 data_len=data_len-block.data_len;
592 if(!memcmp (block.key, &var_key, unicode_bytes (block.key))) {
593 data_ptr=process_read_var_block (filever, data_ptr,
595 } else if (!memcmp (block.key, &str_key,
596 unicode_bytes (block.key))) {
597 data_ptr=process_read_stringtable_block (filever, data_ptr, block.data_len);
601 g_message (G_GNUC_PRETTY_FUNCTION
602 ": Not a valid VERSIONINFO child block");
608 /* Child block hit padding */
610 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
617 static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
619 MonoClass *proc_class, *filever_class;
620 MonoObject *item, *filever;
621 MonoDomain *domain=mono_domain_get ();
623 const char* filename;
625 /* Build a System.Diagnostics.ProcessModule with the data.
626 * Leave BaseAddress and EntryPointAddress set to NULL,
627 * FileName is ass->image->name, FileVersionInfo is an object
628 * constructed from the PE image data referenced by
629 * ass->image, ModuleMemorySize set to 0, ModuleName the last
630 * component of FileName.
632 proc_class=mono_class_from_name (system_assembly, "System.Diagnostics",
634 item=mono_object_new (domain, proc_class);
636 filever_class=mono_class_from_name (system_assembly,
637 "System.Diagnostics",
639 filever=mono_object_new (domain, filever_class);
642 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);
645 process_get_fileversion (filever, mono_assembly_get_image (ass));
647 filename = mono_image_get_filename (mono_assembly_get_image (ass));
648 process_set_field_string_utf8 (filever, "filename", filename);
649 process_set_field_string_utf8 (item, "filename", filename);
650 process_set_field_object (item, "version_info", filever);
652 modulename=g_path_get_basename (filename);
653 process_set_field_string_utf8 (item, "modulename", modulename);
656 g_ptr_array_add (modules, item);
659 static void process_scan_modules (gpointer data, gpointer user_data)
661 MonoAssembly *ass=data;
662 GPtrArray *modules=user_data;
664 /* The main assembly is already in the list */
665 if(mono_assembly_get_main () != ass) {
666 process_add_module (modules, ass);
671 /* Returns an array of System.Diagnostics.ProcessModule */
672 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this)
674 /* I was going to use toolhelp for this, but then realised I
675 * was being an idiot :)
677 * (Toolhelp would give shared libraries open by the runtime,
678 * as well as open assemblies. On windows my tests didnt find
679 * the assemblies loaded by mono either.)
681 GPtrArray *modules_list=g_ptr_array_new ();
687 STASH_SYS_ASS (this);
689 /* Make sure the first entry is the main module */
690 process_add_module (modules_list, mono_assembly_get_main ());
692 mono_assembly_foreach (process_scan_modules, modules_list);
694 /* Build a MonoArray out of modules_list */
695 arr=mono_array_new (mono_domain_get (), mono_get_object_class (),
698 for(i=0; i<modules_list->len; i++) {
699 mono_array_set (arr, MonoObject *, i,
700 g_ptr_array_index (modules_list, i));
703 g_ptr_array_free (modules_list, FALSE);
708 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
711 guchar *filename_utf8;
715 STASH_SYS_ASS (this);
717 filename_utf8=mono_string_to_utf8 (filename);
718 image=mono_image_open (filename_utf8, NULL);
719 g_free (filename_utf8);
722 /* FIXME: an exception might be appropriate here */
724 g_message (G_GNUC_PRETTY_FUNCTION ": Failed to load image");
730 process_get_fileversion (this, image);
731 process_set_field_string_utf8 (this, "filename", mono_image_get_filename (image));
733 mono_image_close (image);
737 complete_path (const gunichar2 *appname, gunichar2 **completed)
742 utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
743 if (g_path_is_absolute (utf8app)) {
748 if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) {
753 found = g_find_program_in_path (utf8app);
760 *completed = g_utf8_to_utf16 (found, -1, NULL, NULL, NULL);
766 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)
770 STARTUPINFO startinfo={0};
771 PROCESS_INFORMATION procinfo;
772 gunichar2 *shell_path = NULL;
773 gchar *env_vars = NULL;
774 gboolean free_shell_path = TRUE;
778 startinfo.cb=sizeof(STARTUPINFO);
779 startinfo.dwFlags=STARTF_USESTDHANDLES;
780 startinfo.hStdInput=stdin_handle;
781 startinfo.hStdOutput=stdout_handle;
782 startinfo.hStdError=stderr_handle;
784 if (process_info->use_shell) {
786 const gchar *shell_args;
787 #ifdef PLATFORM_WIN32
788 spath = g_getenv ("COMSPEC");
789 shell_args = "/c %s";
791 spath = g_getenv ("SHELL");
792 shell_args = "-c %s";
799 shell_path = mono_unicode_from_external (spath, &dummy);
800 tmp = mono_string_to_utf8 (cmd);
801 quoted = g_shell_quote (tmp);
802 #ifdef PLATFORM_WIN32
812 newcmd = g_strdup_printf (shell_args, quoted);
815 cmd = mono_string_new (mono_domain_get (), newcmd);
819 shell_path = mono_string_chars (appname);
820 free_shell_path = complete_path (shell_path, &shell_path);
821 if (shell_path == NULL) {
822 process_info->pid = -ERROR_FILE_NOT_FOUND;
827 if (process_info->env_keys != NULL) {
830 MonoString *key, *value;
831 gunichar2 *str, *ptr;
834 for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
835 ms = mono_array_get (process_info->env_values, MonoString *, i);
839 len += mono_string_length (ms) * sizeof (gunichar2);
840 ms = mono_array_get (process_info->env_keys, MonoString *, i);
841 len += mono_string_length (ms) * sizeof (gunichar2);
842 len += 2 * sizeof (gunichar2);
845 equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
846 ptr = str = g_new0 (gunichar2, len + 1);
847 for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
848 value = mono_array_get (process_info->env_values, MonoString *, i);
852 key = mono_array_get (process_info->env_keys, MonoString *, i);
853 memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
854 ptr += mono_string_length (key);
856 memcpy (ptr, equals16, sizeof (gunichar2));
859 memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
860 ptr += mono_string_length (value);
865 env_vars = (gchar *) str;
868 /* The default dir name is "". Turn that into NULL to mean
869 * "current directory"
871 if(mono_string_length (dirname)==0) {
874 dir=mono_string_chars (dirname);
877 ret=CreateProcess (shell_path, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env_vars, dir, &startinfo, &procinfo);
884 process_info->process_handle=procinfo.hProcess;
885 /*process_info->thread_handle=procinfo.hThread;*/
886 process_info->thread_handle=NULL;
887 CloseHandle(procinfo.hThread);
888 process_info->pid=procinfo.dwProcessId;
889 process_info->tid=procinfo.dwThreadId;
891 process_info->pid = -GetLastError ();
897 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
905 ret=WaitForSingleObjectEx (process, INFINITE, TRUE);
907 ret=WaitForSingleObjectEx (process, ms, TRUE);
909 if(ret==WAIT_OBJECT_0) {
916 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
920 FILETIME create_time, exit_time, kernel_time, user_time;
924 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
927 ticks=((guint64)exit_time.dwHighDateTime << 32) +
928 exit_time.dwLowDateTime;
936 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
940 FILETIME create_time, exit_time, kernel_time, user_time;
944 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
947 ticks=((guint64)create_time.dwHighDateTime << 32) +
948 create_time.dwLowDateTime;
956 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
962 GetExitCodeProcess (process, &code);
965 g_message (G_GNUC_PRETTY_FUNCTION ": process exit code is %d", code);
971 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
976 gunichar2 name[MAX_PATH];
982 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
987 len=GetModuleBaseName (process, mod, name, sizeof(name));
993 g_message (G_GNUC_PRETTY_FUNCTION ": process name is [%s]",
994 g_utf16_to_utf8 (name, -1, NULL, NULL, NULL));
997 string=mono_string_new_utf16 (mono_domain_get (), name, len);
1002 /* Returns an array of pids */
1003 MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
1007 guint32 needed, count, i;
1010 MONO_ARCH_SAVE_REGS;
1012 ret=EnumProcesses (pids, sizeof(pids), &needed);
1014 /* FIXME: throw an exception */
1018 count=needed/sizeof(guint32);
1019 procs=mono_array_new (mono_domain_get (), mono_get_int32_class (),
1021 for(i=0; i<count; i++) {
1022 mono_array_set (procs, guint32, i, pids[i]);
1028 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
1031 size_t ws_min, ws_max;
1033 MONO_ARCH_SAVE_REGS;
1035 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1036 *min=(guint32)ws_min;
1037 *max=(guint32)ws_max;
1042 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
1048 MONO_ARCH_SAVE_REGS;
1050 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1061 ret=SetProcessWorkingSetSize (process, ws_min, ws_max);
1067 ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig)
1069 MONO_ARCH_SAVE_REGS;
1071 /* sig == 1 -> Kill, sig == 2 -> CloseMainWindow */
1073 return TerminateProcess (process, -sig);