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);
726 complete_path (const gunichar2 *appname, gunichar2 **completed)
731 utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
732 if (g_path_is_absolute (utf8app)) {
737 if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE)) {
742 found = g_find_program_in_path (utf8app);
749 *completed = g_utf8_to_utf16 (found, -1, NULL, NULL, NULL);
755 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)
759 STARTUPINFO startinfo={0};
760 PROCESS_INFORMATION procinfo;
761 gunichar2 *shell_path = NULL;
762 gchar *env_vars = NULL;
763 gboolean free_shell_path = TRUE;
767 startinfo.cb=sizeof(STARTUPINFO);
768 startinfo.dwFlags=STARTF_USESTDHANDLES;
769 startinfo.hStdInput=stdin_handle;
770 startinfo.hStdOutput=stdout_handle;
771 startinfo.hStdError=stderr_handle;
773 if (process_info->use_shell) {
775 const gchar *shell_args;
776 #ifdef PLATFORM_WIN32
777 spath = g_getenv ("COMSPEC");
778 shell_args = "/c %s";
780 spath = g_getenv ("SHELL");
781 shell_args = "-c %s";
788 shell_path = mono_unicode_from_external (spath, &dummy);
789 tmp = mono_string_to_utf8 (cmd);
790 quoted = g_shell_quote (tmp);
791 #ifdef PLATFORM_WIN32
801 newcmd = g_strdup_printf (shell_args, quoted);
804 cmd = mono_string_new (mono_domain_get (), newcmd);
808 shell_path = mono_string_chars (appname);
809 free_shell_path = complete_path (shell_path, &shell_path);
810 if (shell_path == NULL) {
811 process_info->pid = -ERROR_FILE_NOT_FOUND;
816 if (process_info->env_keys != NULL) {
819 MonoString *key, *value;
820 gunichar2 *str, *ptr;
823 for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
824 ms = mono_array_get (process_info->env_values, MonoString *, i);
828 len += mono_string_length (ms) * sizeof (gunichar2);
829 ms = mono_array_get (process_info->env_keys, MonoString *, i);
830 len += mono_string_length (ms) * sizeof (gunichar2);
831 len += 2 * sizeof (gunichar2);
834 equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
835 ptr = str = g_new0 (gunichar2, len + 1);
836 for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
837 value = mono_array_get (process_info->env_values, MonoString *, i);
841 key = mono_array_get (process_info->env_keys, MonoString *, i);
842 memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
843 ptr += mono_string_length (key);
845 memcpy (ptr, equals16, sizeof (gunichar2));
848 memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
849 ptr += mono_string_length (value);
854 env_vars = (gchar *) str;
857 /* The default dir name is "". Turn that into NULL to mean
858 * "current directory"
860 if(mono_string_length (dirname)==0) {
863 dir=mono_string_chars (dirname);
866 ret=CreateProcess (shell_path, mono_string_chars (cmd), NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, env_vars, dir, &startinfo, &procinfo);
873 process_info->process_handle=procinfo.hProcess;
874 process_info->thread_handle=procinfo.hThread;
875 process_info->pid=procinfo.dwProcessId;
876 process_info->tid=procinfo.dwThreadId;
878 process_info->pid = -GetLastError ();
884 MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObject *this, HANDLE process, gint32 ms)
892 ret=WaitForSingleObjectEx (process, INFINITE, TRUE);
894 ret=WaitForSingleObjectEx (process, ms, TRUE);
896 if(ret==WAIT_OBJECT_0) {
903 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
907 FILETIME create_time, exit_time, kernel_time, user_time;
911 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
914 ticks=((guint64)exit_time.dwHighDateTime << 32) +
915 exit_time.dwLowDateTime;
923 gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
927 FILETIME create_time, exit_time, kernel_time, user_time;
931 ret=GetProcessTimes (process, &create_time, &exit_time, &kernel_time,
934 ticks=((guint64)create_time.dwHighDateTime << 32) +
935 create_time.dwLowDateTime;
943 gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
949 GetExitCodeProcess (process, &code);
952 g_message (G_GNUC_PRETTY_FUNCTION ": process exit code is %d", code);
958 MonoString *ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
963 gunichar2 name[MAX_PATH];
969 ok=EnumProcessModules (process, &mod, sizeof(mod), &needed);
974 len=GetModuleBaseName (process, mod, name, sizeof(name));
980 g_message (G_GNUC_PRETTY_FUNCTION ": process name is [%s]",
981 g_utf16_to_utf8 (name, -1, NULL, NULL, NULL));
984 string=mono_string_new_utf16 (mono_domain_get (), name, len);
989 /* Returns an array of pids */
990 MonoArray *ves_icall_System_Diagnostics_Process_GetProcesses_internal (void)
994 guint32 needed, count, i;
999 ret=EnumProcesses (pids, sizeof(pids), &needed);
1001 /* FIXME: throw an exception */
1005 count=needed/sizeof(guint32);
1006 procs=mono_array_new (mono_domain_get (), mono_defaults.int_class,
1008 for(i=0; i<count; i++) {
1009 mono_array_set (procs, guint32, i, pids[i]);
1015 MonoBoolean ves_icall_System_Diagnostics_Process_GetWorkingSet_internal (HANDLE process, guint32 *min, guint32 *max)
1018 size_t ws_min, ws_max;
1020 MONO_ARCH_SAVE_REGS;
1022 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1023 *min=(guint32)ws_min;
1024 *max=(guint32)ws_max;
1029 MonoBoolean ves_icall_System_Diagnostics_Process_SetWorkingSet_internal (HANDLE process, guint32 min, guint32 max, MonoBoolean use_min)
1035 MONO_ARCH_SAVE_REGS;
1037 ret=GetProcessWorkingSetSize (process, &ws_min, &ws_max);
1048 ret=SetProcessWorkingSetSize (process, ws_min, ws_max);
1054 ves_icall_System_Diagnostics_Process_Kill_internal (HANDLE process, gint32 sig)
1056 MONO_ARCH_SAVE_REGS;
1058 /* sig == 1 -> Kill, sig == 2 -> CloseMainWindow */
1060 return TerminateProcess (process, -sig);