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/io-layer/io-layer.h>
26 HANDLE ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid)
32 /* GetCurrentProcess returns a pseudo-handle, so use
35 handle=OpenProcess (PROCESS_ALL_ACCESS, TRUE, pid);
38 /* FIXME: Throw an exception */
45 guint32 ves_icall_System_Diagnostics_Process_GetPid_internal (void)
49 return(GetCurrentProcessId ());
52 void ves_icall_System_Diagnostics_Process_Process_free_internal (MonoObject *this,
58 g_message (G_GNUC_PRETTY_FUNCTION ": Closing process %p, handle %p",
62 CloseHandle (process);
65 #define STASH_SYS_ASS(this) \
66 if(system_assembly == NULL) { \
67 system_assembly=this->vtable->klass->image; \
70 static MonoImage *system_assembly=NULL;
72 static guint32 unicode_chars (const gunichar2 *str)
84 static guint32 unicode_bytes (const gunichar2 *str)
90 /* Include the terminators */
97 static void process_set_field_object (MonoObject *obj, const guchar *fieldname,
100 MonoClassField *field;
103 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to object at %p",
107 field=mono_class_get_field_from_name (mono_object_class (obj),
109 *(MonoObject **)(((char *)obj) + field->offset)=data;
112 static void process_set_field_string (MonoObject *obj, const guchar *fieldname,
113 const gunichar2 *val, guint32 len)
115 MonoClassField *field;
119 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to [%s]",
120 fieldname, g_utf16_to_utf8 (val, len, NULL, NULL, NULL));
123 string=mono_string_new_utf16 (mono_object_domain (obj), val, len);
125 field=mono_class_get_field_from_name (mono_object_class (obj),
127 *(MonoString **)(((char *)obj) + field->offset)=string;
130 static void process_set_field_string_utf8 (MonoObject *obj,
131 const guchar *fieldname,
134 MonoClassField *field;
138 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to [%s]",
142 string=mono_string_new (mono_object_domain (obj), val);
144 field=mono_class_get_field_from_name (mono_object_class (obj),
146 *(MonoString **)(((char *)obj) + field->offset)=string;
149 static void process_set_field_int (MonoObject *obj, const guchar *fieldname,
152 MonoClassField *field;
155 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to %d",
159 field=mono_class_get_field_from_name (mono_object_class (obj),
161 *(guint32 *)(((char *)obj) + field->offset)=val;
164 static void process_set_field_bool (MonoObject *obj, const guchar *fieldname,
167 MonoClassField *field;
170 g_message (G_GNUC_PRETTY_FUNCTION ": Setting field %s to %s",
171 fieldname, val?"TRUE":"FALSE");
174 field=mono_class_get_field_from_name (mono_object_class (obj),
176 *(guint8 *)(((char *)obj) + field->offset)=val;
186 /* Returns a pointer to the value data, because theres no way to know
187 * how big that data is (value_len is set to zero for most blocks :-()
189 static gpointer process_get_versioninfo_block (gpointer data,
192 block->data_len=*(((guint16 *)data)++);
193 block->value_len=*(((guint16 *)data)++);
195 /* No idea what the type is supposed to indicate */
196 block->type=*(((guint16 *)data)++);
197 block->key=((gunichar2 *)data);
199 /* skip over the key (including the terminator) */
200 data=((gunichar2 *)data)+(unicode_chars (block->key)+1);
202 /* align on a 32-bit boundary */
203 data=(gpointer)(((unsigned)data+3) & (~3));
208 /* Returns a pointer to the byte following the Var block */
209 static gpointer process_read_var_block (MonoObject *filever, gpointer data_ptr,
212 /* Not currently interested in the VarFileInfo block. This
213 * might change if language support is needed for file version
214 * strings (VarFileInfo contains lists of supported
219 /* data_ptr is pointing at a Var block of length data_len */
220 data_ptr=process_get_versioninfo_block (data_ptr, &block);
221 data_ptr=((guchar *)data_ptr)+block.value_len;
226 /* Returns a pointer to the byte following the String block, or NULL
227 * if the data read hits padding. We can't recover from this because
228 * the data length does not include padding bytes, so it's not
229 * possible to just return the start position + length.
231 static gpointer process_read_string_block (MonoObject *filever,
237 guint16 string_len=0;
238 guchar comments_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
239 'm', '\0', 'e', '\0', 'n', '\0',
240 't', '\0', 's', '\0', '\0', '\0'};
241 guchar compname_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
242 'p', '\0', 'a', '\0', 'n', '\0',
243 'y', '\0', 'N', '\0', 'a', '\0',
244 'm', '\0', 'e', '\0', '\0', '\0'};
245 guchar filedesc_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
246 'e', '\0', 'D', '\0', 'e', '\0',
247 's', '\0', 'c', '\0', 'r', '\0',
248 'i', '\0', 'p', '\0', 't', '\0',
249 'i', '\0', 'o', '\0', 'n', '\0',
251 guchar filever_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
252 'e', '\0', 'V', '\0', 'e', '\0',
253 'r', '\0', 's', '\0', 'i', '\0',
254 'o', '\0', 'n', '\0', '\0', '\0'};
255 guchar internal_key[]= {'I', '\0', 'n', '\0', 't', '\0',
256 'e', '\0', 'r', '\0', 'n', '\0',
257 'a', '\0', 'l', '\0', 'N', '\0',
258 'a', '\0', 'm', '\0', 'e', '\0',
260 guchar legalcpy_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
261 'a', '\0', 'l', '\0', 'C', '\0',
262 'o', '\0', 'p', '\0', 'y', '\0',
263 'r', '\0', 'i', '\0', 'g', '\0',
264 'h', '\0', 't', '\0', '\0', '\0'};
265 guchar legaltrade_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
266 'a', '\0', 'l', '\0', 'T', '\0',
267 'r', '\0', 'a', '\0', 'd', '\0',
268 'e', '\0', 'm', '\0', 'a', '\0',
269 'r', '\0', 'k', '\0', 's', '\0',
271 guchar origfile_key[]= {'O', '\0', 'r', '\0', 'i', '\0',
272 'g', '\0', 'i', '\0', 'n', '\0',
273 'a', '\0', 'l', '\0', 'F', '\0',
274 'i', '\0', 'l', '\0', 'e', '\0',
275 'n', '\0', 'a', '\0', 'm', '\0',
276 'e', '\0', '\0', '\0'};
277 guchar privbuild_key[]= {'P', '\0', 'r', '\0', 'i', '\0',
278 'v', '\0', 'a', '\0', 't', '\0',
279 'e', '\0', 'B', '\0', 'u', '\0',
280 'i', '\0', 'l', '\0', 'd', '\0',
282 guchar prodname_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
283 'd', '\0', 'u', '\0', 'c', '\0',
284 't', '\0', 'N', '\0', 'a', '\0',
285 'm', '\0', 'e', '\0', '\0', '\0'};
286 guchar prodver_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
287 'd', '\0', 'u', '\0', 'c', '\0',
288 't', '\0', 'V', '\0', 'e', '\0',
289 'r', '\0', 's', '\0', 'i', '\0',
290 'o', '\0', 'n', '\0', '\0', '\0'};
291 guchar specbuild_key[]= {'S', '\0', 'p', '\0', 'e', '\0',
292 'c', '\0', 'i', '\0', 'a', '\0',
293 'l', '\0', 'B', '\0', 'u', '\0',
294 'i', '\0', 'l', '\0', 'd', '\0',
297 /* data_ptr is pointing at an array of one or more String
298 * blocks with total length (not including alignment padding)
301 while(string_len<data_len) {
304 /* align on a 32-bit boundary */
305 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
307 data_ptr=process_get_versioninfo_block (data_ptr, &block);
308 if(block.data_len==0) {
309 /* We must have hit padding, so give up
313 g_message (G_GNUC_PRETTY_FUNCTION
314 ": Hit 0-length block, giving up");
319 string_len=string_len+block.data_len;
320 value=(gunichar2 *)data_ptr;
321 /* Skip over the value */
322 data_ptr=((gunichar2 *)data_ptr)+block.value_len;
325 if(!memcmp (block.key, &comments_key,
326 unicode_bytes (block.key))) {
327 process_set_field_string (filever, "comments", value, unicode_chars (value));
328 } else if (!memcmp (block.key, &compname_key,
329 unicode_bytes (block.key))) {
330 process_set_field_string (filever, "companyname", value, unicode_chars (value));
331 } else if (!memcmp (block.key, &filedesc_key,
332 unicode_bytes (block.key))) {
333 process_set_field_string (filever, "filedescription", value, unicode_chars (value));
334 } else if (!memcmp (block.key, &filever_key,
335 unicode_bytes (block.key))) {
336 process_set_field_string (filever, "fileversion", value, unicode_chars (value));
337 } else if (!memcmp (block.key, &internal_key,
338 unicode_bytes (block.key))) {
339 process_set_field_string (filever, "internalname", value, unicode_chars (value));
340 } else if (!memcmp (block.key, &legalcpy_key,
341 unicode_bytes (block.key))) {
342 process_set_field_string (filever, "legalcopyright", value, unicode_chars (value));
343 } else if (!memcmp (block.key, &legaltrade_key,
344 unicode_bytes (block.key))) {
345 process_set_field_string (filever, "legaltrademarks", value, unicode_chars (value));
346 } else if (!memcmp (block.key, &origfile_key,
347 unicode_bytes (block.key))) {
348 process_set_field_string (filever, "originalfilename", value, unicode_chars (value));
349 } else if (!memcmp (block.key, &privbuild_key,
350 unicode_bytes (block.key))) {
351 process_set_field_string (filever, "privatebuild", value, unicode_chars (value));
352 } else if (!memcmp (block.key, &prodname_key,
353 unicode_bytes (block.key))) {
354 process_set_field_string (filever, "productname", value, unicode_chars (value));
355 } else if (!memcmp (block.key, &prodver_key,
356 unicode_bytes (block.key))) {
357 process_set_field_string (filever, "productversion", value, unicode_chars (value));
358 } else if (!memcmp (block.key, &specbuild_key,
359 unicode_bytes (block.key))) {
360 process_set_field_string (filever, "specialbuild", value, unicode_chars (value));
362 /* Not an error, just not interesting
372 /* returns a pointer to the byte following the Stringtable block, or
373 * NULL if the data read hits padding. We can't recover from this
374 * because the data length does not include padding bytes, so it's not
375 * possible to just return the start position + length
377 static gpointer process_read_stringtable_block (MonoObject *filever,
382 guint16 string_len=36; /* length of the StringFileInfo block */
384 /* Specifies language-neutral unicode string block */
385 guchar uni_key[]= {'0', '\0', '0', '\0', '0', '\0', '0', '\0',
386 '0', '\0', '4', '\0', 'b', '\0', '0', '\0',
389 guchar uni_key_uc[]= {'0', '\0', '0', '\0', '0', '\0', '0', '\0',
390 '0', '\0', '4', '\0', 'B', '\0', '0', '\0',
394 /* data_ptr is pointing at an array of StringTable blocks,
395 * with total length (not including alignment padding) of
399 while(string_len<data_len) {
400 /* align on a 32-bit boundary */
401 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
403 data_ptr=process_get_versioninfo_block (data_ptr, &block);
404 if(block.data_len==0) {
405 /* We must have hit padding, so give up
409 g_message (G_GNUC_PRETTY_FUNCTION
410 ": Hit 0-length block, giving up");
414 string_len=string_len+block.data_len;
416 if(!memcmp (block.key, &uni_key, unicode_bytes (block.key)) ||
417 !memcmp (block.key, &uni_key_uc, unicode_bytes (block.key))) {
418 /* Got the one we're interested in */
419 process_set_field_string_utf8 (filever, "language",
422 data_ptr=process_read_string_block (filever, data_ptr,
426 /* Some other language. We might want to do
427 * something with this in the future.
429 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_cli_rva_map (image->image_info,
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 if((ffi->dwSignature!=VS_FFI_SIGNATURE) ||
551 (ffi->dwStrucVersion!=VS_FFI_STRUCVERSION)) {
553 g_message (G_GNUC_PRETTY_FUNCTION
554 ": FIXEDFILEINFO bad signature");
558 process_read_fixedfileinfo_block (filever, ffi);
560 /* Subtract the 92 bytes we've already seen */
563 /* There now follow zero or one StringFileInfo blocks and zero
564 * or one VarFileInfo blocks
566 while(data_len > 0) {
567 /* align on a 32-bit boundary */
568 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
570 data_ptr=process_get_versioninfo_block (data_ptr, &block);
571 if(block.data_len==0) {
572 /* We must have hit padding, so give up
576 g_message (G_GNUC_PRETTY_FUNCTION
577 ": Hit 0-length block, giving up");
582 data_len=data_len-block.data_len;
584 if(!memcmp (block.key, &var_key, unicode_bytes (block.key))) {
585 data_ptr=process_read_var_block (filever, data_ptr,
587 } else if (!memcmp (block.key, &str_key,
588 unicode_bytes (block.key))) {
589 data_ptr=process_read_stringtable_block (filever, data_ptr, block.data_len);
593 g_message (G_GNUC_PRETTY_FUNCTION
594 ": Not a valid VERSIONINFO child block");
600 /* Child block hit padding */
602 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
609 static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
611 MonoClass *proc_class, *filever_class;
612 MonoObject *item, *filever;
613 MonoDomain *domain=mono_domain_get ();
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, ass->image);
638 process_set_field_string_utf8 (filever, "filename", ass->image->name);
639 process_set_field_string_utf8 (item, "filename", ass->image->name);
640 process_set_field_object (item, "version_info", filever);
642 modulename=g_path_get_basename (ass->image->name);
643 process_set_field_string_utf8 (item, "modulename", modulename);
646 g_ptr_array_add (modules, item);
649 static void process_scan_modules (gpointer data, gpointer user_data)
651 MonoAssembly *ass=data;
652 GPtrArray *modules=user_data;
654 /* The main assembly is already in the list */
655 if(mono_assembly_get_main () != ass) {
656 process_add_module (modules, ass);
661 /* Returns an array of System.Diagnostics.ProcessModule */
662 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this)
664 /* I was going to use toolhelp for this, but then realised I
665 * was being an idiot :)
667 * (Toolhelp would give shared libraries open by the runtime,
668 * as well as open assemblies. On windows my tests didnt find
669 * the assemblies loaded by mono either.)
671 GPtrArray *modules_list=g_ptr_array_new ();
677 STASH_SYS_ASS (this);
679 /* Make sure the first entry is the main module */
680 process_add_module (modules_list, mono_assembly_get_main ());
682 mono_assembly_foreach (process_scan_modules, modules_list);
684 /* Build a MonoArray out of modules_list */
685 arr=mono_array_new (mono_domain_get (), mono_defaults.object_class,
688 for(i=0; i<modules_list->len; i++) {
689 mono_array_set (arr, MonoObject *, i,
690 g_ptr_array_index (modules_list, i));
693 g_ptr_array_free (modules_list, FALSE);
698 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
701 guchar *filename_utf8;
705 STASH_SYS_ASS (this);
707 filename_utf8=mono_string_to_utf8 (filename);
708 image=mono_image_open (filename_utf8, NULL);
709 g_free (filename_utf8);
712 /* FIXME: an exception might be appropriate here */
714 g_message (G_GNUC_PRETTY_FUNCTION ": Failed to load image");
720 process_get_fileversion (this, image);
721 process_set_field_string_utf8 (this, "filename", image->name);
723 mono_image_close (image);
726 MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *cmd, MonoString *dirname, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info)
730 STARTUPINFO startinfo={0};
731 PROCESS_INFORMATION procinfo;
735 startinfo.cb=sizeof(STARTUPINFO);
736 startinfo.dwFlags=STARTF_USESTDHANDLES;
737 startinfo.hStdInput=stdin_handle;
738 startinfo.hStdOutput=stdout_handle;
739 startinfo.hStdError=stderr_handle;
741 /* The default dir name is "". Turn that into NULL to mean
742 * "current directory"
744 if(mono_string_length (dirname)==0) {
747 dir=mono_string_chars (dirname);
750 ret=CreateProcess (NULL, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, NULL, dir, &startinfo, &procinfo);
753 process_info->process_handle=procinfo.hProcess;
754 process_info->thread_handle=procinfo.hThread;
755 process_info->pid=procinfo.dwProcessId;
756 process_info->tid=procinfo.dwThreadId;
762 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
770 ret=WaitForSingleObject (process, INFINITE);
772 ret=WaitForSingleObject (process, ms);
775 if(ret==WAIT_OBJECT_0) {
782 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
786 FILETIME create_time, exit_time, kernel_time, user_time;
790 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
793 ticks=((guint64)exit_time.dwHighDateTime << 32) +
794 exit_time.dwLowDateTime;
802 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
806 FILETIME create_time, exit_time, kernel_time, user_time;
810 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
813 ticks=((guint64)create_time.dwHighDateTime << 32) +
814 create_time.dwLowDateTime;
822 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
828 GetExitCodeProcess (process, &code);
831 g_message (G_GNUC_PRETTY_FUNCTION ": process exit code is %d", code);
837 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
842 gunichar2 name[MAX_PATH];
848 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
853 len=GetModuleBaseName (process, mod, name, sizeof(name));
859 g_message (G_GNUC_PRETTY_FUNCTION ": process name is [%s]",
860 g_utf16_to_utf8 (name, -1, NULL, NULL, NULL));
863 string=mono_string_new_utf16 (mono_domain_get (), name, len);
868 /* Returns an array of pids */
869 MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
873 guint32 needed, count, i;
878 ret=EnumProcesses (pids, sizeof(pids), &needed);
880 /* FIXME: throw an exception */
884 count=needed/sizeof(guint32);
885 procs=mono_array_new (mono_domain_get (), mono_defaults.int_class,
887 for(i=0; i<count; i++) {
888 mono_array_set (procs, guint32, i, pids[i]);
894 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
900 ret=GetProcessWorkingSetSize (process, min, max);
905 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
913 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
924 ret=SetProcessWorkingSetSize (process, min, max);