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_cli_rva_map (image->image_info,
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 ();
615 /* Build a System.Diagnostics.ProcessModule with the data.
616 * Leave BaseAddress and EntryPointAddress set to NULL,
617 * FileName is ass->image->name, FileVersionInfo is an object
618 * constructed from the PE image data referenced by
619 * ass->image, ModuleMemorySize set to 0, ModuleName the last
620 * component of FileName.
622 proc_class=mono_class_from_name (system_assembly, "System.Diagnostics",
624 item=mono_object_new (domain, proc_class);
626 filever_class=mono_class_from_name (system_assembly,
627 "System.Diagnostics",
629 filever=mono_object_new (domain, filever_class);
632 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);
635 process_get_fileversion (filever, ass->image);
637 process_set_field_string_utf8 (filever, "filename", ass->image->name);
638 process_set_field_string_utf8 (item, "filename", ass->image->name);
639 process_set_field_object (item, "version_info", filever);
641 modulename=g_path_get_basename (ass->image->name);
642 process_set_field_string_utf8 (item, "modulename", modulename);
645 g_ptr_array_add (modules, item);
648 static void process_scan_modules (gpointer data, gpointer user_data)
650 MonoAssembly *ass=data;
651 GPtrArray *modules=user_data;
653 /* The main assembly is already in the list */
654 if(mono_assembly_get_main () != ass) {
655 process_add_module (modules, ass);
660 /* Returns an array of System.Diagnostics.ProcessModule */
661 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this)
663 /* I was going to use toolhelp for this, but then realised I
664 * was being an idiot :)
666 * (Toolhelp would give shared libraries open by the runtime,
667 * as well as open assemblies. On windows my tests didnt find
668 * the assemblies loaded by mono either.)
670 GPtrArray *modules_list=g_ptr_array_new ();
676 STASH_SYS_ASS (this);
678 /* Make sure the first entry is the main module */
679 process_add_module (modules_list, mono_assembly_get_main ());
681 mono_assembly_foreach (process_scan_modules, modules_list);
683 /* Build a MonoArray out of modules_list */
684 arr=mono_array_new (mono_domain_get (), mono_defaults.object_class,
687 for(i=0; i<modules_list->len; i++) {
688 mono_array_set (arr, MonoObject *, i,
689 g_ptr_array_index (modules_list, i));
692 g_ptr_array_free (modules_list, FALSE);
697 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
700 guchar *filename_utf8;
704 STASH_SYS_ASS (this);
706 filename_utf8=mono_string_to_utf8 (filename);
707 image=mono_image_open (filename_utf8, NULL);
708 g_free (filename_utf8);
711 /* FIXME: an exception might be appropriate here */
713 g_message (G_GNUC_PRETTY_FUNCTION ": Failed to load image");
719 process_get_fileversion (this, image);
720 process_set_field_string_utf8 (this, "filename", image->name);
722 mono_image_close (image);
725 MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *cmd, MonoString *dirname, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info)
729 STARTUPINFO startinfo={0};
730 PROCESS_INFORMATION procinfo;
731 gunichar2 *shell_path = NULL;
732 gchar *env_vars = NULL;
736 startinfo.cb=sizeof(STARTUPINFO);
737 startinfo.dwFlags=STARTF_USESTDHANDLES;
738 startinfo.hStdInput=stdin_handle;
739 startinfo.hStdOutput=stdout_handle;
740 startinfo.hStdError=stderr_handle;
742 if (process_info->use_shell) {
745 #ifdef PLATFORM_WIN32
746 spath = g_getenv ("COMSPEC");
747 shell_args = "/c %s";
749 spath = g_getenv ("SHELL");
750 shell_args = "-c %s";
757 shell_path = mono_unicode_from_external (spath, &dummy);
758 tmp = mono_string_to_utf8 (cmd);
759 quoted = g_shell_quote (tmp);
760 newcmd = g_strdup_printf (shell_args, quoted);
763 cmd = mono_string_new (mono_domain_get (), newcmd);
768 if (process_info->env_keys != NULL) {
771 MonoString *key, *value;
772 gunichar2 *str, *ptr;
775 for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
776 ms = mono_array_get (process_info->env_values, MonoString *, i);
780 len += mono_string_length (ms) * sizeof (gunichar2);
781 ms = mono_array_get (process_info->env_keys, MonoString *, i);
782 len += mono_string_length (ms) * sizeof (gunichar2);
783 len += 2 * sizeof (gunichar2);
786 equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
787 ptr = str = g_new0 (gunichar2, len + 1);
788 for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
789 value = mono_array_get (process_info->env_values, MonoString *, i);
793 key = mono_array_get (process_info->env_keys, MonoString *, i);
794 memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
795 ptr += mono_string_length (key);
797 memcpy (ptr, equals16, sizeof (gunichar2));
800 memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
801 ptr += mono_string_length (value);
806 env_vars = (gchar *) str;
809 /* The default dir name is "". Turn that into NULL to mean
810 * "current directory"
812 if(mono_string_length (dirname)==0) {
815 dir=mono_string_chars (dirname);
818 ret=CreateProcess (shell_path, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env_vars, dir, &startinfo, &procinfo);
823 process_info->process_handle=procinfo.hProcess;
824 process_info->thread_handle=procinfo.hThread;
825 process_info->pid=procinfo.dwProcessId;
826 process_info->tid=procinfo.dwThreadId;
828 process_info->pid = -GetLastError ();
834 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
842 ret=WaitForSingleObject (process, INFINITE);
844 ret=WaitForSingleObject (process, ms);
847 if(ret==WAIT_OBJECT_0) {
854 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
858 FILETIME create_time, exit_time, kernel_time, user_time;
862 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
865 ticks=((guint64)exit_time.dwHighDateTime << 32) +
866 exit_time.dwLowDateTime;
874 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
878 FILETIME create_time, exit_time, kernel_time, user_time;
882 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
885 ticks=((guint64)create_time.dwHighDateTime << 32) +
886 create_time.dwLowDateTime;
894 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
900 GetExitCodeProcess (process, &code);
903 g_message (G_GNUC_PRETTY_FUNCTION ": process exit code is %d", code);
909 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
914 gunichar2 name[MAX_PATH];
920 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
925 len=GetModuleBaseName (process, mod, name, sizeof(name));
931 g_message (G_GNUC_PRETTY_FUNCTION ": process name is [%s]",
932 g_utf16_to_utf8 (name, -1, NULL, NULL, NULL));
935 string=mono_string_new_utf16 (mono_domain_get (), name, len);
940 /* Returns an array of pids */
941 MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
945 guint32 needed, count, i;
950 ret=EnumProcesses (pids, sizeof(pids), &needed);
952 /* FIXME: throw an exception */
956 count=needed/sizeof(guint32);
957 procs=mono_array_new (mono_domain_get (), mono_defaults.int_class,
959 for(i=0; i<count; i++) {
960 mono_array_set (procs, guint32, i, pids[i]);
966 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
969 size_t ws_min, ws_max;
973 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
974 *min=(guint32)ws_min;
975 *max=(guint32)ws_max;
980 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
988 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
999 ret=SetProcessWorkingSetSize (process, ws_min, ws_max);
1005 ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig)
1007 MONO_ARCH_SAVE_REGS;
1009 /* sig == 1 -> Kill, sig == 2 -> CloseMainWindow */
1011 return TerminateProcess (process, -sig);