4 #include "w32process.h"
5 #include "w32process-internals.h"
6 #include "w32process-win32-internals.h"
9 #include "object-internals.h"
11 #include "class-internals.h"
13 #include "utils/mono-proclib.h"
14 #include "utils/w32api.h"
17 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
19 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32)
22 mono_w32process_get_pid (gpointer handle
)
24 return GetProcessId (handle
);
28 mono_w32process_try_get_modules (gpointer process
, gpointer
*modules
, guint32 size
, guint32
*needed
)
30 return EnumProcessModules (process
, (HMODULE
*) modules
, size
, (LPDWORD
) needed
);
34 mono_w32process_module_get_name (gpointer process
, gpointer module
, gunichar2
*basename
, guint32 size
)
36 return GetModuleBaseName (process
, module
, basename
, size
);
40 mono_w32process_module_get_filename (gpointer process
, gpointer module
, gunichar2
*basename
, guint32 size
)
42 return GetModuleFileNameEx (process
, module
, basename
, size
);
46 mono_w32process_module_get_information (gpointer process
, gpointer module
, MODULEINFO
*modinfo
, guint32 size
)
48 return GetModuleInformation (process
, module
, modinfo
, size
);
52 mono_w32process_get_fileversion_info_size (gunichar2
*filename
, guint32
*handle
)
54 return GetFileVersionInfoSize (filename
, handle
);
58 mono_w32process_get_fileversion_info (gunichar2
*filename
, guint32 handle
, guint32 len
, gpointer data
)
60 return GetFileVersionInfo (filename
, handle
, len
, data
);
64 mono_w32process_ver_query_value (gconstpointer datablock
, const gunichar2
*subblock
, gpointer
*buffer
, guint32
*len
)
66 return VerQueryValue (datablock
, subblock
, buffer
, len
);
70 mono_w32process_ver_language_name (guint32 lang
, gunichar2
*lang_out
, guint32 lang_len
)
72 return VerLanguageName (lang
, lang_out
, lang_len
);
75 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32) */
77 static MonoImage
*system_image
;
80 stash_system_image (MonoImage
*image
)
86 get_file_version_info_class (void)
88 static MonoClass
*file_version_info_class
;
90 if (file_version_info_class
)
91 return file_version_info_class
;
93 g_assert (system_image
);
95 return file_version_info_class
= mono_class_load_from_name (
96 system_image
, "System.Diagnostics", "FileVersionInfo");
100 get_process_module_class (void)
102 static MonoClass
*process_module_class
;
104 if (process_module_class
)
105 return process_module_class
;
107 g_assert (system_image
);
109 return process_module_class
= mono_class_load_from_name (
110 system_image
, "System.Diagnostics", "ProcessModule");
114 unicode_chars (const gunichar2
*str
)
117 for (len
= 0; str
[len
] != '\0'; ++len
) {}
122 process_set_field_object (MonoObject
*obj
, const gchar
*fieldname
, MonoObject
*data
)
125 MonoClassField
*field
;
127 LOGDEBUG (g_message ("%s: Setting field %s to object at %p", __func__
, fieldname
, data
));
129 klass
= mono_object_class (obj
);
132 field
= mono_class_get_field_from_name (klass
, fieldname
);
135 mono_gc_wbarrier_generic_store (((char *)obj
) + field
->offset
, data
);
139 process_set_field_string (MonoObject
*obj
, const gchar
*fieldname
, const gunichar2
*val
, guint32 len
, MonoError
*error
)
143 MonoClassField
*field
;
146 mono_error_init (error
);
148 LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__
, fieldname
, g_utf16_to_utf8 (val
, len
, NULL
, NULL
, NULL
)));
150 domain
= mono_object_domain (obj
);
153 klass
= mono_object_class (obj
);
156 field
= mono_class_get_field_from_name (klass
, fieldname
);
159 string
= mono_string_new_utf16_checked (domain
, val
, len
, error
);
160 return_if_nok (error
);
162 mono_gc_wbarrier_generic_store (((char *)obj
) + field
->offset
, (MonoObject
*)string
);
166 process_set_field_string_char (MonoObject
*obj
, const gchar
*fieldname
, const gchar
*val
)
170 MonoClassField
*field
;
173 LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__
, fieldname
, val
));
175 domain
= mono_object_domain (obj
);
178 klass
= mono_object_class (obj
);
181 field
= mono_class_get_field_from_name (klass
, fieldname
);
184 string
= mono_string_new (domain
, val
);
186 mono_gc_wbarrier_generic_store (((char *)obj
) + field
->offset
, (MonoObject
*)string
);
190 process_set_field_int (MonoObject
*obj
, const gchar
*fieldname
, guint32 val
)
193 MonoClassField
*field
;
195 LOGDEBUG (g_message ("%s: Setting field %s to %d", __func__
,fieldname
, val
));
197 klass
= mono_object_class (obj
);
200 field
= mono_class_get_field_from_name (klass
, fieldname
);
203 *(guint32
*)(((char *)obj
) + field
->offset
)=val
;
207 process_set_field_intptr (MonoObject
*obj
, const gchar
*fieldname
, gpointer val
)
210 MonoClassField
*field
;
212 LOGDEBUG (g_message ("%s: Setting field %s to %p", __func__
, fieldname
, val
));
214 klass
= mono_object_class (obj
);
217 field
= mono_class_get_field_from_name (klass
, fieldname
);
220 *(gpointer
*)(((char *)obj
) + field
->offset
) = val
;
224 process_set_field_bool (MonoObject
*obj
, const gchar
*fieldname
, gboolean val
)
227 MonoClassField
*field
;
229 LOGDEBUG (g_message ("%s: Setting field %s to %s", __func__
, fieldname
, val
? "TRUE":"FALSE"));
231 klass
= mono_object_class (obj
);
234 field
= mono_class_get_field_from_name (klass
, fieldname
);
237 *(guint8
*)(((char *)obj
) + field
->offset
) = val
;
240 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
242 #define SFI_COMMENTS "\\StringFileInfo\\%02X%02X%02X%02X\\Comments"
243 #define SFI_COMPANYNAME "\\StringFileInfo\\%02X%02X%02X%02X\\CompanyName"
244 #define SFI_FILEDESCRIPTION "\\StringFileInfo\\%02X%02X%02X%02X\\FileDescription"
245 #define SFI_FILEVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion"
246 #define SFI_INTERNALNAME "\\StringFileInfo\\%02X%02X%02X%02X\\InternalName"
247 #define SFI_LEGALCOPYRIGHT "\\StringFileInfo\\%02X%02X%02X%02X\\LegalCopyright"
248 #define SFI_LEGALTRADEMARKS "\\StringFileInfo\\%02X%02X%02X%02X\\LegalTrademarks"
249 #define SFI_ORIGINALFILENAME "\\StringFileInfo\\%02X%02X%02X%02X\\OriginalFilename"
250 #define SFI_PRIVATEBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\PrivateBuild"
251 #define SFI_PRODUCTNAME "\\StringFileInfo\\%02X%02X%02X%02X\\ProductName"
252 #define SFI_PRODUCTVERSION "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion"
253 #define SFI_SPECIALBUILD "\\StringFileInfo\\%02X%02X%02X%02X\\SpecialBuild"
254 #define EMPTY_STRING (gunichar2*)"\000\000"
261 static StringTableEntry stringtable_entries
[] = {
262 { "comments", SFI_COMMENTS
},
263 { "companyname", SFI_COMPANYNAME
},
264 { "filedescription", SFI_FILEDESCRIPTION
},
265 { "fileversion", SFI_FILEVERSION
},
266 { "internalname", SFI_INTERNALNAME
},
267 { "legalcopyright", SFI_LEGALCOPYRIGHT
},
268 { "legaltrademarks", SFI_LEGALTRADEMARKS
},
269 { "originalfilename", SFI_ORIGINALFILENAME
},
270 { "privatebuild", SFI_PRIVATEBUILD
},
271 { "productname", SFI_PRODUCTNAME
},
272 { "productversion", SFI_PRODUCTVERSION
},
273 { "specialbuild", SFI_SPECIALBUILD
}
277 process_module_string_read (MonoObject
*filever
, gpointer data
, const gchar
*fieldname
,
278 guchar lang_hi
, guchar lang_lo
, const gchar
*key
, MonoError
*error
)
280 gchar
*lang_key_utf8
;
281 gunichar2
*lang_key
, *buffer
;
284 mono_error_init (error
);
286 lang_key_utf8
= g_strdup_printf (key
, lang_lo
, lang_hi
, 0x04, 0xb0);
288 LOGDEBUG (g_message ("%s: asking for [%s]", __func__
, lang_key_utf8
));
290 lang_key
= g_utf8_to_utf16 (lang_key_utf8
, -1, NULL
, NULL
, NULL
);
292 if (mono_w32process_ver_query_value (data
, lang_key
, (gpointer
*)&buffer
, &chars
) && chars
> 0) {
293 LOGDEBUG (g_message ("%s: found %d chars of [%s]", __func__
, chars
, g_utf16_to_utf8 (buffer
, chars
, NULL
, NULL
, NULL
)));
294 /* chars includes trailing null */
295 process_set_field_string (filever
, fieldname
, buffer
, chars
- 1, error
);
297 process_set_field_string (filever
, fieldname
, EMPTY_STRING
, 0, error
);
301 g_free (lang_key_utf8
);
305 process_module_stringtable (MonoObject
*filever
, gpointer data
, guchar lang_hi
, guchar lang_lo
, MonoError
*error
)
307 for (int i
= 0; i
< G_N_ELEMENTS (stringtable_entries
); ++i
) {
308 process_module_string_read (filever
, data
, stringtable_entries
[i
].name
,
309 lang_hi
, lang_lo
, stringtable_entries
[i
].id
, error
);
310 return_if_nok (error
);
315 mono_w32process_get_fileversion (MonoObject
*filever
, gunichar2
*filename
, MonoError
*error
)
318 VS_FIXEDFILEINFO
*ffi
;
323 UINT ffi_size
, trans_size
;
325 gunichar2 lang_buf
[128];
326 guint32 lang
, lang_count
;
328 mono_error_init (error
);
330 datalen
= mono_w32process_get_fileversion_info_size (filename
, &verinfohandle
);
332 data
= g_malloc0 (datalen
);
333 ok
= mono_w32process_get_fileversion_info (filename
, verinfohandle
, datalen
, data
);
335 query
= g_utf8_to_utf16 ("\\", -1, NULL
, NULL
, NULL
);
341 if (mono_w32process_ver_query_value (data
, query
, (gpointer
*)&ffi
, &ffi_size
)) {
342 #define LOWORD(i32) ((guint16)((i32) & 0xFFFF))
343 #define HIWORD(i32) ((guint16)(((guint32)(i32) >> 16) & 0xFFFF))
345 LOGDEBUG (g_message ("%s: recording assembly: FileName [%s] FileVersionInfo [%d.%d.%d.%d]",
346 __func__
, g_utf16_to_utf8 (filename
, -1, NULL
, NULL
, NULL
), HIWORD (ffi
->dwFileVersionMS
),
347 LOWORD (ffi
->dwFileVersionMS
), HIWORD (ffi
->dwFileVersionLS
), LOWORD (ffi
->dwFileVersionLS
)));
349 process_set_field_int (filever
, "filemajorpart", HIWORD (ffi
->dwFileVersionMS
));
350 process_set_field_int (filever
, "fileminorpart", LOWORD (ffi
->dwFileVersionMS
));
351 process_set_field_int (filever
, "filebuildpart", HIWORD (ffi
->dwFileVersionLS
));
352 process_set_field_int (filever
, "fileprivatepart", LOWORD (ffi
->dwFileVersionLS
));
354 process_set_field_int (filever
, "productmajorpart", HIWORD (ffi
->dwProductVersionMS
));
355 process_set_field_int (filever
, "productminorpart", LOWORD (ffi
->dwProductVersionMS
));
356 process_set_field_int (filever
, "productbuildpart", HIWORD (ffi
->dwProductVersionLS
));
357 process_set_field_int (filever
, "productprivatepart", LOWORD (ffi
->dwProductVersionLS
));
359 process_set_field_bool (filever
, "isdebug", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_DEBUG
) != 0);
360 process_set_field_bool (filever
, "isprerelease", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_PRERELEASE
) != 0);
361 process_set_field_bool (filever
, "ispatched", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_PATCHED
) != 0);
362 process_set_field_bool (filever
, "isprivatebuild", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_PRIVATEBUILD
) != 0);
363 process_set_field_bool (filever
, "isspecialbuild", ((ffi
->dwFileFlags
& ffi
->dwFileFlagsMask
) & VS_FF_SPECIALBUILD
) != 0);
370 query
= g_utf8_to_utf16 ("\\VarFileInfo\\Translation", -1, NULL
, NULL
, NULL
);
376 if (mono_w32process_ver_query_value (data
, query
, (gpointer
*)&trans_data
, &trans_size
)) {
377 /* use the first language ID we see */
378 if (trans_size
>= 4) {
379 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]));
380 lang
= (trans_data
[0]) | (trans_data
[1] << 8) | (trans_data
[2] << 16) | (trans_data
[3] << 24);
381 /* Only give the lower 16 bits to mono_w32process_ver_language_name, as Windows gets confused otherwise */
382 lang_count
= mono_w32process_ver_language_name (lang
& 0xFFFF, lang_buf
, 128);
384 process_set_field_string (filever
, "language", lang_buf
, lang_count
, error
);
385 return_if_nok (error
);
387 process_module_stringtable (filever
, data
, trans_data
[0], trans_data
[1], error
);
388 return_if_nok (error
);
393 for (i
= 0; i
< G_N_ELEMENTS (stringtable_entries
); ++i
) {
394 /* No strings, so set every field to the empty string */
395 process_set_field_string (filever
, stringtable_entries
[i
].name
, EMPTY_STRING
, 0, error
);
396 return_if_nok (error
);
399 /* And language seems to be set to en_US according to bug 374600 */
400 lang_count
= mono_w32process_ver_language_name (0x0409, lang_buf
, 128);
402 process_set_field_string (filever
, "language", lang_buf
, lang_count
, error
);
403 return_if_nok (error
);
413 #endif /* #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
416 ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject
*this_obj
, MonoString
*filename
)
420 stash_system_image (mono_object_class (this_obj
)->image
);
422 mono_w32process_get_fileversion (this_obj
, mono_string_chars (filename
), &error
);
423 if (!mono_error_ok (&error
)) {
424 mono_error_set_pending_exception (&error
);
428 process_set_field_string (this_obj
, "filename", mono_string_chars (filename
), mono_string_length (filename
), &error
);
429 if (!mono_error_ok (&error
)) {
430 mono_error_set_pending_exception (&error
);
434 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
437 get_domain_assemblies (MonoDomain
*domain
)
440 GPtrArray
*assemblies
;
443 * Make a copy of the list of assemblies because we can't hold the assemblies
444 * lock while creating objects etc.
446 assemblies
= g_ptr_array_new ();
447 mono_domain_assemblies_lock (domain
);
448 for (tmp
= domain
->domain_assemblies
; tmp
; tmp
= tmp
->next
) {
449 MonoAssembly
*ass
= (MonoAssembly
*)tmp
->data
;
450 if (ass
->image
->fileio_used
)
452 g_ptr_array_add (assemblies
, ass
);
454 mono_domain_assemblies_unlock (domain
);
460 process_add_module (HANDLE process
, HMODULE mod
, gunichar2
*filename
, gunichar2
*modulename
, MonoClass
*proc_class
, MonoError
*error
)
462 MonoObject
*item
, *filever
;
463 MonoDomain
*domain
= mono_domain_get ();
467 mono_error_init (error
);
469 /* Build a System.Diagnostics.ProcessModule with the data. */
470 item
= mono_object_new_checked (domain
, proc_class
, error
);
471 return_val_if_nok (error
, NULL
);
473 filever
= mono_object_new_checked (domain
, get_file_version_info_class (), error
);
474 return_val_if_nok (error
, NULL
);
476 mono_w32process_get_fileversion (filever
, filename
, error
);
477 return_val_if_nok (error
, NULL
);
479 process_set_field_string (filever
, "filename", filename
, unicode_chars (filename
), error
);
480 return_val_if_nok (error
, NULL
);
482 ok
= mono_w32process_module_get_information (process
, mod
, &modinfo
, sizeof(MODULEINFO
));
484 process_set_field_intptr (item
, "baseaddr", modinfo
.lpBaseOfDll
);
485 process_set_field_intptr (item
, "entryaddr", modinfo
.EntryPoint
);
486 process_set_field_int (item
, "memory_size", modinfo
.SizeOfImage
);
489 process_set_field_string (item
, "filename", filename
, unicode_chars (filename
), error
);
490 return_val_if_nok (error
, NULL
);
492 process_set_field_string (item
, "modulename", modulename
, unicode_chars (modulename
), error
);
493 return_val_if_nok (error
, NULL
);
495 process_set_field_object (item
, "version_info", filever
);
501 process_get_assembly_fileversion (MonoObject
*filever
, MonoAssembly
*assembly
)
503 process_set_field_int (filever
, "filemajorpart", assembly
->aname
.major
);
504 process_set_field_int (filever
, "fileminorpart", assembly
->aname
.minor
);
505 process_set_field_int (filever
, "filebuildpart", assembly
->aname
.build
);
509 process_get_module (MonoAssembly
*assembly
, MonoClass
*proc_class
, MonoError
*error
)
511 MonoObject
*item
, *filever
;
514 const gchar
*modulename
;
516 mono_error_init (error
);
518 domain
= mono_domain_get ();
520 modulename
= assembly
->aname
.name
;
522 /* Build a System.Diagnostics.ProcessModule with the data. */
523 item
= mono_object_new_checked (domain
, proc_class
, error
);
524 return_val_if_nok (error
, NULL
);
526 filever
= mono_object_new_checked (domain
, get_file_version_info_class (), error
);
527 return_val_if_nok (error
, NULL
);
529 filename
= g_strdup_printf ("[In Memory] %s", modulename
);
531 process_get_assembly_fileversion (filever
, assembly
);
532 process_set_field_string_char (filever
, "filename", filename
);
533 process_set_field_object (item
, "version_info", filever
);
535 process_set_field_intptr (item
, "baseaddr", assembly
->image
->raw_data
);
536 process_set_field_int (item
, "memory_size", assembly
->image
->raw_data_len
);
537 process_set_field_string_char (item
, "filename", filename
);
538 process_set_field_string_char (item
, "modulename", modulename
);
545 /* Returns an array of System.Diagnostics.ProcessModule */
547 ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject
*this_obj
, HANDLE process
)
550 MonoArray
*temp_arr
= NULL
;
553 gunichar2 filename
[MAX_PATH
];
554 gunichar2 modname
[MAX_PATH
];
556 guint32 count
= 0, module_count
= 0, assembly_count
= 0;
557 guint32 i
, num_added
= 0;
558 GPtrArray
*assemblies
= NULL
;
560 stash_system_image (mono_object_class (this_obj
)->image
);
562 if (mono_w32process_get_pid (process
) == mono_process_current_pid ()) {
563 assemblies
= get_domain_assemblies (mono_domain_get ());
564 assembly_count
= assemblies
->len
;
567 if (mono_w32process_try_get_modules (process
, mods
, sizeof(mods
), &needed
))
568 module_count
+= needed
/ sizeof(HMODULE
);
570 count
= module_count
+ assembly_count
;
571 temp_arr
= mono_array_new_checked (mono_domain_get (), get_process_module_class (), count
, &error
);
572 if (mono_error_set_pending_exception (&error
))
575 for (i
= 0; i
< module_count
; i
++) {
576 if (mono_w32process_module_get_name (process
, mods
[i
], modname
, MAX_PATH
)
577 && mono_w32process_module_get_filename (process
, mods
[i
], filename
, MAX_PATH
))
579 MonoObject
*module
= process_add_module (process
, mods
[i
], filename
, modname
, get_process_module_class (), &error
);
580 if (!mono_error_ok (&error
)) {
581 mono_error_set_pending_exception (&error
);
584 mono_array_setref (temp_arr
, num_added
++, module
);
589 for (i
= 0; i
< assembly_count
; i
++) {
590 MonoAssembly
*ass
= (MonoAssembly
*)g_ptr_array_index (assemblies
, i
);
591 MonoObject
*module
= process_get_module (ass
, get_process_module_class (), &error
);
592 if (!mono_error_ok (&error
)) {
593 mono_error_set_pending_exception (&error
);
596 mono_array_setref (temp_arr
, num_added
++, module
);
598 g_ptr_array_free (assemblies
, TRUE
);
601 if (count
== num_added
) {
604 /* shorter version of the array */
605 arr
= mono_array_new_checked (mono_domain_get (), get_process_module_class (), num_added
, &error
);
606 if (mono_error_set_pending_exception (&error
))
609 for (i
= 0; i
< num_added
; i
++)
610 mono_array_setref (arr
, i
, mono_array_get (temp_arr
, MonoObject
*, i
));
616 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
618 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
621 ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process
)
625 gunichar2 name
[MAX_PATH
];
631 ok
= mono_w32process_try_get_modules (process
, &mod
, sizeof(mod
), &needed
);
635 len
= mono_w32process_module_get_name (process
, mod
, name
, MAX_PATH
);
639 string
= mono_string_new_utf16_checked (mono_domain_get (), name
, len
, &error
);
640 if (!mono_error_ok (&error
))
641 mono_error_set_pending_exception (&error
);
646 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
649 ves_icall_System_Diagnostics_Process_GetProcessData (int pid
, gint32 data_type
, gint32
*error
)
651 MonoProcessError perror
;
654 res
= mono_process_get_data_with_error (GINT_TO_POINTER (pid
), (MonoProcessData
)data_type
, &perror
);