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 data = (char *)data + sizeof(guint16);
194 block->value_len=*((guint16 *)data);
195 data = (char *)data + sizeof(guint16);
197 /* No idea what the type is supposed to indicate */
198 block->type=*((guint16 *)data);
199 data = (char *)data + sizeof(guint16);
200 block->key=((gunichar2 *)data);
202 /* skip over the key (including the terminator) */
203 data=((gunichar2 *)data)+(unicode_chars (block->key)+1);
205 /* align on a 32-bit boundary */
206 data=(gpointer)(((unsigned)data+3) & (~3));
211 /* Returns a pointer to the byte following the Var block */
212 static gpointer process_read_var_block (MonoObject *filever, gpointer data_ptr,
215 /* Not currently interested in the VarFileInfo block. This
216 * might change if language support is needed for file version
217 * strings (VarFileInfo contains lists of supported
222 /* data_ptr is pointing at a Var block of length data_len */
223 data_ptr=process_get_versioninfo_block (data_ptr, &block);
224 data_ptr=((guchar *)data_ptr)+block.value_len;
229 /* Returns a pointer to the byte following the String block, or NULL
230 * if the data read hits padding. We can't recover from this because
231 * the data length does not include padding bytes, so it's not
232 * possible to just return the start position + length.
234 static gpointer process_read_string_block (MonoObject *filever,
240 guint16 string_len=0;
241 guchar comments_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
242 'm', '\0', 'e', '\0', 'n', '\0',
243 't', '\0', 's', '\0', '\0', '\0'};
244 guchar compname_key[]= {'C', '\0', 'o', '\0', 'm', '\0',
245 'p', '\0', 'a', '\0', 'n', '\0',
246 'y', '\0', 'N', '\0', 'a', '\0',
247 'm', '\0', 'e', '\0', '\0', '\0'};
248 guchar filedesc_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
249 'e', '\0', 'D', '\0', 'e', '\0',
250 's', '\0', 'c', '\0', 'r', '\0',
251 'i', '\0', 'p', '\0', 't', '\0',
252 'i', '\0', 'o', '\0', 'n', '\0',
254 guchar filever_key[]= {'F', '\0', 'i', '\0', 'l', '\0',
255 'e', '\0', 'V', '\0', 'e', '\0',
256 'r', '\0', 's', '\0', 'i', '\0',
257 'o', '\0', 'n', '\0', '\0', '\0'};
258 guchar internal_key[]= {'I', '\0', 'n', '\0', 't', '\0',
259 'e', '\0', 'r', '\0', 'n', '\0',
260 'a', '\0', 'l', '\0', 'N', '\0',
261 'a', '\0', 'm', '\0', 'e', '\0',
263 guchar legalcpy_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
264 'a', '\0', 'l', '\0', 'C', '\0',
265 'o', '\0', 'p', '\0', 'y', '\0',
266 'r', '\0', 'i', '\0', 'g', '\0',
267 'h', '\0', 't', '\0', '\0', '\0'};
268 guchar legaltrade_key[]= {'L', '\0', 'e', '\0', 'g', '\0',
269 'a', '\0', 'l', '\0', 'T', '\0',
270 'r', '\0', 'a', '\0', 'd', '\0',
271 'e', '\0', 'm', '\0', 'a', '\0',
272 'r', '\0', 'k', '\0', 's', '\0',
274 guchar origfile_key[]= {'O', '\0', 'r', '\0', 'i', '\0',
275 'g', '\0', 'i', '\0', 'n', '\0',
276 'a', '\0', 'l', '\0', 'F', '\0',
277 'i', '\0', 'l', '\0', 'e', '\0',
278 'n', '\0', 'a', '\0', 'm', '\0',
279 'e', '\0', '\0', '\0'};
280 guchar privbuild_key[]= {'P', '\0', 'r', '\0', 'i', '\0',
281 'v', '\0', 'a', '\0', 't', '\0',
282 'e', '\0', 'B', '\0', 'u', '\0',
283 'i', '\0', 'l', '\0', 'd', '\0',
285 guchar prodname_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
286 'd', '\0', 'u', '\0', 'c', '\0',
287 't', '\0', 'N', '\0', 'a', '\0',
288 'm', '\0', 'e', '\0', '\0', '\0'};
289 guchar prodver_key[]= {'P', '\0', 'r', '\0', 'o', '\0',
290 'd', '\0', 'u', '\0', 'c', '\0',
291 't', '\0', 'V', '\0', 'e', '\0',
292 'r', '\0', 's', '\0', 'i', '\0',
293 'o', '\0', 'n', '\0', '\0', '\0'};
294 guchar specbuild_key[]= {'S', '\0', 'p', '\0', 'e', '\0',
295 'c', '\0', 'i', '\0', 'a', '\0',
296 'l', '\0', 'B', '\0', 'u', '\0',
297 'i', '\0', 'l', '\0', 'd', '\0',
300 /* data_ptr is pointing at an array of one or more String
301 * blocks with total length (not including alignment padding)
304 while(string_len<data_len) {
307 /* align on a 32-bit boundary */
308 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
310 data_ptr=process_get_versioninfo_block (data_ptr, &block);
311 if(block.data_len==0) {
312 /* We must have hit padding, so give up
316 g_message (G_GNUC_PRETTY_FUNCTION
317 ": Hit 0-length block, giving up");
322 string_len=string_len+block.data_len;
323 value=(gunichar2 *)data_ptr;
324 /* Skip over the value */
325 data_ptr=((gunichar2 *)data_ptr)+block.value_len;
328 if(!memcmp (block.key, &comments_key,
329 unicode_bytes (block.key))) {
331 process_set_field_string (filever, "comments", value, unicode_chars (value));
332 } else if (!memcmp (block.key, &compname_key,
333 unicode_bytes (block.key))) {
334 process_set_field_string (filever, "companyname", value, unicode_chars (value));
335 } else if (!memcmp (block.key, &filedesc_key,
336 unicode_bytes (block.key))) {
337 process_set_field_string (filever, "filedescription", value, unicode_chars (value));
338 } else if (!memcmp (block.key, &filever_key,
339 unicode_bytes (block.key))) {
340 process_set_field_string (filever, "fileversion", value, unicode_chars (value));
341 } else if (!memcmp (block.key, &internal_key,
342 unicode_bytes (block.key))) {
343 process_set_field_string (filever, "internalname", value, unicode_chars (value));
344 } else if (!memcmp (block.key, &legalcpy_key,
345 unicode_bytes (block.key))) {
346 process_set_field_string (filever, "legalcopyright", value, unicode_chars (value));
347 } else if (!memcmp (block.key, &legaltrade_key,
348 unicode_bytes (block.key))) {
349 process_set_field_string (filever, "legaltrademarks", value, unicode_chars (value));
350 } else if (!memcmp (block.key, &origfile_key,
351 unicode_bytes (block.key))) {
352 process_set_field_string (filever, "originalfilename", value, unicode_chars (value));
353 } else if (!memcmp (block.key, &privbuild_key,
354 unicode_bytes (block.key))) {
355 process_set_field_string (filever, "privatebuild", value, unicode_chars (value));
356 } else if (!memcmp (block.key, &prodname_key,
357 unicode_bytes (block.key))) {
358 process_set_field_string (filever, "productname", value, unicode_chars (value));
359 } else if (!memcmp (block.key, &prodver_key,
360 unicode_bytes (block.key))) {
361 process_set_field_string (filever, "productversion", value, unicode_chars (value));
362 } else if (!memcmp (block.key, &specbuild_key,
363 unicode_bytes (block.key))) {
364 process_set_field_string (filever, "specialbuild", value, unicode_chars (value));
366 /* Not an error, just not interesting
376 /* returns a pointer to the byte following the Stringtable block, or
377 * NULL if the data read hits padding. We can't recover from this
378 * because the data length does not include padding bytes, so it's not
379 * possible to just return the start position + length
381 static gpointer process_read_stringtable_block (MonoObject *filever,
386 const char *language;
387 guint16 string_len=36; /* length of the StringFileInfo block */
389 /* data_ptr is pointing at an array of StringTable blocks,
390 * with total length (not including alignment padding) of
394 while(string_len<data_len) {
395 /* align on a 32-bit boundary */
396 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
398 data_ptr=process_get_versioninfo_block (data_ptr, &block);
399 if(block.data_len==0) {
400 /* We must have hit padding, so give up
404 g_message (G_GNUC_PRETTY_FUNCTION
405 ": Hit 0-length block, giving up");
409 string_len=string_len+block.data_len;
411 language = g_utf16_to_utf8 (block.key, unicode_bytes (block.key), NULL, NULL, NULL);
412 g_strdown (language);
413 if (!strcmp (language, "007f04b0") || !strcmp (language, "000004b0")) {
414 /* Got the one we're interested in */
415 process_set_field_string_utf8 (filever, "language",
418 data_ptr=process_read_string_block (filever, data_ptr,
422 /* Some other language. We might want to do
423 * something with this in the future.
425 data_ptr=process_read_string_block (filever, data_ptr,
432 /* Child block hit padding */
434 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
443 static void process_read_fixedfileinfo_block (MonoObject *filever,
444 VS_FIXEDFILEINFO *ffi)
447 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);
450 process_set_field_int (filever, "filemajorpart",
451 HIWORD (ffi->dwFileVersionMS));
452 process_set_field_int (filever, "fileminorpart",
453 LOWORD (ffi->dwFileVersionMS));
454 process_set_field_int (filever, "filebuildpart",
455 HIWORD (ffi->dwFileVersionLS));
456 process_set_field_int (filever, "fileprivatepart",
457 LOWORD (ffi->dwFileVersionLS));
459 process_set_field_int (filever, "productmajorpart",
460 HIWORD (ffi->dwProductVersionMS));
461 process_set_field_int (filever, "productminorpart",
462 LOWORD (ffi->dwProductVersionMS));
463 process_set_field_int (filever, "productbuildpart",
464 HIWORD (ffi->dwProductVersionLS));
465 process_set_field_int (filever, "productprivatepart",
466 LOWORD (ffi->dwProductVersionLS));
468 process_set_field_bool (filever, "isdebug",
469 ffi->dwFileFlags&VS_FF_DEBUG);
470 process_set_field_bool (filever, "isprerelease",
471 ffi->dwFileFlags&VS_FF_PRERELEASE);
472 process_set_field_bool (filever, "ispatched",
473 ffi->dwFileFlags&VS_FF_PATCHED);
474 process_set_field_bool (filever, "isprivatebuild",
475 ffi->dwFileFlags&VS_FF_PRIVATEBUILD);
476 process_set_field_bool (filever, "isspecialbuild",
477 ffi->dwFileFlags&VS_FF_SPECIALBUILD);
480 static void process_get_fileversion (MonoObject *filever, MonoImage *image)
482 MonoPEResourceDataEntry *version_info;
484 VS_FIXEDFILEINFO *ffi;
487 gint32 data_len; /* signed to guard against underflow */
488 guchar vs_key[]= {'V', '\0', 'S', '\0', '_', '\0', 'V', '\0',
489 'E', '\0', 'R', '\0', 'S', '\0', 'I', '\0',
490 'O', '\0', 'N', '\0', '_', '\0', 'I', '\0',
491 'N', '\0', 'F', '\0', 'O', '\0', '\0', '\0'
493 guchar var_key[]= {'V', '\0', 'a', '\0', 'r', '\0', 'F', '\0',
494 'i', '\0', 'l', '\0', 'e', '\0', 'I', '\0',
495 'n', '\0', 'f', '\0', 'o', '\0', '\0', '\0',
497 guchar str_key[]= {'S', '\0', 't', '\0', 'r', '\0', 'i', '\0',
498 'n', '\0', 'g', '\0', 'F', '\0', 'i', '\0',
499 'l', '\0', 'e', '\0', 'I', '\0', 'n', '\0',
500 'f', '\0', 'o', '\0', '\0', '\0',
503 version_info=mono_image_lookup_resource (image,
504 MONO_PE_RESOURCE_ID_VERSION,
507 g_message (G_GNUC_PRETTY_FUNCTION ": image_lookup returned %p",
511 if(version_info==NULL) {
515 data=mono_cli_rva_map (image->image_info,
516 version_info->rde_data_offset);
521 /* See io-layer/versioninfo.h for the gory details on how this
522 * data is laid out. (data should be pointing to
523 * VS_VERSIONINFO data).
526 data_ptr=process_get_versioninfo_block (data, &block);
528 data_len=block.data_len;
530 if(block.value_len!=sizeof(VS_FIXEDFILEINFO)) {
532 g_message (G_GNUC_PRETTY_FUNCTION
533 ": FIXEDFILEINFO size mismatch");
538 if(memcmp (block.key, &vs_key, unicode_bytes (block.key))) {
540 g_message (G_GNUC_PRETTY_FUNCTION
541 ": VS_VERSION_INFO mismatch");
546 ffi=((VS_FIXEDFILEINFO *)data_ptr);
547 data_ptr = (char *)data_ptr + sizeof(VS_FIXEDFILEINFO);
548 if((ffi->dwSignature!=VS_FFI_SIGNATURE) ||
549 (ffi->dwStrucVersion!=VS_FFI_STRUCVERSION)) {
551 g_message (G_GNUC_PRETTY_FUNCTION
552 ": FIXEDFILEINFO bad signature");
556 process_read_fixedfileinfo_block (filever, ffi);
558 /* Subtract the 92 bytes we've already seen */
561 /* There now follow zero or one StringFileInfo blocks and zero
562 * or one VarFileInfo blocks
564 while(data_len > 0) {
565 /* align on a 32-bit boundary */
566 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
568 data_ptr=process_get_versioninfo_block (data_ptr, &block);
569 if(block.data_len==0) {
570 /* We must have hit padding, so give up
574 g_message (G_GNUC_PRETTY_FUNCTION
575 ": Hit 0-length block, giving up");
580 data_len=data_len-block.data_len;
582 if(!memcmp (block.key, &var_key, unicode_bytes (block.key))) {
583 data_ptr=process_read_var_block (filever, data_ptr,
585 } else if (!memcmp (block.key, &str_key,
586 unicode_bytes (block.key))) {
587 data_ptr=process_read_stringtable_block (filever, data_ptr, block.data_len);
591 g_message (G_GNUC_PRETTY_FUNCTION
592 ": Not a valid VERSIONINFO child block");
598 /* Child block hit padding */
600 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
607 static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
609 MonoClass *proc_class, *filever_class;
610 MonoObject *item, *filever;
611 MonoDomain *domain=mono_domain_get ();
614 /* Build a System.Diagnostics.ProcessModule with the data.
615 * Leave BaseAddress and EntryPointAddress set to NULL,
616 * FileName is ass->image->name, FileVersionInfo is an object
617 * constructed from the PE image data referenced by
618 * ass->image, ModuleMemorySize set to 0, ModuleName the last
619 * component of FileName.
621 proc_class=mono_class_from_name (system_assembly, "System.Diagnostics",
623 item=mono_object_new (domain, proc_class);
625 filever_class=mono_class_from_name (system_assembly,
626 "System.Diagnostics",
628 filever=mono_object_new (domain, filever_class);
631 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);
634 process_get_fileversion (filever, ass->image);
636 process_set_field_string_utf8 (filever, "filename", ass->image->name);
637 process_set_field_string_utf8 (item, "filename", ass->image->name);
638 process_set_field_object (item, "version_info", filever);
640 modulename=g_path_get_basename (ass->image->name);
641 process_set_field_string_utf8 (item, "modulename", modulename);
644 g_ptr_array_add (modules, item);
647 static void process_scan_modules (gpointer data, gpointer user_data)
649 MonoAssembly *ass=data;
650 GPtrArray *modules=user_data;
652 /* The main assembly is already in the list */
653 if(mono_assembly_get_main () != ass) {
654 process_add_module (modules, ass);
659 /* Returns an array of System.Diagnostics.ProcessModule */
660 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this)
662 /* I was going to use toolhelp for this, but then realised I
663 * was being an idiot :)
665 * (Toolhelp would give shared libraries open by the runtime,
666 * as well as open assemblies. On windows my tests didnt find
667 * the assemblies loaded by mono either.)
669 GPtrArray *modules_list=g_ptr_array_new ();
675 STASH_SYS_ASS (this);
677 /* Make sure the first entry is the main module */
678 process_add_module (modules_list, mono_assembly_get_main ());
680 mono_assembly_foreach (process_scan_modules, modules_list);
682 /* Build a MonoArray out of modules_list */
683 arr=mono_array_new (mono_domain_get (), mono_defaults.object_class,
686 for(i=0; i<modules_list->len; i++) {
687 mono_array_set (arr, MonoObject *, i,
688 g_ptr_array_index (modules_list, i));
691 g_ptr_array_free (modules_list, FALSE);
696 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
699 guchar *filename_utf8;
703 STASH_SYS_ASS (this);
705 filename_utf8=mono_string_to_utf8 (filename);
706 image=mono_image_open (filename_utf8, NULL);
707 g_free (filename_utf8);
710 /* FIXME: an exception might be appropriate here */
712 g_message (G_GNUC_PRETTY_FUNCTION ": Failed to load image");
718 process_get_fileversion (this, image);
719 process_set_field_string_utf8 (this, "filename", image->name);
721 mono_image_close (image);
724 MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *cmd, MonoString *dirname, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info)
728 STARTUPINFO startinfo={0};
729 PROCESS_INFORMATION procinfo;
733 startinfo.cb=sizeof(STARTUPINFO);
734 startinfo.dwFlags=STARTF_USESTDHANDLES;
735 startinfo.hStdInput=stdin_handle;
736 startinfo.hStdOutput=stdout_handle;
737 startinfo.hStdError=stderr_handle;
739 /* The default dir name is "". Turn that into NULL to mean
740 * "current directory"
742 if(mono_string_length (dirname)==0) {
745 dir=mono_string_chars (dirname);
748 ret=CreateProcess (NULL, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, NULL, dir, &startinfo, &procinfo);
751 process_info->process_handle=procinfo.hProcess;
752 process_info->thread_handle=procinfo.hThread;
753 process_info->pid=procinfo.dwProcessId;
754 process_info->tid=procinfo.dwThreadId;
756 process_info->pid = -GetLastError ();
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)
897 size_t ws_min, ws_max;
901 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
902 *min=(guint32)ws_min;
903 *max=(guint32)ws_max;
908 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
916 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
927 ret=SetProcessWorkingSetSize (process, ws_min, ws_max);