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))) {
330 process_set_field_string (filever, "comments", value, unicode_chars (value));
331 } else if (!memcmp (block.key, &compname_key,
332 unicode_bytes (block.key))) {
333 process_set_field_string (filever, "companyname", value, unicode_chars (value));
334 } else if (!memcmp (block.key, &filedesc_key,
335 unicode_bytes (block.key))) {
336 process_set_field_string (filever, "filedescription", value, unicode_chars (value));
337 } else if (!memcmp (block.key, &filever_key,
338 unicode_bytes (block.key))) {
339 process_set_field_string (filever, "fileversion", value, unicode_chars (value));
340 } else if (!memcmp (block.key, &internal_key,
341 unicode_bytes (block.key))) {
342 process_set_field_string (filever, "internalname", value, unicode_chars (value));
343 } else if (!memcmp (block.key, &legalcpy_key,
344 unicode_bytes (block.key))) {
345 process_set_field_string (filever, "legalcopyright", value, unicode_chars (value));
346 } else if (!memcmp (block.key, &legaltrade_key,
347 unicode_bytes (block.key))) {
348 process_set_field_string (filever, "legaltrademarks", value, unicode_chars (value));
349 } else if (!memcmp (block.key, &origfile_key,
350 unicode_bytes (block.key))) {
351 process_set_field_string (filever, "originalfilename", value, unicode_chars (value));
352 } else if (!memcmp (block.key, &privbuild_key,
353 unicode_bytes (block.key))) {
354 process_set_field_string (filever, "privatebuild", value, unicode_chars (value));
355 } else if (!memcmp (block.key, &prodname_key,
356 unicode_bytes (block.key))) {
357 process_set_field_string (filever, "productname", value, unicode_chars (value));
358 } else if (!memcmp (block.key, &prodver_key,
359 unicode_bytes (block.key))) {
360 process_set_field_string (filever, "productversion", value, unicode_chars (value));
361 } else if (!memcmp (block.key, &specbuild_key,
362 unicode_bytes (block.key))) {
363 process_set_field_string (filever, "specialbuild", value, unicode_chars (value));
365 /* Not an error, just not interesting
375 /* returns a pointer to the byte following the Stringtable block, or
376 * NULL if the data read hits padding. We can't recover from this
377 * because the data length does not include padding bytes, so it's not
378 * possible to just return the start position + length
380 static gpointer process_read_stringtable_block (MonoObject *filever,
385 guint16 string_len=36; /* length of the StringFileInfo block */
387 /* Specifies language-neutral unicode string block */
388 guchar uni_key[]= {'0', '\0', '0', '\0', '0', '\0', '0', '\0',
389 '0', '\0', '4', '\0', 'b', '\0', '0', '\0',
392 guchar uni_key_uc[]= {'0', '\0', '0', '\0', '0', '\0', '0', '\0',
393 '0', '\0', '4', '\0', 'B', '\0', '0', '\0',
397 /* data_ptr is pointing at an array of StringTable blocks,
398 * with total length (not including alignment padding) of
402 while(string_len<data_len) {
403 /* align on a 32-bit boundary */
404 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
406 data_ptr=process_get_versioninfo_block (data_ptr, &block);
407 if(block.data_len==0) {
408 /* We must have hit padding, so give up
412 g_message (G_GNUC_PRETTY_FUNCTION
413 ": Hit 0-length block, giving up");
417 string_len=string_len+block.data_len;
419 if(!memcmp (block.key, &uni_key, unicode_bytes (block.key)) ||
420 !memcmp (block.key, &uni_key_uc, unicode_bytes (block.key))) {
421 /* Got the one we're interested in */
422 process_set_field_string_utf8 (filever, "language",
425 data_ptr=process_read_string_block (filever, data_ptr,
429 /* Some other language. We might want to do
430 * something with this in the future.
432 data_ptr=process_read_string_block (filever, data_ptr,
438 /* Child block hit padding */
440 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
449 static void process_read_fixedfileinfo_block (MonoObject *filever,
450 VS_FIXEDFILEINFO *ffi)
453 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);
456 process_set_field_int (filever, "filemajorpart",
457 HIWORD (ffi->dwFileVersionMS));
458 process_set_field_int (filever, "fileminorpart",
459 LOWORD (ffi->dwFileVersionMS));
460 process_set_field_int (filever, "filebuildpart",
461 HIWORD (ffi->dwFileVersionLS));
462 process_set_field_int (filever, "fileprivatepart",
463 LOWORD (ffi->dwFileVersionLS));
465 process_set_field_int (filever, "productmajorpart",
466 HIWORD (ffi->dwProductVersionMS));
467 process_set_field_int (filever, "productminorpart",
468 LOWORD (ffi->dwProductVersionMS));
469 process_set_field_int (filever, "productbuildpart",
470 HIWORD (ffi->dwProductVersionLS));
471 process_set_field_int (filever, "productprivatepart",
472 LOWORD (ffi->dwProductVersionLS));
474 process_set_field_bool (filever, "isdebug",
475 ffi->dwFileFlags&VS_FF_DEBUG);
476 process_set_field_bool (filever, "isprerelease",
477 ffi->dwFileFlags&VS_FF_PRERELEASE);
478 process_set_field_bool (filever, "ispatched",
479 ffi->dwFileFlags&VS_FF_PATCHED);
480 process_set_field_bool (filever, "isprivatebuild",
481 ffi->dwFileFlags&VS_FF_PRIVATEBUILD);
482 process_set_field_bool (filever, "isspecialbuild",
483 ffi->dwFileFlags&VS_FF_SPECIALBUILD);
486 static void process_get_fileversion (MonoObject *filever, MonoImage *image)
488 MonoPEResourceDataEntry *version_info;
490 VS_FIXEDFILEINFO *ffi;
493 gint32 data_len; /* signed to guard against underflow */
494 guchar vs_key[]= {'V', '\0', 'S', '\0', '_', '\0', 'V', '\0',
495 'E', '\0', 'R', '\0', 'S', '\0', 'I', '\0',
496 'O', '\0', 'N', '\0', '_', '\0', 'I', '\0',
497 'N', '\0', 'F', '\0', 'O', '\0', '\0', '\0'
499 guchar var_key[]= {'V', '\0', 'a', '\0', 'r', '\0', 'F', '\0',
500 'i', '\0', 'l', '\0', 'e', '\0', 'I', '\0',
501 'n', '\0', 'f', '\0', 'o', '\0', '\0', '\0',
503 guchar str_key[]= {'S', '\0', 't', '\0', 'r', '\0', 'i', '\0',
504 'n', '\0', 'g', '\0', 'F', '\0', 'i', '\0',
505 'l', '\0', 'e', '\0', 'I', '\0', 'n', '\0',
506 'f', '\0', 'o', '\0', '\0', '\0',
509 version_info=mono_image_lookup_resource (image,
510 MONO_PE_RESOURCE_ID_VERSION,
513 g_message (G_GNUC_PRETTY_FUNCTION ": image_lookup returned %p",
517 if(version_info==NULL) {
521 data=mono_cli_rva_map (image->image_info,
522 version_info->rde_data_offset);
527 /* See io-layer/versioninfo.h for the gory details on how this
528 * data is laid out. (data should be pointing to
529 * VS_VERSIONINFO data).
532 data_ptr=process_get_versioninfo_block (data, &block);
534 data_len=block.data_len;
536 if(block.value_len!=sizeof(VS_FIXEDFILEINFO)) {
538 g_message (G_GNUC_PRETTY_FUNCTION
539 ": FIXEDFILEINFO size mismatch");
544 if(memcmp (block.key, &vs_key, unicode_bytes (block.key))) {
546 g_message (G_GNUC_PRETTY_FUNCTION
547 ": VS_VERSION_INFO mismatch");
552 ffi=((VS_FIXEDFILEINFO *)data_ptr);
553 data_ptr = (char *)data_ptr + sizeof(VS_FIXEDFILEINFO);
554 if((ffi->dwSignature!=VS_FFI_SIGNATURE) ||
555 (ffi->dwStrucVersion!=VS_FFI_STRUCVERSION)) {
557 g_message (G_GNUC_PRETTY_FUNCTION
558 ": FIXEDFILEINFO bad signature");
562 process_read_fixedfileinfo_block (filever, ffi);
564 /* Subtract the 92 bytes we've already seen */
567 /* There now follow zero or one StringFileInfo blocks and zero
568 * or one VarFileInfo blocks
570 while(data_len > 0) {
571 /* align on a 32-bit boundary */
572 data_ptr=(gpointer)(((unsigned)data_ptr+3) & (~3));
574 data_ptr=process_get_versioninfo_block (data_ptr, &block);
575 if(block.data_len==0) {
576 /* We must have hit padding, so give up
580 g_message (G_GNUC_PRETTY_FUNCTION
581 ": Hit 0-length block, giving up");
586 data_len=data_len-block.data_len;
588 if(!memcmp (block.key, &var_key, unicode_bytes (block.key))) {
589 data_ptr=process_read_var_block (filever, data_ptr,
591 } else if (!memcmp (block.key, &str_key,
592 unicode_bytes (block.key))) {
593 data_ptr=process_read_stringtable_block (filever, data_ptr, block.data_len);
597 g_message (G_GNUC_PRETTY_FUNCTION
598 ": Not a valid VERSIONINFO child block");
604 /* Child block hit padding */
606 g_message (G_GNUC_PRETTY_FUNCTION ": Child block hit 0-length block, giving up");
613 static void process_add_module (GPtrArray *modules, MonoAssembly *ass)
615 MonoClass *proc_class, *filever_class;
616 MonoObject *item, *filever;
617 MonoDomain *domain=mono_domain_get ();
620 /* Build a System.Diagnostics.ProcessModule with the data.
621 * Leave BaseAddress and EntryPointAddress set to NULL,
622 * FileName is ass->image->name, FileVersionInfo is an object
623 * constructed from the PE image data referenced by
624 * ass->image, ModuleMemorySize set to 0, ModuleName the last
625 * component of FileName.
627 proc_class=mono_class_from_name (system_assembly, "System.Diagnostics",
629 item=mono_object_new (domain, proc_class);
631 filever_class=mono_class_from_name (system_assembly,
632 "System.Diagnostics",
634 filever=mono_object_new (domain, filever_class);
637 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);
640 process_get_fileversion (filever, ass->image);
642 process_set_field_string_utf8 (filever, "filename", ass->image->name);
643 process_set_field_string_utf8 (item, "filename", ass->image->name);
644 process_set_field_object (item, "version_info", filever);
646 modulename=g_path_get_basename (ass->image->name);
647 process_set_field_string_utf8 (item, "modulename", modulename);
650 g_ptr_array_add (modules, item);
653 static void process_scan_modules (gpointer data, gpointer user_data)
655 MonoAssembly *ass=data;
656 GPtrArray *modules=user_data;
658 /* The main assembly is already in the list */
659 if(mono_assembly_get_main () != ass) {
660 process_add_module (modules, ass);
665 /* Returns an array of System.Diagnostics.ProcessModule */
666 MonoArray *ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this)
668 /* I was going to use toolhelp for this, but then realised I
669 * was being an idiot :)
671 * (Toolhelp would give shared libraries open by the runtime,
672 * as well as open assemblies. On windows my tests didnt find
673 * the assemblies loaded by mono either.)
675 GPtrArray *modules_list=g_ptr_array_new ();
681 STASH_SYS_ASS (this);
683 /* Make sure the first entry is the main module */
684 process_add_module (modules_list, mono_assembly_get_main ());
686 mono_assembly_foreach (process_scan_modules, modules_list);
688 /* Build a MonoArray out of modules_list */
689 arr=mono_array_new (mono_domain_get (), mono_defaults.object_class,
692 for(i=0; i<modules_list->len; i++) {
693 mono_array_set (arr, MonoObject *, i,
694 g_ptr_array_index (modules_list, i));
697 g_ptr_array_free (modules_list, FALSE);
702 void ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this, MonoString *filename)
705 guchar *filename_utf8;
709 STASH_SYS_ASS (this);
711 filename_utf8=mono_string_to_utf8 (filename);
712 image=mono_image_open (filename_utf8, NULL);
713 g_free (filename_utf8);
716 /* FIXME: an exception might be appropriate here */
718 g_message (G_GNUC_PRETTY_FUNCTION ": Failed to load image");
724 process_get_fileversion (this, image);
725 process_set_field_string_utf8 (this, "filename", image->name);
727 mono_image_close (image);
730 MonoBoolean ves_icall_System_Diagnostics_Process_Start_internal (MonoString *cmd, MonoString *dirname, HANDLE stdin_handle, HANDLE stdout_handle, HANDLE stderr_handle, MonoProcInfo *process_info)
734 STARTUPINFO startinfo={0};
735 PROCESS_INFORMATION procinfo;
739 startinfo.cb=sizeof(STARTUPINFO);
740 startinfo.dwFlags=STARTF_USESTDHANDLES;
741 startinfo.hStdInput=stdin_handle;
742 startinfo.hStdOutput=stdout_handle;
743 startinfo.hStdError=stderr_handle;
745 /* The default dir name is "". Turn that into NULL to mean
746 * "current directory"
748 if(mono_string_length (dirname)==0) {
751 dir=mono_string_chars (dirname);
754 ret=CreateProcess (NULL, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, NULL, dir, &startinfo, &procinfo);
757 process_info->process_handle=procinfo.hProcess;
758 process_info->thread_handle=procinfo.hThread;
759 process_info->pid=procinfo.dwProcessId;
760 process_info->tid=procinfo.dwThreadId;
766 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
774 ret=WaitForSingleObject (process, INFINITE);
776 ret=WaitForSingleObject (process, ms);
779 if(ret==WAIT_OBJECT_0) {
786 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
790 FILETIME create_time, exit_time, kernel_time, user_time;
794 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
797 ticks=((guint64)exit_time.dwHighDateTime << 32) +
798 exit_time.dwLowDateTime;
806 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
810 FILETIME create_time, exit_time, kernel_time, user_time;
814 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
817 ticks=((guint64)create_time.dwHighDateTime << 32) +
818 create_time.dwLowDateTime;
826 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
832 GetExitCodeProcess (process, &code);
835 g_message (G_GNUC_PRETTY_FUNCTION ": process exit code is %d", code);
841 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
846 gunichar2 name[MAX_PATH];
852 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
857 len=GetModuleBaseName (process, mod, name, sizeof(name));
863 g_message (G_GNUC_PRETTY_FUNCTION ": process name is [%s]",
864 g_utf16_to_utf8 (name, -1, NULL, NULL, NULL));
867 string=mono_string_new_utf16 (mono_domain_get (), name, len);
872 /* Returns an array of pids */
873 MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
877 guint32 needed, count, i;
882 ret=EnumProcesses (pids, sizeof(pids), &needed);
884 /* FIXME: throw an exception */
888 count=needed/sizeof(guint32);
889 procs=mono_array_new (mono_domain_get (), mono_defaults.int_class,
891 for(i=0; i<count; i++) {
892 mono_array_set (procs, guint32, i, pids[i]);
898 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
904 ret=GetProcessWorkingSetSize (process, min, max);
909 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
917 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
928 ret=SetProcessWorkingSetSize (process, min, max);