7 #include "w32process.h"
8 #include "w32process-internals.h"
9 #include "w32process-win32-internals.h"
12 #include "object-internals.h"
14 #include "class-internals.h"
16 #include "utils/mono-proclib.h"
17 #include "utils/w32api.h"
20 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
22 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32)
25 mono_w32process_get_pid (gpointer handle
)
27 return GetProcessId (handle
);
31 mono_w32process_try_get_modules (gpointer process
, gpointer
*modules
, guint32 size
, guint32
*needed
)
33 return EnumProcessModules (process
, (HMODULE
*) modules
, size
, (LPDWORD
) needed
);
37 mono_w32process_module_get_name (gpointer process
, gpointer module
, gunichar2
*basename
, guint32 size
)
39 return GetModuleBaseName (process
, module
, basename
, size
);
43 mono_w32process_module_get_filename (gpointer process
, gpointer module
, gunichar2
*basename
, guint32 size
)
45 return GetModuleFileNameEx (process
, module
, basename
, size
);
49 mono_w32process_module_get_information (gpointer process
, gpointer module
, MODULEINFO
*modinfo
, guint32 size
)
51 return GetModuleInformation (process
, module
, modinfo
, size
);
55 mono_w32process_get_fileversion_info_size (gunichar2
*filename
, guint32
*handle
)
57 return GetFileVersionInfoSize (filename
, handle
);
61 mono_w32process_get_fileversion_info (gunichar2
*filename
, guint32 handle
, guint32 len
, gpointer data
)
63 return GetFileVersionInfo (filename
, handle
, len
, data
);
67 mono_w32process_ver_query_value (gconstpointer datablock
, const gunichar2
*subblock
, gpointer
*buffer
, guint32
*len
)
69 return VerQueryValue (datablock
, subblock
, buffer
, len
);
73 mono_w32process_ver_language_name (guint32 lang
, gunichar2
*lang_out
, guint32 lang_len
)
75 return VerLanguageName (lang
, lang_out
, lang_len
);
78 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32) */
80 static MonoImage
*system_image
;
83 stash_system_image (MonoImage
*image
)
89 get_file_version_info_class (void)
91 static MonoClass
*file_version_info_class
;
93 if (file_version_info_class
)
94 return file_version_info_class
;
96 g_assert (system_image
);
98 return file_version_info_class
= mono_class_load_from_name (
99 system_image
, "System.Diagnostics", "FileVersionInfo");
103 get_process_module_class (void)
105 static MonoClass
*process_module_class
;
107 if (process_module_class
)
108 return process_module_class
;
110 g_assert (system_image
);
112 return process_module_class
= mono_class_load_from_name (
113 system_image
, "System.Diagnostics", "ProcessModule");
117 unicode_chars (const gunichar2
*str
)
120 for (len
= 0; str
[len
] != '\0'; ++len
) {}
125 process_set_field_object (MonoObject
*obj
, const gchar
*fieldname
, MonoObject
*data
)
128 MonoClassField
*field
;
130 LOGDEBUG (g_message ("%s: Setting field %s to object at %p", __func__
, fieldname
, data
));
132 klass
= mono_object_class (obj
);
135 field
= mono_class_get_field_from_name (klass
, fieldname
);
138 mono_gc_wbarrier_generic_store (((char *)obj
) + field
->offset
, data
);
142 process_set_field_string (MonoObject
*obj
, const gchar
*fieldname
, const gunichar2
*val
, guint32 len
, MonoError
*error
)
146 MonoClassField
*field
;
151 LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__
, fieldname
, g_utf16_to_utf8 (val
, len
, NULL
, NULL
, NULL
)));
153 domain
= mono_object_domain (obj
);
156 klass
= mono_object_class (obj
);
159 field
= mono_class_get_field_from_name (klass
, fieldname
);
162 string
= mono_string_new_utf16_checked (domain
, val
, len
, error
);
163 return_if_nok (error
);
165 mono_gc_wbarrier_generic_store (((char *)obj
) + field
->offset
, (MonoObject
*)string
);
169 process_set_field_string_char (MonoObject
*obj
, const gchar
*fieldname
, const gchar
*val
, MonoError
*error
)
173 MonoClassField
*field
;
177 LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__
, fieldname
, val
));
179 domain
= mono_object_domain (obj
);
182 klass
= mono_object_class (obj
);
185 field
= mono_class_get_field_from_name (klass
, fieldname
);
188 string
= mono_string_new_checked (domain
, val
, error
);
189 return_if_nok (error
);
191 mono_gc_wbarrier_generic_store (((char *)obj
) + field
->offset
, (MonoObject
*)string
);
195 process_set_field_int (MonoObject
*obj
, const gchar
*fieldname
, guint32 val
)
198 MonoClassField
*field
;
200 LOGDEBUG (g_message ("%s: Setting field %s to %d", __func__
,fieldname
, val
));
202 klass
= mono_object_class (obj
);
205 field
= mono_class_get_field_from_name (klass
, fieldname
);
208 *(guint32
*)(((char *)obj
) + field
->offset
)=val
;
212 process_set_field_intptr (MonoObject
*obj
, const gchar
*fieldname
, gpointer val
)
215 MonoClassField
*field
;
217 LOGDEBUG (g_message ("%s: Setting field %s to %p", __func__
, fieldname
, val
));
219 klass
= mono_object_class (obj
);
222 field
= mono_class_get_field_from_name (klass
, fieldname
);
225 *(gpointer
*)(((char *)obj
) + field
->offset
) = val
;
229 process_set_field_bool (MonoObject
*obj
, const gchar
*fieldname
, gboolean val
)
232 MonoClassField
*field
;
234 LOGDEBUG (g_message ("%s: Setting field %s to %s", __func__
, fieldname
, val
? "TRUE":"FALSE"));
236 klass
= mono_object_class (obj
);
239 field
= mono_class_get_field_from_name (klass
, fieldname
);
242 *(guint8
*)(((char *)obj
) + field
->offset
) = val
;
245 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
247 #define SFI_COMMENTS "\\StringFileInfo\\%02X%02X%02X%02X\\Comments"
248 #define SFI_COMPANYNAME "\\StringFileInfo\\%02X%02X%02X%02X\\CompanyName"
249 #define SFI_FILEDESCRIPTION "\\StringFileInfo\\%02X%02X%02X%02X\\FileDescription"
250 #define SFI_FILEVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion"
251 #define SFI_INTERNALNAME "\\StringFileInfo\\%02X%02X%02X%02X\\InternalName"
252 #define SFI_LEGALCOPYRIGHT "\\StringFileInfo\\%02X%02X%02X%02X\\LegalCopyright"
253 #define SFI_LEGALTRADEMARKS "\\StringFileInfo\\%02X%02X%02X%02X\\LegalTrademarks"
254 #define SFI_ORIGINALFILENAME "\\StringFileInfo\\%02X%02X%02X%02X\\OriginalFilename"
255 #define SFI_PRIVATEBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\PrivateBuild"
256 #define SFI_PRODUCTNAME "\\StringFileInfo\\%02X%02X%02X%02X\\ProductName"
257 #define SFI_PRODUCTVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion"
258 #define SFI_SPECIALBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\SpecialBuild"
259 #define EMPTY_STRING (gunichar2*)"\000\000"
266 static StringTableEntry stringtable_entries
[] = {
267 { "comments", SFI_COMMENTS
},
268 { "companyname", SFI_COMPANYNAME
},
269 { "filedescription", SFI_FILEDESCRIPTION
},
270 { "fileversion", SFI_FILEVERSION
},
271 { "internalname", SFI_INTERNALNAME
},
272 { "legalcopyright", SFI_LEGALCOPYRIGHT
},
273 { "legaltrademarks", SFI_LEGALTRADEMARKS
},
274 { "originalfilename", SFI_ORIGINALFILENAME
},
275 { "privatebuild", SFI_PRIVATEBUILD
},
276 { "productname", SFI_PRODUCTNAME
},
277 { "productversion", SFI_PRODUCTVERSION
},
278 { "specialbuild", SFI_SPECIALBUILD
}
282 process_module_string_read (MonoObject
*filever
, gpointer data
, const gchar
*fieldname
,
283 guchar lang_hi
, guchar lang_lo
, const gchar
*key
, MonoError
*error
)
285 gchar
*lang_key_utf8
;
286 gunichar2
*lang_key
, *buffer
;
291 lang_key_utf8
= g_strdup_printf (key
, lang_lo
, lang_hi
, 0x04, 0xb0);
293 LOGDEBUG (g_message ("%s: asking for [%s]", __func__
, lang_key_utf8
));
295 lang_key
= g_utf8_to_utf16 (lang_key_utf8
, -1, NULL
, NULL
, NULL
);
297 if (mono_w32process_ver_query_value (data
, lang_key
, (gpointer
*)&buffer
, &chars
) && chars
> 0) {
298 LOGDEBUG (g_message ("%s: found %d chars of [%s]", __func__
, chars
, g_utf16_to_utf8 (buffer
, chars
, NULL
, NULL
, NULL
)));
299 /* chars includes trailing null */
300 process_set_field_string (filever
, fieldname
, buffer
, chars
- 1, error
);
302 process_set_field_string (filever
, fieldname
, EMPTY_STRING
, 0, error
);
306 g_free (lang_key_utf8
);
310 process_module_stringtable (MonoObject
*filever
, gpointer data
, guchar lang_hi
, guchar lang_lo
, MonoError
*error
)
312 for (int i
= 0; i
< G_N_ELEMENTS (stringtable_entries
); ++i
) {
313 process_module_string_read (filever
, data
, stringtable_entries
[i
].name
,
314 lang_hi
, lang_lo
, stringtable_entries
[i
].id
, error
);
315 return_if_nok (error
);
320 mono_w32process_get_fileversion (MonoObject
*filever
, gunichar2
*filename
, MonoError
*error
)
323 VS_FIXEDFILEINFO
*ffi
;
328 UINT ffi_size
, trans_size
;
330 gunichar2 lang_buf
[128];
331 guint32 lang
, lang_count
;
335 datalen
= mono_w32process_get_fileversion_info_size (filename
, &verinfohandle
);
337 data
= g_malloc0 (datalen
);
338 ok
= mono_w32process_get_fileversion_info (filename
, verinfohandle
, datalen
, data
);
340 query
= g_utf8_to_utf16 ("\\", -1, NULL
, NULL
, NULL
);
346 if (mono_w32process_ver_query_value (data
, query
, (gpointer
*)&ffi
, &ffi_size
)) {
347 #define LOWORD(i32) ((guint16)((i32) & 0xFFFF))
348 #define HIWORD(i32) ((guint16)(((guint32)(i32) >> 16) & 0xFFFF))
350 LOGDEBUG (g_message ("%s: recording assembly: FileName [%s] FileVersionInfo [%d.%d.%d.%d]",
351 __func__
, g_utf16_to_utf8 (filename
, -1, NULL
, NULL
, NULL
), HIWORD (ffi
->dwFileVersionMS
),
352 LOWORD (ffi
->dwFileVersionMS
), HIWORD (ffi
->dwFileVersionLS
), LOWORD (ffi
->dwFileVersionLS
)));
354 process_set_field_int (filever
, "filemajorpart", HIWORD (ffi
->dwFileVersionMS
));
355 process_set_field_int (filever
, "fileminorpart", LOWORD (ffi
->dwFileVersionMS
));
356 process_set_field_int (filever
, "filebuildpart", HIWORD (ffi
->dwFileVersionLS
));
357 process_set_field_int (filever
, "fileprivatepart", LOWORD (ffi
->dwFileVersionLS
));
359 process_set_field_int (filever
, "productmajorpart", HIWORD (ffi
->dwProductVersionMS
));
360 process_set_field_int (filever
, "productminorpart", LOWORD (ffi
->dwProductVersionMS
));
361 process_set_field_int (filever
, "productbuildpart", HIWORD (ffi
->dwProductVersionLS
));
362 process_set_field_int (filever
, "productprivatepart", LOWORD (ffi
->dwProductVersionLS
));
364 process_set_field_bool (filever
, "isdebug", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_DEBUG
) != 0);
365 process_set_field_bool (filever
, "isprerelease", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_PRERELEASE
) != 0);
366 process_set_field_bool (filever
, "ispatched", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_PATCHED
) != 0);
367 process_set_field_bool (filever
, "isprivatebuild", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_PRIVATEBUILD
) != 0);
368 process_set_field_bool (filever
, "isspecialbuild", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_SPECIALBUILD
) != 0);
375 query
= g_utf8_to_utf16 ("\\VarFileInfo\\Translation", -1, NULL
, NULL
, NULL
);
381 if (mono_w32process_ver_query_value (data
, query
, (gpointer
*)&trans_data
, &trans_size
)) {
382 /* use the first language ID we see */
383 if (trans_size
>= 4) {
384 LOGDEBUG (g_message("%s: %s has 0x%0x 0x%0x 0x%0x 0x%0x", __func__
, g_utf16_to_utf8 (filename
, -1, NULL
, NULL
, NULL
), trans_data
[0], trans_data
[1], trans_data
[2], trans_data
[3]));
385 lang
= (trans_data
[0]) | (trans_data
[1] << 8) | (trans_data
[2] << 16) | (trans_data
[3] << 24);
386 /* Only give the lower 16 bits to mono_w32process_ver_language_name, as Windows gets confused otherwise */
387 lang_count
= mono_w32process_ver_language_name (lang
& 0xFFFF, lang_buf
, 128);
389 process_set_field_string (filever
, "language", lang_buf
, lang_count
, error
);
390 return_if_nok (error
);
392 process_module_stringtable (filever
, data
, trans_data
[0], trans_data
[1], error
);
393 return_if_nok (error
);
398 for (i
= 0; i
< G_N_ELEMENTS (stringtable_entries
); ++i
) {
399 /* No strings, so set every field to the empty string */
400 process_set_field_string (filever
, stringtable_entries
[i
].name
, EMPTY_STRING
, 0, error
);
401 return_if_nok (error
);
404 /* And language seems to be set to en_US according to bug 374600 */
405 lang_count
= mono_w32process_ver_language_name (0x0409, lang_buf
, 128);
407 process_set_field_string (filever
, "language", lang_buf
, lang_count
, error
);
408 return_if_nok (error
);
418 #endif /* #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
421 ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject
*this_obj
, MonoString
*filename
)
425 stash_system_image (mono_object_class (this_obj
)->image
);
427 mono_w32process_get_fileversion (this_obj
, mono_string_chars (filename
), &error
);
428 if (!mono_error_ok (&error
)) {
429 mono_error_set_pending_exception (&error
);
433 process_set_field_string (this_obj
, "filename", mono_string_chars (filename
), mono_string_length (filename
), &error
);
434 if (!mono_error_ok (&error
)) {
435 mono_error_set_pending_exception (&error
);
439 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
442 get_domain_assemblies (MonoDomain
*domain
)
445 GPtrArray
*assemblies
;
448 * Make a copy of the list of assemblies because we can't hold the assemblies
449 * lock while creating objects etc.
451 assemblies
= g_ptr_array_new ();
452 mono_domain_assemblies_lock (domain
);
453 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
454 MonoAssembly
*ass
= (MonoAssembly
*)tmp
->data
;
455 if (ass
->image
->fileio_used
)
457 g_ptr_array_add (assemblies
, ass
);
459 mono_domain_assemblies_unlock (domain
);
465 process_add_module (HANDLE process
, HMODULE mod
, gunichar2
*filename
, gunichar2
*modulename
, MonoClass
*proc_class
, MonoError
*error
)
467 MonoObject
*item
, *filever
;
468 MonoDomain
*domain
= mono_domain_get ();
474 /* Build a System.Diagnostics.ProcessModule with the data. */
475 item
= mono_object_new_checked (domain
, proc_class
, error
);
476 return_val_if_nok (error
, NULL
);
478 filever
= mono_object_new_checked (domain
, get_file_version_info_class (), error
);
479 return_val_if_nok (error
, NULL
);
481 mono_w32process_get_fileversion (filever
, filename
, error
);
482 return_val_if_nok (error
, NULL
);
484 process_set_field_string (filever
, "filename", filename
, unicode_chars (filename
), error
);
485 return_val_if_nok (error
, NULL
);
487 ok
= mono_w32process_module_get_information (process
, mod
, &modinfo
, sizeof(MODULEINFO
));
489 process_set_field_intptr (item
, "baseaddr", modinfo
.lpBaseOfDll
);
490 process_set_field_intptr (item
, "entryaddr", modinfo
.EntryPoint
);
491 process_set_field_int (item
, "memory_size", modinfo
.SizeOfImage
);
494 process_set_field_string (item
, "filename", filename
, unicode_chars (filename
), error
);
495 return_val_if_nok (error
, NULL
);
497 process_set_field_string (item
, "modulename", modulename
, unicode_chars (modulename
), error
);
498 return_val_if_nok (error
, NULL
);
500 process_set_field_object (item
, "version_info", filever
);
506 process_get_assembly_fileversion (MonoObject
*filever
, MonoAssembly
*assembly
)
508 process_set_field_int (filever
, "filemajorpart", assembly
->aname
.major
);
509 process_set_field_int (filever
, "fileminorpart", assembly
->aname
.minor
);
510 process_set_field_int (filever
, "filebuildpart", assembly
->aname
.build
);
514 process_get_module (MonoAssembly
*assembly
, MonoClass
*proc_class
, MonoError
*error
)
516 MonoObject
*item
, *filever
;
519 const gchar
*modulename
;
523 domain
= mono_domain_get ();
525 modulename
= assembly
->aname
.name
;
527 /* Build a System.Diagnostics.ProcessModule with the data. */
528 item
= mono_object_new_checked (domain
, proc_class
, error
);
529 return_val_if_nok (error
, NULL
);
531 filever
= mono_object_new_checked (domain
, get_file_version_info_class (), error
);
532 return_val_if_nok (error
, NULL
);
534 filename
= g_strdup_printf ("[In Memory] %s", modulename
);
536 process_get_assembly_fileversion (filever
, assembly
);
537 process_set_field_string_char (filever
, "filename", filename
, error
);
538 return_val_if_nok (error
, NULL
);
539 process_set_field_object (item
, "version_info", filever
);
541 process_set_field_intptr (item
, "baseaddr", assembly
->image
->raw_data
);
542 process_set_field_int (item
, "memory_size", assembly
->image
->raw_data_len
);
543 process_set_field_string_char (item
, "filename", filename
, error
);
544 return_val_if_nok (error
, NULL
);
545 process_set_field_string_char (item
, "modulename", modulename
, error
);
546 return_val_if_nok (error
, NULL
);
553 /* Returns an array of System.Diagnostics.ProcessModule */
555 ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject
*this_obj
, HANDLE process
)
558 MonoArray
*temp_arr
= NULL
;
561 gunichar2 filename
[MAX_PATH
];
562 gunichar2 modname
[MAX_PATH
];
564 guint32 count
= 0, module_count
= 0, assembly_count
= 0;
565 guint32 i
, num_added
= 0;
566 GPtrArray
*assemblies
= NULL
;
568 stash_system_image (mono_object_class (this_obj
)->image
);
570 if (mono_w32process_get_pid (process
) == mono_process_current_pid ()) {
571 assemblies
= get_domain_assemblies (mono_domain_get ());
572 assembly_count
= assemblies
->len
;
575 if (mono_w32process_try_get_modules (process
, mods
, sizeof(mods
), &needed
))
576 module_count
+= needed
/ sizeof(HMODULE
);
578 count
= module_count
+ assembly_count
;
579 temp_arr
= mono_array_new_checked (mono_domain_get (), get_process_module_class (), count
, &error
);
580 if (mono_error_set_pending_exception (&error
))
583 for (i
= 0; i
< module_count
; i
++) {
584 if (mono_w32process_module_get_name (process
, mods
[i
], modname
, MAX_PATH
)
585 && mono_w32process_module_get_filename (process
, mods
[i
], filename
, MAX_PATH
))
587 MonoObject
*module
= process_add_module (process
, mods
[i
], filename
, modname
, get_process_module_class (), &error
);
588 if (!mono_error_ok (&error
)) {
589 mono_error_set_pending_exception (&error
);
592 mono_array_setref (temp_arr
, num_added
++, module
);
597 for (i
= 0; i
< assembly_count
; i
++) {
598 MonoAssembly
*ass
= (MonoAssembly
*)g_ptr_array_index (assemblies
, i
);
599 MonoObject
*module
= process_get_module (ass
, get_process_module_class (), &error
);
600 if (!mono_error_ok (&error
)) {
601 mono_error_set_pending_exception (&error
);
604 mono_array_setref (temp_arr
, num_added
++, module
);
606 g_ptr_array_free (assemblies
, TRUE
);
609 if (count
== num_added
) {
612 /* shorter version of the array */
613 arr
= mono_array_new_checked (mono_domain_get (), get_process_module_class (), num_added
, &error
);
614 if (mono_error_set_pending_exception (&error
))
617 for (i
= 0; i
< num_added
; i
++)
618 mono_array_setref (arr
, i
, mono_array_get (temp_arr
, MonoObject
*, i
));
624 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
626 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
629 ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process
)
633 gunichar2 name
[MAX_PATH
];
639 ok
= mono_w32process_try_get_modules (process
, &mod
, sizeof(mod
), &needed
);
643 len
= mono_w32process_module_get_name (process
, mod
, name
, MAX_PATH
);
647 string
= mono_string_new_utf16_checked (mono_domain_get (), name
, len
, &error
);
648 if (!mono_error_ok (&error
))
649 mono_error_set_pending_exception (&error
);
654 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
657 ves_icall_System_Diagnostics_Process_GetProcessData (int pid
, gint32 data_type
, gint32
*error
)
659 MonoProcessError perror
;
662 res
= mono_process_get_data_with_error (GINT_TO_POINTER (pid
), (MonoProcessData
)data_type
, &perror
);