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)(((unsigned)data+3) & (~3));
214 /* Returns a pointer to the byte following the Var block */
215 static gpointer process_read_var_block (MonoObject *filever, gpointer data_ptr,
218 /* Not currently interested in the VarFileInfo block. This
219 * might change if language support is needed for file version
220 * strings (VarFileInfo contains lists of supported
225 /* data_ptr is pointing at a Var block of length data_len */
226 data_ptr=process_get_versioninfo_block (data_ptr, &block);
227 data_ptr=((guchar *)data_ptr)+block.value_len;
232 /* Returns a pointer to the byte following the String block, or NULL
233 * if the data read hits padding. We can't recover from this because
234 * the data length does not include padding bytes, so it's not
235 * possible to just return the start position + length.
237 static gpointer process_read_string_block (MonoObject *filever,
243 guint16 string_len=0;
244 guchar comments_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
245 'm', '\0', 'e', '\0', 'n', '\0',
246 't', '\0', 's', '\0', '\0', '\0'};
247 guchar compname_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
248 'p', '\0', 'a', '\0', 'n', '\0',
249 'y', '\0', 'N', '\0', 'a', '\0',
250 'm', '\0', 'e', '\0', '\0', '\0'};
251 guchar filedesc_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
252 'e', '\0', 'D', '\0', 'e', '\0',
253 's', '\0', 'c', '\0', 'r', '\0',
254 'i', '\0', 'p', '\0', 't', '\0',
255 'i', '\0', 'o', '\0', 'n', '\0',
257 guchar filever_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
258 'e', '\0', 'V', '\0', 'e', '\0',
259 'r', '\0', 's', '\0', 'i', '\0',
260 'o', '\0', 'n', '\0', '\0', '\0'};
261 guchar internal_key[]= {'I', '\0', 'n', '\0', 't', '\0',
262 'e', '\0', 'r', '\0', 'n', '\0',
263 'a', '\0', 'l', '\0', 'N', '\0',
264 'a', '\0', 'm', '\0', 'e', '\0',
266 guchar legalcpy_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
267 'a', '\0', 'l', '\0', 'C', '\0',
268 'o', '\0', 'p', '\0', 'y', '\0',
269 'r', '\0', 'i', '\0', 'g', '\0',
270 'h', '\0', 't', '\0', '\0', '\0'};
271 guchar legaltrade_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
272 'a', '\0', 'l', '\0', 'T', '\0',
273 'r', '\0', 'a', '\0', 'd', '\0',
274 'e', '\0', 'm', '\0', 'a', '\0',
275 'r', '\0', 'k', '\0', 's', '\0',
277 guchar origfile_key[]= {'O', '\0', 'r', '\0', 'i', '\0',
278 'g', '\0', 'i', '\0', 'n', '\0',
279 'a', '\0', 'l', '\0', 'F', '\0',
280 'i', '\0', 'l', '\0', 'e', '\0',
281 'n', '\0', 'a', '\0', 'm', '\0',
282 'e', '\0', '\0', '\0'};
283 guchar privbuild_key[]= {'P', '\0', 'r', '\0', 'i', '\0',
284 'v', '\0', 'a', '\0', 't', '\0',
285 'e', '\0', 'B', '\0', 'u', '\0',
286 'i', '\0', 'l', '\0', 'd', '\0',
288 guchar prodname_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
289 'd', '\0', 'u', '\0', 'c', '\0',
290 't', '\0', 'N', '\0', 'a', '\0',
291 'm', '\0', 'e', '\0', '\0', '\0'};
292 guchar prodver_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
293 'd', '\0', 'u', '\0', 'c', '\0',
294 't', '\0', 'V', '\0', 'e', '\0',
295 'r', '\0', 's', '\0', 'i', '\0',
296 'o', '\0', 'n', '\0', '\0', '\0'};
297 guchar specbuild_key[]= {'S', '\0', 'p', '\0', 'e', '\0',
298 'c', '\0', 'i', '\0', 'a', '\0',
299 'l', '\0', 'B', '\0', 'u', '\0',
300 'i', '\0', 'l', '\0', 'd', '\0',
303 /* data_ptr is pointing at an array of one or more String
304 * blocks with total length (not including alignment padding)
307 while(string_len<data_len) {
310 /* align on a 32-bit boundary */
311 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
313 data_ptr=process_get_versioninfo_block (data_ptr, &block);
314 if(block.data_len==0) {
315 /* We must have hit padding, so give up
319 g_message (G_GNUC_PRETTY_FUNCTION
320 ": Hit 0-length block, giving up");
325 string_len=string_len+block.data_len;
326 value=(gunichar2 *)data_ptr;
327 /* Skip over the value */
328 data_ptr=((gunichar2 *)data_ptr)+block.value_len;
331 if(!memcmp (block.key, &comments_key,
332 unicode_bytes (block.key))) {
334 process_set_field_string (filever, "comments", value, unicode_chars (value));
335 } else if (!memcmp (block.key, &compname_key,
336 unicode_bytes (block.key))) {
337 process_set_field_string (filever, "companyname", value, unicode_chars (value));
338 } else if (!memcmp (block.key, &filedesc_key,
339 unicode_bytes (block.key))) {
340 process_set_field_string (filever, "filedescription", value, unicode_chars (value));
341 } else if (!memcmp (block.key, &filever_key,
342 unicode_bytes (block.key))) {
343 process_set_field_string (filever, "fileversion", value, unicode_chars (value));
344 } else if (!memcmp (block.key, &internal_key,
345 unicode_bytes (block.key))) {
346 process_set_field_string (filever, "internalname", value, unicode_chars (value));
347 } else if (!memcmp (block.key, &legalcpy_key,
348 unicode_bytes (block.key))) {
349 process_set_field_string (filever, "legalcopyright", value, unicode_chars (value));
350 } else if (!memcmp (block.key, &legaltrade_key,
351 unicode_bytes (block.key))) {
352 process_set_field_string (filever, "legaltrademarks", value, unicode_chars (value));
353 } else if (!memcmp (block.key, &origfile_key,
354 unicode_bytes (block.key))) {
355 process_set_field_string (filever, "originalfilename", value, unicode_chars (value));
356 } else if (!memcmp (block.key, &privbuild_key,
357 unicode_bytes (block.key))) {
358 process_set_field_string (filever, "privatebuild", value, unicode_chars (value));
359 } else if (!memcmp (block.key, &prodname_key,
360 unicode_bytes (block.key))) {
361 process_set_field_string (filever, "productname", value, unicode_chars (value));
362 } else if (!memcmp (block.key, &prodver_key,
363 unicode_bytes (block.key))) {
364 process_set_field_string (filever, "productversion", value, unicode_chars (value));
365 } else if (!memcmp (block.key, &specbuild_key,
366 unicode_bytes (block.key))) {
367 process_set_field_string (filever, "specialbuild", value, unicode_chars (value));
369 /* Not an error, just not interesting
379 /* returns a pointer to the byte following the Stringtable block, or
380 * NULL if the data read hits padding. We can't recover from this
381 * because the data length does not include padding bytes, so it's not
382 * possible to just return the start position + length
384 static gpointer process_read_stringtable_block (MonoObject *filever,
390 guint16 string_len=36; /* length of the StringFileInfo block */
392 /* data_ptr is pointing at an array of StringTable blocks,
393 * with total length (not including alignment padding) of
397 while(string_len<data_len) {
398 /* align on a 32-bit boundary */
399 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
401 data_ptr=process_get_versioninfo_block (data_ptr, &block);
402 if(block.data_len==0) {
403 /* We must have hit padding, so give up
407 g_message (G_GNUC_PRETTY_FUNCTION
408 ": Hit 0-length block, giving up");
412 string_len=string_len+block.data_len;
414 language = g_utf16_to_utf8 (block.key, unicode_bytes (block.key), NULL, NULL, NULL);
415 g_strdown (language);
416 if (!strcmp (language, "007f04b0") || !strcmp (language, "000004b0")) {
417 /* Got the one we're interested in */
418 process_set_field_string_utf8 (filever, "language",
421 data_ptr=process_read_string_block (filever, data_ptr,
425 /* Some other language. We might want to do
426 * something with this in the future.
428 data_ptr=process_read_string_block (filever, data_ptr,
435 /* Child block hit padding */
437 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
446 static void process_read_fixedfileinfo_block (MonoObject *filever,
447 VS_FIXEDFILEINFO *ffi)
450 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);
453 process_set_field_int (filever, "filemajorpart",
454 HIWORD (ffi->dwFileVersionMS));
455 process_set_field_int (filever, "fileminorpart",
456 LOWORD (ffi->dwFileVersionMS));
457 process_set_field_int (filever, "filebuildpart",
458 HIWORD (ffi->dwFileVersionLS));
459 process_set_field_int (filever, "fileprivatepart",
460 LOWORD (ffi->dwFileVersionLS));
462 process_set_field_int (filever, "productmajorpart",
463 HIWORD (ffi->dwProductVersionMS));
464 process_set_field_int (filever, "productminorpart",
465 LOWORD (ffi->dwProductVersionMS));
466 process_set_field_int (filever, "productbuildpart",
467 HIWORD (ffi->dwProductVersionLS));
468 process_set_field_int (filever, "productprivatepart",
469 LOWORD (ffi->dwProductVersionLS));
471 process_set_field_bool (filever, "isdebug",
472 ffi->dwFileFlags&VS_FF_DEBUG);
473 process_set_field_bool (filever, "isprerelease",
474 ffi->dwFileFlags&VS_FF_PRERELEASE);
475 process_set_field_bool (filever, "ispatched",
476 ffi->dwFileFlags&VS_FF_PATCHED);
477 process_set_field_bool (filever, "isprivatebuild",
478 ffi->dwFileFlags&VS_FF_PRIVATEBUILD);
479 process_set_field_bool (filever, "isspecialbuild",
480 ffi->dwFileFlags&VS_FF_SPECIALBUILD);
483 static void process_get_fileversion (MonoObject *filever, MonoImage *image)
485 MonoPEResourceDataEntry *version_info;
487 VS_FIXEDFILEINFO *ffi;
490 gint32 data_len; /* signed to guard against underflow */
491 guchar vs_key[]= {'V', '\0', 'S', '\0', '_', '\0', 'V', '\0',
492 'E', '\0', 'R', '\0', 'S', '\0', 'I', '\0',
493 'O', '\0', 'N', '\0', '_', '\0', 'I', '\0',
494 'N', '\0', 'F', '\0', 'O', '\0', '\0', '\0'
496 guchar var_key[]= {'V', '\0', 'a', '\0', 'r', '\0', 'F', '\0',
497 'i', '\0', 'l', '\0', 'e', '\0', 'I', '\0',
498 'n', '\0', 'f', '\0', 'o', '\0', '\0', '\0',
500 guchar str_key[]= {'S', '\0', 't', '\0', 'r', '\0', 'i', '\0',
501 'n', '\0', 'g', '\0', 'F', '\0', 'i', '\0',
502 'l', '\0', 'e', '\0', 'I', '\0', 'n', '\0',
503 'f', '\0', 'o', '\0', '\0', '\0',
506 version_info=mono_image_lookup_resource (image,
507 MONO_PE_RESOURCE_ID_VERSION,
510 g_message (G_GNUC_PRETTY_FUNCTION ": image_lookup returned %p",
514 if(version_info==NULL) {
518 data=mono_image_rva_map (image,
519 version_info->rde_data_offset);
524 /* See io-layer/versioninfo.h for the gory details on how this
525 * data is laid out. (data should be pointing to
526 * VS_VERSIONINFO data).
529 data_ptr=process_get_versioninfo_block (data, &block);
531 data_len=block.data_len;
533 if(block.value_len!=sizeof(VS_FIXEDFILEINFO)) {
535 g_message (G_GNUC_PRETTY_FUNCTION
536 ": FIXEDFILEINFO size mismatch");
541 if(memcmp (block.key, &vs_key, unicode_bytes (block.key))) {
543 g_message (G_GNUC_PRETTY_FUNCTION
544 ": VS_VERSION_INFO mismatch");
549 ffi=((VS_FIXEDFILEINFO *)data_ptr);
550 data_ptr = (char *)data_ptr + sizeof(VS_FIXEDFILEINFO);
551 if((ffi->dwSignature!=VS_FFI_SIGNATURE) ||
552 (ffi->dwStrucVersion!=VS_FFI_STRUCVERSION)) {
554 g_message (G_GNUC_PRETTY_FUNCTION
555 ": FIXEDFILEINFO bad signature");
559 process_read_fixedfileinfo_block (filever, ffi);
561 /* Subtract the 92 bytes we've already seen */
564 /* There now follow zero or one StringFileInfo blocks and zero
565 * or one VarFileInfo blocks
567 while(data_len > 0) {
568 /* align on a 32-bit boundary */
569 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
571 data_ptr=process_get_versioninfo_block (data_ptr, &block);
572 if(block.data_len==0) {
573 /* We must have hit padding, so give up
577 g_message (G_GNUC_PRETTY_FUNCTION
578 ": Hit 0-length block, giving up");
583 data_len=data_len-block.data_len;
585 if(!memcmp (block.key, &var_key, unicode_bytes (block.key))) {
586 data_ptr=process_read_var_block (filever, data_ptr,
588 } else if (!memcmp (block.key, &str_key,
589 unicode_bytes (block.key))) {
590 data_ptr=process_read_stringtable_block (filever, data_ptr, block.data_len);
594 g_message (G_GNUC_PRETTY_FUNCTION
595 ": Not a valid VERSIONINFO child block");
601 /* Child block hit padding */
603 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
610 static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
612 MonoClass *proc_class, *filever_class;
613 MonoObject *item, *filever;
614 MonoDomain *domain=mono_domain_get ();
616 const char* filename;
618 /* Build a System.Diagnostics.ProcessModule with the data.
619 * Leave BaseAddress and EntryPointAddress set to NULL,
620 * FileName is ass->image->name, FileVersionInfo is an object
621 * constructed from the PE image data referenced by
622 * ass->image, ModuleMemorySize set to 0, ModuleName the last
623 * component of FileName.
625 proc_class=mono_class_from_name (system_assembly, "System.Diagnostics",
627 item=mono_object_new (domain, proc_class);
629 filever_class=mono_class_from_name (system_assembly,
630 "System.Diagnostics",
632 filever=mono_object_new (domain, filever_class);
635 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);
638 process_get_fileversion (filever, mono_assembly_get_image (ass));
640 filename = mono_image_get_filename (mono_assembly_get_image (ass));
641 process_set_field_string_utf8 (filever, "filename", filename);
642 process_set_field_string_utf8 (item, "filename", filename);
643 process_set_field_object (item, "version_info", filever);
645 modulename=g_path_get_basename (filename);
646 process_set_field_string_utf8 (item, "modulename", modulename);
649 g_ptr_array_add (modules, item);
652 static void process_scan_modules (gpointer data, gpointer user_data)
654 MonoAssembly *ass=data;
655 GPtrArray *modules=user_data;
657 /* The main assembly is already in the list */
658 if(mono_assembly_get_main () != ass) {
659 process_add_module (modules, ass);
664 /* Returns an array of System.Diagnostics.ProcessModule */
665 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this)
667 /* I was going to use toolhelp for this, but then realised I
668 * was being an idiot :)
670 * (Toolhelp would give shared libraries open by the runtime,
671 * as well as open assemblies. On windows my tests didnt find
672 * the assemblies loaded by mono either.)
674 GPtrArray *modules_list=g_ptr_array_new ();
680 STASH_SYS_ASS (this);
682 /* Make sure the first entry is the main module */
683 process_add_module (modules_list, mono_assembly_get_main ());
685 mono_assembly_foreach (process_scan_modules, modules_list);
687 /* Build a MonoArray out of modules_list */
688 arr=mono_array_new (mono_domain_get (), mono_get_object_class (),
691 for(i=0; i<modules_list->len; i++) {
692 mono_array_set (arr, MonoObject *, i,
693 g_ptr_array_index (modules_list, i));
696 g_ptr_array_free (modules_list, FALSE);
701 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
704 guchar *filename_utf8;
708 STASH_SYS_ASS (this);
710 filename_utf8=mono_string_to_utf8 (filename);
711 image=mono_image_open (filename_utf8, NULL);
712 g_free (filename_utf8);
715 /* FIXME: an exception might be appropriate here */
717 g_message (G_GNUC_PRETTY_FUNCTION ": Failed to load image");
723 process_get_fileversion (this, image);
724 process_set_field_string_utf8 (this, "filename", mono_image_get_filename (image));
726 mono_image_close (image);
730 complete_path (const gunichar2 *appname, gunichar2 **completed)
735 utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
736 if (g_path_is_absolute (utf8app)) {
741 if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) {
746 found = g_find_program_in_path (utf8app);
753 *completed = g_utf8_to_utf16 (found, -1, NULL, NULL, NULL);
759 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)
763 STARTUPINFO startinfo={0};
764 PROCESS_INFORMATION procinfo;
765 gunichar2 *shell_path = NULL;
766 gchar *env_vars = NULL;
767 gboolean free_shell_path = TRUE;
771 startinfo.cb=sizeof(STARTUPINFO);
772 startinfo.dwFlags=STARTF_USESTDHANDLES;
773 startinfo.hStdInput=stdin_handle;
774 startinfo.hStdOutput=stdout_handle;
775 startinfo.hStdError=stderr_handle;
777 if (process_info->use_shell) {
779 const gchar *shell_args;
780 #ifdef PLATFORM_WIN32
781 spath = g_getenv ("COMSPEC");
782 shell_args = "/c %s";
784 spath = g_getenv ("SHELL");
785 shell_args = "-c %s";
792 shell_path = mono_unicode_from_external (spath, &dummy);
793 tmp = mono_string_to_utf8 (cmd);
794 quoted = g_shell_quote (tmp);
795 #ifdef PLATFORM_WIN32
805 newcmd = g_strdup_printf (shell_args, quoted);
808 cmd = mono_string_new (mono_domain_get (), newcmd);
812 shell_path = mono_string_chars (appname);
813 free_shell_path = complete_path (shell_path, &shell_path);
814 if (shell_path == NULL) {
815 process_info->pid = -ERROR_FILE_NOT_FOUND;
820 if (process_info->env_keys != NULL) {
823 MonoString *key, *value;
824 gunichar2 *str, *ptr;
827 for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
828 ms = mono_array_get (process_info->env_values, MonoString *, i);
832 len += mono_string_length (ms) * sizeof (gunichar2);
833 ms = mono_array_get (process_info->env_keys, MonoString *, i);
834 len += mono_string_length (ms) * sizeof (gunichar2);
835 len += 2 * sizeof (gunichar2);
838 equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
839 ptr = str = g_new0 (gunichar2, len + 1);
840 for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
841 value = mono_array_get (process_info->env_values, MonoString *, i);
845 key = mono_array_get (process_info->env_keys, MonoString *, i);
846 memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
847 ptr += mono_string_length (key);
849 memcpy (ptr, equals16, sizeof (gunichar2));
852 memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
853 ptr += mono_string_length (value);
858 env_vars = (gchar *) str;
861 /* The default dir name is "". Turn that into NULL to mean
862 * "current directory"
864 if(mono_string_length (dirname)==0) {
867 dir=mono_string_chars (dirname);
870 ret=CreateProcess (shell_path, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env_vars, dir, &startinfo, &procinfo);
877 process_info->process_handle=procinfo.hProcess;
878 process_info->thread_handle=procinfo.hThread;
879 process_info->pid=procinfo.dwProcessId;
880 process_info->tid=procinfo.dwThreadId;
882 process_info->pid = -GetLastError ();
888 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
896 ret=WaitForSingleObjectEx (process, INFINITE, TRUE);
898 ret=WaitForSingleObjectEx (process, ms, TRUE);
900 if(ret==WAIT_OBJECT_0) {
907 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
911 FILETIME create_time, exit_time, kernel_time, user_time;
915 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
918 ticks=((guint64)exit_time.dwHighDateTime << 32) +
919 exit_time.dwLowDateTime;
927 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
931 FILETIME create_time, exit_time, kernel_time, user_time;
935 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
938 ticks=((guint64)create_time.dwHighDateTime << 32) +
939 create_time.dwLowDateTime;
947 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
953 GetExitCodeProcess (process, &code);
956 g_message (G_GNUC_PRETTY_FUNCTION ": process exit code is %d", code);
962 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
967 gunichar2 name[MAX_PATH];
973 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
978 len=GetModuleBaseName (process, mod, name, sizeof(name));
984 g_message (G_GNUC_PRETTY_FUNCTION ": process name is [%s]",
985 g_utf16_to_utf8 (name, -1, NULL, NULL, NULL));
988 string=mono_string_new_utf16 (mono_domain_get (), name, len);
993 /* Returns an array of pids */
994 MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
998 guint32 needed, count, i;
1001 MONO_ARCH_SAVE_REGS;
1003 ret=EnumProcesses (pids, sizeof(pids), &needed);
1005 /* FIXME: throw an exception */
1009 count=needed/sizeof(guint32);
1010 procs=mono_array_new (mono_domain_get (), mono_get_int32_class (),
1012 for(i=0; i<count; i++) {
1013 mono_array_set (procs, guint32, i, pids[i]);
1019 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
1022 size_t ws_min, ws_max;
1024 MONO_ARCH_SAVE_REGS;
1026 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1027 *min=(guint32)ws_min;
1028 *max=(guint32)ws_max;
1033 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
1039 MONO_ARCH_SAVE_REGS;
1041 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1052 ret=SetProcessWorkingSetSize (process, ws_min, ws_max);
1058 ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig)
1060 MONO_ARCH_SAVE_REGS;
1062 /* sig == 1 -> Kill, sig == 2 -> CloseMainWindow */
1064 return TerminateProcess (process, -sig);