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>
27 HANDLE ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid)
33 /* GetCurrentProcess returns a pseudo-handle, so use
36 handle=OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid);
39 /* FIXME: Throw an exception */
46 guint32 ves_icall_System_Diagnostics_Process_GetPid_internal (void)
50 return(GetCurrentProcessId ());
53 void ves_icall_System_Diagnostics_Process_Process_free_internal (MonoObject *this,
59 g_message (G_GNUC_PRETTY_FUNCTION ": Closing process %p, handle %p",
63 CloseHandle (process);
66 #define STASH_SYS_ASS(this) \
67 if(system_assembly == NULL) { \
68 system_assembly=this->vtable->klass->image; \
71 static MonoImage *system_assembly=NULL;
73 static guint32 unicode_chars (const gunichar2 *str)
85 static guint32 unicode_bytes (const gunichar2 *str)
91 /* Include the terminators */
98 static void process_set_field_object (MonoObject *obj, const guchar *fieldname,
101 MonoClassField *field;
104 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to object at %p",
108 field=mono_class_get_field_from_name (mono_object_class (obj),
110 *(MonoObject **)(((char *)obj) + field->offset)=data;
113 static void process_set_field_string (MonoObject *obj, const guchar *fieldname,
114 const gunichar2 *val, guint32 len)
116 MonoClassField *field;
120 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to [%s]",
121 fieldname, g_utf16_to_utf8 (val, len, NULL, NULL, NULL));
124 string=mono_string_new_utf16 (mono_object_domain (obj), val, len);
126 field=mono_class_get_field_from_name (mono_object_class (obj),
128 *(MonoString **)(((char *)obj) + field->offset)=string;
131 static void process_set_field_string_utf8 (MonoObject *obj,
132 const guchar *fieldname,
135 MonoClassField *field;
139 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to [%s]",
143 string=mono_string_new (mono_object_domain (obj), val);
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_int (MonoObject *obj, const guchar *fieldname,
153 MonoClassField *field;
156 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to %d",
160 field=mono_class_get_field_from_name (mono_object_class (obj),
162 *(guint32 *)(((char *)obj) + field->offset)=val;
165 static void process_set_field_bool (MonoObject *obj, const guchar *fieldname,
168 MonoClassField *field;
171 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to %s",
172 fieldname, val?"TRUE":"FALSE");
175 field=mono_class_get_field_from_name (mono_object_class (obj),
177 *(guint8 *)(((char *)obj) + field->offset)=val;
187 /* Returns a pointer to the value data, because theres no way to know
188 * how big that data is (value_len is set to zero for most blocks :-()
190 static gpointer process_get_versioninfo_block (gpointer data,
193 block->data_len=*((guint16 *)data);
194 data = (char *)data + sizeof(guint16);
195 block->value_len=*((guint16 *)data);
196 data = (char *)data + sizeof(guint16);
198 /* No idea what the type is supposed to indicate */
199 block->type=*((guint16 *)data);
200 data = (char *)data + sizeof(guint16);
201 block->key=((gunichar2 *)data);
203 /* skip over the key (including the terminator) */
204 data=((gunichar2 *)data)+(unicode_chars (block->key)+1);
206 /* align on a 32-bit boundary */
207 data=(gpointer)(((unsigned)data+3) & (~3));
212 /* Returns a pointer to the byte following the Var block */
213 static gpointer process_read_var_block (MonoObject *filever, gpointer data_ptr,
216 /* Not currently interested in the VarFileInfo block. This
217 * might change if language support is needed for file version
218 * strings (VarFileInfo contains lists of supported
223 /* data_ptr is pointing at a Var block of length data_len */
224 data_ptr=process_get_versioninfo_block (data_ptr, &block);
225 data_ptr=((guchar *)data_ptr)+block.value_len;
230 /* Returns a pointer to the byte following the String block, or NULL
231 * if the data read hits padding. We can't recover from this because
232 * the data length does not include padding bytes, so it's not
233 * possible to just return the start position + length.
235 static gpointer process_read_string_block (MonoObject *filever,
241 guint16 string_len=0;
242 guchar comments_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
243 'm', '\0', 'e', '\0', 'n', '\0',
244 't', '\0', 's', '\0', '\0', '\0'};
245 guchar compname_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
246 'p', '\0', 'a', '\0', 'n', '\0',
247 'y', '\0', 'N', '\0', 'a', '\0',
248 'm', '\0', 'e', '\0', '\0', '\0'};
249 guchar filedesc_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
250 'e', '\0', 'D', '\0', 'e', '\0',
251 's', '\0', 'c', '\0', 'r', '\0',
252 'i', '\0', 'p', '\0', 't', '\0',
253 'i', '\0', 'o', '\0', 'n', '\0',
255 guchar filever_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
256 'e', '\0', 'V', '\0', 'e', '\0',
257 'r', '\0', 's', '\0', 'i', '\0',
258 'o', '\0', 'n', '\0', '\0', '\0'};
259 guchar internal_key[]= {'I', '\0', 'n', '\0', 't', '\0',
260 'e', '\0', 'r', '\0', 'n', '\0',
261 'a', '\0', 'l', '\0', 'N', '\0',
262 'a', '\0', 'm', '\0', 'e', '\0',
264 guchar legalcpy_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
265 'a', '\0', 'l', '\0', 'C', '\0',
266 'o', '\0', 'p', '\0', 'y', '\0',
267 'r', '\0', 'i', '\0', 'g', '\0',
268 'h', '\0', 't', '\0', '\0', '\0'};
269 guchar legaltrade_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
270 'a', '\0', 'l', '\0', 'T', '\0',
271 'r', '\0', 'a', '\0', 'd', '\0',
272 'e', '\0', 'm', '\0', 'a', '\0',
273 'r', '\0', 'k', '\0', 's', '\0',
275 guchar origfile_key[]= {'O', '\0', 'r', '\0', 'i', '\0',
276 'g', '\0', 'i', '\0', 'n', '\0',
277 'a', '\0', 'l', '\0', 'F', '\0',
278 'i', '\0', 'l', '\0', 'e', '\0',
279 'n', '\0', 'a', '\0', 'm', '\0',
280 'e', '\0', '\0', '\0'};
281 guchar privbuild_key[]= {'P', '\0', 'r', '\0', 'i', '\0',
282 'v', '\0', 'a', '\0', 't', '\0',
283 'e', '\0', 'B', '\0', 'u', '\0',
284 'i', '\0', 'l', '\0', 'd', '\0',
286 guchar prodname_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
287 'd', '\0', 'u', '\0', 'c', '\0',
288 't', '\0', 'N', '\0', 'a', '\0',
289 'm', '\0', 'e', '\0', '\0', '\0'};
290 guchar prodver_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
291 'd', '\0', 'u', '\0', 'c', '\0',
292 't', '\0', 'V', '\0', 'e', '\0',
293 'r', '\0', 's', '\0', 'i', '\0',
294 'o', '\0', 'n', '\0', '\0', '\0'};
295 guchar specbuild_key[]= {'S', '\0', 'p', '\0', 'e', '\0',
296 'c', '\0', 'i', '\0', 'a', '\0',
297 'l', '\0', 'B', '\0', 'u', '\0',
298 'i', '\0', 'l', '\0', 'd', '\0',
301 /* data_ptr is pointing at an array of one or more String
302 * blocks with total length (not including alignment padding)
305 while(string_len<data_len) {
308 /* align on a 32-bit boundary */
309 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
311 data_ptr=process_get_versioninfo_block (data_ptr, &block);
312 if(block.data_len==0) {
313 /* We must have hit padding, so give up
317 g_message (G_GNUC_PRETTY_FUNCTION
318 ": Hit 0-length block, giving up");
323 string_len=string_len+block.data_len;
324 value=(gunichar2 *)data_ptr;
325 /* Skip over the value */
326 data_ptr=((gunichar2 *)data_ptr)+block.value_len;
329 if(!memcmp (block.key, &comments_key,
330 unicode_bytes (block.key))) {
332 process_set_field_string (filever, "comments", value, unicode_chars (value));
333 } else if (!memcmp (block.key, &compname_key,
334 unicode_bytes (block.key))) {
335 process_set_field_string (filever, "companyname", value, unicode_chars (value));
336 } else if (!memcmp (block.key, &filedesc_key,
337 unicode_bytes (block.key))) {
338 process_set_field_string (filever, "filedescription", value, unicode_chars (value));
339 } else if (!memcmp (block.key, &filever_key,
340 unicode_bytes (block.key))) {
341 process_set_field_string (filever, "fileversion", value, unicode_chars (value));
342 } else if (!memcmp (block.key, &internal_key,
343 unicode_bytes (block.key))) {
344 process_set_field_string (filever, "internalname", value, unicode_chars (value));
345 } else if (!memcmp (block.key, &legalcpy_key,
346 unicode_bytes (block.key))) {
347 process_set_field_string (filever, "legalcopyright", value, unicode_chars (value));
348 } else if (!memcmp (block.key, &legaltrade_key,
349 unicode_bytes (block.key))) {
350 process_set_field_string (filever, "legaltrademarks", value, unicode_chars (value));
351 } else if (!memcmp (block.key, &origfile_key,
352 unicode_bytes (block.key))) {
353 process_set_field_string (filever, "originalfilename", value, unicode_chars (value));
354 } else if (!memcmp (block.key, &privbuild_key,
355 unicode_bytes (block.key))) {
356 process_set_field_string (filever, "privatebuild", value, unicode_chars (value));
357 } else if (!memcmp (block.key, &prodname_key,
358 unicode_bytes (block.key))) {
359 process_set_field_string (filever, "productname", value, unicode_chars (value));
360 } else if (!memcmp (block.key, &prodver_key,
361 unicode_bytes (block.key))) {
362 process_set_field_string (filever, "productversion", value, unicode_chars (value));
363 } else if (!memcmp (block.key, &specbuild_key,
364 unicode_bytes (block.key))) {
365 process_set_field_string (filever, "specialbuild", value, unicode_chars (value));
367 /* Not an error, just not interesting
377 /* returns a pointer to the byte following the Stringtable block, or
378 * NULL if the data read hits padding. We can't recover from this
379 * because the data length does not include padding bytes, so it's not
380 * possible to just return the start position + length
382 static gpointer process_read_stringtable_block (MonoObject *filever,
388 guint16 string_len=36; /* length of the StringFileInfo block */
390 /* data_ptr is pointing at an array of StringTable blocks,
391 * with total length (not including alignment padding) of
395 while(string_len<data_len) {
396 /* align on a 32-bit boundary */
397 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
399 data_ptr=process_get_versioninfo_block (data_ptr, &block);
400 if(block.data_len==0) {
401 /* We must have hit padding, so give up
405 g_message (G_GNUC_PRETTY_FUNCTION
406 ": Hit 0-length block, giving up");
410 string_len=string_len+block.data_len;
412 language = g_utf16_to_utf8 (block.key, unicode_bytes (block.key), NULL, NULL, NULL);
413 g_strdown (language);
414 if (!strcmp (language, "007f04b0") || !strcmp (language, "000004b0")) {
415 /* Got the one we're interested in */
416 process_set_field_string_utf8 (filever, "language",
419 data_ptr=process_read_string_block (filever, data_ptr,
423 /* Some other language. We might want to do
424 * something with this in the future.
426 data_ptr=process_read_string_block (filever, data_ptr,
433 /* Child block hit padding */
435 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
444 static void process_read_fixedfileinfo_block (MonoObject *filever,
445 VS_FIXEDFILEINFO *ffi)
448 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);
451 process_set_field_int (filever, "filemajorpart",
452 HIWORD (ffi->dwFileVersionMS));
453 process_set_field_int (filever, "fileminorpart",
454 LOWORD (ffi->dwFileVersionMS));
455 process_set_field_int (filever, "filebuildpart",
456 HIWORD (ffi->dwFileVersionLS));
457 process_set_field_int (filever, "fileprivatepart",
458 LOWORD (ffi->dwFileVersionLS));
460 process_set_field_int (filever, "productmajorpart",
461 HIWORD (ffi->dwProductVersionMS));
462 process_set_field_int (filever, "productminorpart",
463 LOWORD (ffi->dwProductVersionMS));
464 process_set_field_int (filever, "productbuildpart",
465 HIWORD (ffi->dwProductVersionLS));
466 process_set_field_int (filever, "productprivatepart",
467 LOWORD (ffi->dwProductVersionLS));
469 process_set_field_bool (filever, "isdebug",
470 ffi->dwFileFlags&VS_FF_DEBUG);
471 process_set_field_bool (filever, "isprerelease",
472 ffi->dwFileFlags&VS_FF_PRERELEASE);
473 process_set_field_bool (filever, "ispatched",
474 ffi->dwFileFlags&VS_FF_PATCHED);
475 process_set_field_bool (filever, "isprivatebuild",
476 ffi->dwFileFlags&VS_FF_PRIVATEBUILD);
477 process_set_field_bool (filever, "isspecialbuild",
478 ffi->dwFileFlags&VS_FF_SPECIALBUILD);
481 static void process_get_fileversion (MonoObject *filever, MonoImage *image)
483 MonoPEResourceDataEntry *version_info;
485 VS_FIXEDFILEINFO *ffi;
488 gint32 data_len; /* signed to guard against underflow */
489 guchar vs_key[]= {'V', '\0', 'S', '\0', '_', '\0', 'V', '\0',
490 'E', '\0', 'R', '\0', 'S', '\0', 'I', '\0',
491 'O', '\0', 'N', '\0', '_', '\0', 'I', '\0',
492 'N', '\0', 'F', '\0', 'O', '\0', '\0', '\0'
494 guchar var_key[]= {'V', '\0', 'a', '\0', 'r', '\0', 'F', '\0',
495 'i', '\0', 'l', '\0', 'e', '\0', 'I', '\0',
496 'n', '\0', 'f', '\0', 'o', '\0', '\0', '\0',
498 guchar str_key[]= {'S', '\0', 't', '\0', 'r', '\0', 'i', '\0',
499 'n', '\0', 'g', '\0', 'F', '\0', 'i', '\0',
500 'l', '\0', 'e', '\0', 'I', '\0', 'n', '\0',
501 'f', '\0', 'o', '\0', '\0', '\0',
504 version_info=mono_image_lookup_resource (image,
505 MONO_PE_RESOURCE_ID_VERSION,
508 g_message (G_GNUC_PRETTY_FUNCTION ": image_lookup returned %p",
512 if(version_info==NULL) {
516 data=mono_image_rva_map (image,
517 version_info->rde_data_offset);
522 /* See io-layer/versioninfo.h for the gory details on how this
523 * data is laid out. (data should be pointing to
524 * VS_VERSIONINFO data).
527 data_ptr=process_get_versioninfo_block (data, &block);
529 data_len=block.data_len;
531 if(block.value_len!=sizeof(VS_FIXEDFILEINFO)) {
533 g_message (G_GNUC_PRETTY_FUNCTION
534 ": FIXEDFILEINFO size mismatch");
539 if(memcmp (block.key, &vs_key, unicode_bytes (block.key))) {
541 g_message (G_GNUC_PRETTY_FUNCTION
542 ": VS_VERSION_INFO mismatch");
547 ffi=((VS_FIXEDFILEINFO *)data_ptr);
548 data_ptr = (char *)data_ptr + sizeof(VS_FIXEDFILEINFO);
549 if((ffi->dwSignature!=VS_FFI_SIGNATURE) ||
550 (ffi->dwStrucVersion!=VS_FFI_STRUCVERSION)) {
552 g_message (G_GNUC_PRETTY_FUNCTION
553 ": FIXEDFILEINFO bad signature");
557 process_read_fixedfileinfo_block (filever, ffi);
559 /* Subtract the 92 bytes we've already seen */
562 /* There now follow zero or one StringFileInfo blocks and zero
563 * or one VarFileInfo blocks
565 while(data_len > 0) {
566 /* align on a 32-bit boundary */
567 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
569 data_ptr=process_get_versioninfo_block (data_ptr, &block);
570 if(block.data_len==0) {
571 /* We must have hit padding, so give up
575 g_message (G_GNUC_PRETTY_FUNCTION
576 ": Hit 0-length block, giving up");
581 data_len=data_len-block.data_len;
583 if(!memcmp (block.key, &var_key, unicode_bytes (block.key))) {
584 data_ptr=process_read_var_block (filever, data_ptr,
586 } else if (!memcmp (block.key, &str_key,
587 unicode_bytes (block.key))) {
588 data_ptr=process_read_stringtable_block (filever, data_ptr, block.data_len);
592 g_message (G_GNUC_PRETTY_FUNCTION
593 ": Not a valid VERSIONINFO child block");
599 /* Child block hit padding */
601 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
608 static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
610 MonoClass *proc_class, *filever_class;
611 MonoObject *item, *filever;
612 MonoDomain *domain=mono_domain_get ();
614 const char* filename;
616 /* Build a System.Diagnostics.ProcessModule with the data.
617 * Leave BaseAddress and EntryPointAddress set to NULL,
618 * FileName is ass->image->name, FileVersionInfo is an object
619 * constructed from the PE image data referenced by
620 * ass->image, ModuleMemorySize set to 0, ModuleName the last
621 * component of FileName.
623 proc_class=mono_class_from_name (system_assembly, "System.Diagnostics",
625 item=mono_object_new (domain, proc_class);
627 filever_class=mono_class_from_name (system_assembly,
628 "System.Diagnostics",
630 filever=mono_object_new (domain, filever_class);
633 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);
636 process_get_fileversion (filever, mono_assembly_get_image (ass));
638 filename = mono_image_get_filename (mono_assembly_get_image (ass));
639 process_set_field_string_utf8 (filever, "filename", filename);
640 process_set_field_string_utf8 (item, "filename", filename);
641 process_set_field_object (item, "version_info", filever);
643 modulename=g_path_get_basename (filename);
644 process_set_field_string_utf8 (item, "modulename", modulename);
647 g_ptr_array_add (modules, item);
650 static void process_scan_modules (gpointer data, gpointer user_data)
652 MonoAssembly *ass=data;
653 GPtrArray *modules=user_data;
655 /* The main assembly is already in the list */
656 if(mono_assembly_get_main () != ass) {
657 process_add_module (modules, ass);
662 /* Returns an array of System.Diagnostics.ProcessModule */
663 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this)
665 /* I was going to use toolhelp for this, but then realised I
666 * was being an idiot :)
668 * (Toolhelp would give shared libraries open by the runtime,
669 * as well as open assemblies. On windows my tests didnt find
670 * the assemblies loaded by mono either.)
672 GPtrArray *modules_list=g_ptr_array_new ();
678 STASH_SYS_ASS (this);
680 /* Make sure the first entry is the main module */
681 process_add_module (modules_list, mono_assembly_get_main ());
683 mono_assembly_foreach (process_scan_modules, modules_list);
685 /* Build a MonoArray out of modules_list */
686 arr=mono_array_new (mono_domain_get (), mono_defaults.object_class,
689 for(i=0; i<modules_list->len; i++) {
690 mono_array_set (arr, MonoObject *, i,
691 g_ptr_array_index (modules_list, i));
694 g_ptr_array_free (modules_list, FALSE);
699 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
702 guchar *filename_utf8;
706 STASH_SYS_ASS (this);
708 filename_utf8=mono_string_to_utf8 (filename);
709 image=mono_image_open (filename_utf8, NULL);
710 g_free (filename_utf8);
713 /* FIXME: an exception might be appropriate here */
715 g_message (G_GNUC_PRETTY_FUNCTION ": Failed to load image");
721 process_get_fileversion (this, image);
722 process_set_field_string_utf8 (this, "filename", mono_image_get_filename (image));
724 mono_image_close (image);
728 complete_path (const gunichar2 *appname, gunichar2 **completed)
733 utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
734 if (g_path_is_absolute (utf8app)) {
739 if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE)) {
744 found = g_find_program_in_path (utf8app);
751 *completed = g_utf8_to_utf16 (found, -1, NULL, NULL, NULL);
757 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)
761 STARTUPINFO startinfo={0};
762 PROCESS_INFORMATION procinfo;
763 gunichar2 *shell_path = NULL;
764 gchar *env_vars = NULL;
765 gboolean free_shell_path = TRUE;
769 startinfo.cb=sizeof(STARTUPINFO);
770 startinfo.dwFlags=STARTF_USESTDHANDLES;
771 startinfo.hStdInput=stdin_handle;
772 startinfo.hStdOutput=stdout_handle;
773 startinfo.hStdError=stderr_handle;
775 if (process_info->use_shell) {
777 const gchar *shell_args;
778 #ifdef PLATFORM_WIN32
779 spath = g_getenv ("COMSPEC");
780 shell_args = "/c %s";
782 spath = g_getenv ("SHELL");
783 shell_args = "-c %s";
790 shell_path = mono_unicode_from_external (spath, &dummy);
791 tmp = mono_string_to_utf8 (cmd);
792 quoted = g_shell_quote (tmp);
793 #ifdef PLATFORM_WIN32
803 newcmd = g_strdup_printf (shell_args, quoted);
806 cmd = mono_string_new (mono_domain_get (), newcmd);
810 shell_path = mono_string_chars (appname);
811 free_shell_path = complete_path (shell_path, &shell_path);
812 if (shell_path == NULL) {
813 process_info->pid = -ERROR_FILE_NOT_FOUND;
818 if (process_info->env_keys != NULL) {
821 MonoString *key, *value;
822 gunichar2 *str, *ptr;
825 for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
826 ms = mono_array_get (process_info->env_values, MonoString *, i);
830 len += mono_string_length (ms) * sizeof (gunichar2);
831 ms = mono_array_get (process_info->env_keys, MonoString *, i);
832 len += mono_string_length (ms) * sizeof (gunichar2);
833 len += 2 * sizeof (gunichar2);
836 equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
837 ptr = str = g_new0 (gunichar2, len + 1);
838 for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
839 value = mono_array_get (process_info->env_values, MonoString *, i);
843 key = mono_array_get (process_info->env_keys, MonoString *, i);
844 memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
845 ptr += mono_string_length (key);
847 memcpy (ptr, equals16, sizeof (gunichar2));
850 memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
851 ptr += mono_string_length (value);
856 env_vars = (gchar *) str;
859 /* The default dir name is "". Turn that into NULL to mean
860 * "current directory"
862 if(mono_string_length (dirname)==0) {
865 dir=mono_string_chars (dirname);
868 ret=CreateProcess (shell_path, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env_vars, dir, &startinfo, &procinfo);
875 process_info->process_handle=procinfo.hProcess;
876 process_info->thread_handle=procinfo.hThread;
877 process_info->pid=procinfo.dwProcessId;
878 process_info->tid=procinfo.dwThreadId;
880 process_info->pid = -GetLastError ();
886 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
894 ret=WaitForSingleObjectEx (process, INFINITE, TRUE);
896 ret=WaitForSingleObjectEx (process, ms, TRUE);
898 if(ret==WAIT_OBJECT_0) {
905 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
909 FILETIME create_time, exit_time, kernel_time, user_time;
913 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
916 ticks=((guint64)exit_time.dwHighDateTime << 32) +
917 exit_time.dwLowDateTime;
925 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
929 FILETIME create_time, exit_time, kernel_time, user_time;
933 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
936 ticks=((guint64)create_time.dwHighDateTime << 32) +
937 create_time.dwLowDateTime;
945 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
951 GetExitCodeProcess (process, &code);
954 g_message (G_GNUC_PRETTY_FUNCTION ": process exit code is %d", code);
960 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
965 gunichar2 name[MAX_PATH];
971 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
976 len=GetModuleBaseName (process, mod, name, sizeof(name));
982 g_message (G_GNUC_PRETTY_FUNCTION ": process name is [%s]",
983 g_utf16_to_utf8 (name, -1, NULL, NULL, NULL));
986 string=mono_string_new_utf16 (mono_domain_get (), name, len);
991 /* Returns an array of pids */
992 MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
996 guint32 needed, count, i;
1001 ret=EnumProcesses (pids, sizeof(pids), &needed);
1003 /* FIXME: throw an exception */
1007 count=needed/sizeof(guint32);
1008 procs=mono_array_new (mono_domain_get (), mono_defaults.int_class,
1010 for(i=0; i<count; i++) {
1011 mono_array_set (procs, guint32, i, pids[i]);
1017 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
1020 size_t ws_min, ws_max;
1022 MONO_ARCH_SAVE_REGS;
1024 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1025 *min=(guint32)ws_min;
1026 *max=(guint32)ws_max;
1031 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
1037 MONO_ARCH_SAVE_REGS;
1039 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1050 ret=SetProcessWorkingSetSize (process, ws_min, ws_max);
1056 ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig)
1058 MONO_ARCH_SAVE_REGS;
1060 /* sig == 1 -> Kill, sig == 2 -> CloseMainWindow */
1062 return TerminateProcess (process, -sig);