Merge pull request #3902 from henricm/fix-rename-lpstr-utf8
[mono.git] / mono / metadata / w32process.c
1
2 #include <glib.h>
3
4 #include "w32process.h"
5 #include "w32process-internals.h"
6 #include "w32process-win32-internals.h"
7 #include "object.h"
8 #include "object-internals.h"
9 #include "class.h"
10 #include "class-internals.h"
11 #include "image.h"
12 #include "utils/mono-proclib.h"
13
14 #define LOGDEBUG(...)
15 /* define LOGDEBUG(...) g_message(__VA_ARGS__)  */
16
17 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32)
18
19 static guint32
20 mono_w32process_get_pid (gpointer handle)
21 {
22         return GetProcessId (handle);
23 }
24
25 static gboolean
26 mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 size, guint32 *needed)
27 {
28         return EnumProcessModules (process, (HMODULE *) modules, size, (LPDWORD) needed);
29 }
30
31 static guint32
32 mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *basename, guint32 size)
33 {
34         return GetModuleBaseName (process, module, basename, size);
35 }
36
37 static guint32
38 mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar2 *basename, guint32 size)
39 {
40         return GetModuleFileNameEx (process, module, basename, size);
41 }
42
43 static gboolean
44 mono_w32process_module_get_information (gpointer process, gpointer module, MODULEINFO *modinfo, guint32 size)
45 {
46         return GetModuleInformation (process, module, modinfo, size);
47 }
48
49 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) && defined(HOST_WIN32) */
50
51 static MonoImage *system_image;
52
53 static void
54 stash_system_image (MonoImage *image)
55 {
56         system_image = image;
57 }
58
59 static MonoClass*
60 get_file_version_info_class (void)
61 {
62         static MonoClass *file_version_info_class;
63
64         if (file_version_info_class)
65                 return file_version_info_class;
66
67         g_assert (system_image);
68
69         return file_version_info_class = mono_class_load_from_name (
70                 system_image, "System.Diagnostics", "FileVersionInfo");
71 }
72
73 static MonoClass*
74 get_process_module_class (void)
75 {
76         static MonoClass *process_module_class;
77
78         if (process_module_class)
79                 return process_module_class;
80
81         g_assert (system_image);
82
83         return process_module_class = mono_class_load_from_name (
84                 system_image, "System.Diagnostics", "ProcessModule");
85 }
86
87 static guint32
88 unicode_chars (const gunichar2 *str)
89 {
90         guint32 len;
91         for (len = 0; str [len] != '\0'; ++len) {}
92         return len;
93 }
94
95 static void
96 process_set_field_object (MonoObject *obj, const gchar *fieldname, MonoObject *data)
97 {
98         MonoClass *klass;
99         MonoClassField *field;
100
101         LOGDEBUG (g_message ("%s: Setting field %s to object at %p", __func__, fieldname, data));
102
103         klass = mono_object_class (obj);
104         g_assert (klass);
105
106         field = mono_class_get_field_from_name (klass, fieldname);
107         g_assert (field);
108
109         mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, data);
110 }
111
112 static void
113 process_set_field_string (MonoObject *obj, const gchar *fieldname, const gunichar2 *val, guint32 len, MonoError *error)
114 {
115         MonoDomain *domain;
116         MonoClass *klass;
117         MonoClassField *field;
118         MonoString *string;
119
120         mono_error_init (error);
121
122         LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__, fieldname, g_utf16_to_utf8 (val, len, NULL, NULL, NULL)));
123
124         domain = mono_object_domain (obj);
125         g_assert (domain);
126
127         klass = mono_object_class (obj);
128         g_assert (klass);
129
130         field = mono_class_get_field_from_name (klass, fieldname);
131         g_assert (field);
132
133         string = mono_string_new_utf16_checked (domain, val, len, error);
134         return_if_nok (error);
135
136         mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, (MonoObject*)string);
137 }
138
139 static void
140 process_set_field_string_char (MonoObject *obj, const gchar *fieldname, const gchar *val)
141 {
142         MonoDomain *domain;
143         MonoClass *klass;
144         MonoClassField *field;
145         MonoString *string;
146
147         LOGDEBUG (g_message ("%s: Setting field %s to [%s]", __func__, fieldname, val));
148
149         domain = mono_object_domain (obj);
150         g_assert (domain);
151
152         klass = mono_object_class (obj);
153         g_assert (klass);
154
155         field = mono_class_get_field_from_name (klass, fieldname);
156         g_assert (field);
157
158         string = mono_string_new (domain, val);
159
160         mono_gc_wbarrier_generic_store (((char *)obj) + field->offset, (MonoObject*)string);
161 }
162
163 static void
164 process_set_field_int (MonoObject *obj, const gchar *fieldname, guint32 val)
165 {
166         MonoClass *klass;
167         MonoClassField *field;
168
169         LOGDEBUG (g_message ("%s: Setting field %s to %d", __func__,fieldname, val));
170
171         klass = mono_object_class (obj);
172         g_assert (klass);
173
174         field = mono_class_get_field_from_name (klass, fieldname);
175         g_assert (field);
176
177         *(guint32 *)(((char *)obj) + field->offset)=val;
178 }
179
180 static void
181 process_set_field_intptr (MonoObject *obj, const gchar *fieldname, gpointer val)
182 {
183         MonoClass *klass;
184         MonoClassField *field;
185
186         LOGDEBUG (g_message ("%s: Setting field %s to %p", __func__, fieldname, val));
187
188         klass = mono_object_class (obj);
189         g_assert (klass);
190
191         field = mono_class_get_field_from_name (klass, fieldname);
192         g_assert (field);
193
194         *(gpointer *)(((char *)obj) + field->offset) = val;
195 }
196
197 static void
198 process_set_field_bool (MonoObject *obj, const gchar *fieldname, gboolean val)
199 {
200         MonoClass *klass;
201         MonoClassField *field;
202
203         LOGDEBUG (g_message ("%s: Setting field %s to %s", __func__, fieldname, val ? "TRUE":"FALSE"));
204
205         klass = mono_object_class (obj);
206         g_assert (klass);
207
208         field = mono_class_get_field_from_name (klass, fieldname);
209         g_assert (field);
210
211         *(guint8 *)(((char *)obj) + field->offset) = val;
212 }
213
214 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
215
216 #define SFI_COMMENTS            "\\StringFileInfo\\%02X%02X%02X%02X\\Comments"
217 #define SFI_COMPANYNAME         "\\StringFileInfo\\%02X%02X%02X%02X\\CompanyName"
218 #define SFI_FILEDESCRIPTION     "\\StringFileInfo\\%02X%02X%02X%02X\\FileDescription"
219 #define SFI_FILEVERSION         "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion"
220 #define SFI_INTERNALNAME        "\\StringFileInfo\\%02X%02X%02X%02X\\InternalName"
221 #define SFI_LEGALCOPYRIGHT      "\\StringFileInfo\\%02X%02X%02X%02X\\LegalCopyright"
222 #define SFI_LEGALTRADEMARKS     "\\StringFileInfo\\%02X%02X%02X%02X\\LegalTrademarks"
223 #define SFI_ORIGINALFILENAME    "\\StringFileInfo\\%02X%02X%02X%02X\\OriginalFilename"
224 #define SFI_PRIVATEBUILD        "\\StringFileInfo\\%02X%02X%02X%02X\\PrivateBuild"
225 #define SFI_PRODUCTNAME         "\\StringFileInfo\\%02X%02X%02X%02X\\ProductName"
226 #define SFI_PRODUCTVERSION      "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion"
227 #define SFI_SPECIALBUILD        "\\StringFileInfo\\%02X%02X%02X%02X\\SpecialBuild"
228 #define EMPTY_STRING            (gunichar2*)"\000\000"
229
230 typedef struct {
231         const char *name;
232         const char *id;
233 } StringTableEntry;
234
235 static StringTableEntry stringtable_entries [] = {
236         { "comments", SFI_COMMENTS },
237         { "companyname", SFI_COMPANYNAME },
238         { "filedescription", SFI_FILEDESCRIPTION },
239         { "fileversion", SFI_FILEVERSION },
240         { "internalname", SFI_INTERNALNAME },
241         { "legalcopyright", SFI_LEGALCOPYRIGHT },
242         { "legaltrademarks", SFI_LEGALTRADEMARKS },
243         { "originalfilename", SFI_ORIGINALFILENAME },
244         { "privatebuild", SFI_PRIVATEBUILD },
245         { "productname", SFI_PRODUCTNAME },
246         { "productversion", SFI_PRODUCTVERSION },
247         { "specialbuild", SFI_SPECIALBUILD }
248 };
249
250 static void
251 process_module_string_read (MonoObject *filever, gpointer data, const gchar *fieldname,
252                 guchar lang_hi, guchar lang_lo, const gchar *key, MonoError *error)
253 {
254         gchar *lang_key_utf8;
255         gunichar2 *lang_key, *buffer;
256         UINT chars;
257
258         mono_error_init (error);
259
260         lang_key_utf8 = g_strdup_printf (key, lang_lo, lang_hi, 0x04, 0xb0);
261
262         LOGDEBUG (g_message ("%s: asking for [%s]", __func__, lang_key_utf8));
263
264         lang_key = g_utf8_to_utf16 (lang_key_utf8, -1, NULL, NULL, NULL);
265
266         if (VerQueryValue (data, lang_key, (gpointer *)&buffer, &chars) && chars > 0) {
267                 LOGDEBUG (g_message ("%s: found %d chars of [%s]", __func__, chars, g_utf16_to_utf8 (buffer, chars, NULL, NULL, NULL)));
268                 /* chars includes trailing null */
269                 process_set_field_string (filever, fieldname, buffer, chars - 1, error);
270         } else {
271                 process_set_field_string (filever, fieldname, EMPTY_STRING, 0, error);
272         }
273
274         g_free (lang_key);
275         g_free (lang_key_utf8);
276 }
277
278 static void
279 process_module_stringtable (MonoObject *filever, gpointer data, guchar lang_hi, guchar lang_lo, MonoError *error)
280 {
281         for (int i = 0; i < G_N_ELEMENTS (stringtable_entries); ++i) {
282                 process_module_string_read (filever, data, stringtable_entries [i].name,
283                         lang_hi, lang_lo, stringtable_entries [i].id, error);
284                 return_if_nok (error);
285         }
286 }
287
288 static void
289 mono_w32process_get_fileversion (MonoObject *filever, gunichar2 *filename, MonoError *error)
290 {
291         DWORD verinfohandle;
292         VS_FIXEDFILEINFO *ffi;
293         gpointer data;
294         DWORD datalen;
295         guchar *trans_data;
296         gunichar2 *query;
297         UINT ffi_size, trans_size;
298         BOOL ok;
299         gunichar2 lang_buf[128];
300         guint32 lang, lang_count;
301
302         mono_error_init (error);
303
304         datalen = GetFileVersionInfoSize (filename, &verinfohandle);
305         if (datalen) {
306                 data = g_malloc0 (datalen);
307                 ok = GetFileVersionInfo (filename, verinfohandle, datalen, data);
308                 if (ok) {
309                         query = g_utf8_to_utf16 ("\\", -1, NULL, NULL, NULL);
310                         if (query == NULL) {
311                                 g_free (data);
312                                 return;
313                         }
314
315                         if (VerQueryValue (data, query, (gpointer *)&ffi, &ffi_size)) {
316                                 LOGDEBUG (g_message ("%s: recording assembly: FileName [%s] FileVersionInfo [%d.%d.%d.%d]", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), HIWORD (ffi->dwFileVersionMS), LOWORD (ffi->dwFileVersionMS), HIWORD (ffi->dwFileVersionLS), LOWORD (ffi->dwFileVersionLS)));
317
318                                 process_set_field_int (filever, "filemajorpart", HIWORD (ffi->dwFileVersionMS));
319                                 process_set_field_int (filever, "fileminorpart", LOWORD (ffi->dwFileVersionMS));
320                                 process_set_field_int (filever, "filebuildpart", HIWORD (ffi->dwFileVersionLS));
321                                 process_set_field_int (filever, "fileprivatepart", LOWORD (ffi->dwFileVersionLS));
322
323                                 process_set_field_int (filever, "productmajorpart", HIWORD (ffi->dwProductVersionMS));
324                                 process_set_field_int (filever, "productminorpart", LOWORD (ffi->dwProductVersionMS));
325                                 process_set_field_int (filever, "productbuildpart", HIWORD (ffi->dwProductVersionLS));
326                                 process_set_field_int (filever, "productprivatepart", LOWORD (ffi->dwProductVersionLS));
327
328                                 process_set_field_bool (filever, "isdebug", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_DEBUG) != 0);
329                                 process_set_field_bool (filever, "isprerelease", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PRERELEASE) != 0);
330                                 process_set_field_bool (filever, "ispatched", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PATCHED) != 0);
331                                 process_set_field_bool (filever, "isprivatebuild", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_PRIVATEBUILD) != 0);
332                                 process_set_field_bool (filever, "isspecialbuild", ((ffi->dwFileFlags & ffi->dwFileFlagsMask) & VS_FF_SPECIALBUILD) != 0);
333                         }
334                         g_free (query);
335
336                         query = g_utf8_to_utf16 ("\\VarFileInfo\\Translation", -1, NULL, NULL, NULL);
337                         if (query == NULL) {
338                                 g_free (data);
339                                 return;
340                         }
341
342                         if (VerQueryValue (data, query, (gpointer *)&trans_data, &trans_size)) {
343                                 /* use the first language ID we see */
344                                 if (trans_size >= 4) {
345                                         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]));
346                                         lang = (trans_data[0]) | (trans_data[1] << 8) | (trans_data[2] << 16) | (trans_data[3] << 24);
347                                         /* Only give the lower 16 bits to VerLanguageName, as Windows gets confused otherwise  */
348                                         lang_count = VerLanguageName (lang & 0xFFFF, lang_buf, 128);
349                                         if (lang_count) {
350                                                 process_set_field_string (filever, "language", lang_buf, lang_count, error);
351                                                 return_if_nok (error);
352                                         }
353                                         process_module_stringtable (filever, data, trans_data[0], trans_data[1], error);
354                                         return_if_nok (error);
355                                 }
356                         } else {
357                                 int i;
358
359                                 for (i = 0; i < G_N_ELEMENTS (stringtable_entries); ++i) {
360                                         /* No strings, so set every field to the empty string */
361                                         process_set_field_string (filever, stringtable_entries [i].name, EMPTY_STRING, 0, error);
362                                         return_if_nok (error);
363                                 }
364
365                                 /* And language seems to be set to en_US according to bug 374600 */
366                                 lang_count = VerLanguageName (0x0409, lang_buf, 128);
367                                 if (lang_count) {
368                                         process_set_field_string (filever, "language", lang_buf, lang_count, error);
369                                         return_if_nok (error);
370                                 }
371                         }
372
373                         g_free (query);
374                 }
375                 g_free (data);
376         }
377 }
378
379 #endif /* #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
380
381 void
382 ves_icall_System_Diagnostics_FileVersionInfo_GetVersionInfo_internal (MonoObject *this_obj, MonoString *filename)
383 {
384         MonoError error;
385
386         stash_system_image (mono_object_class (this_obj)->image);
387
388         mono_w32process_get_fileversion (this_obj, mono_string_chars (filename), &error);
389         if (!mono_error_ok (&error)) {
390                 mono_error_set_pending_exception (&error);
391                 return;
392         }
393
394         process_set_field_string (this_obj, "filename", mono_string_chars (filename), mono_string_length (filename), &error);
395         if (!mono_error_ok (&error)) {
396                 mono_error_set_pending_exception (&error);
397         }
398 }
399
400 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
401
402 static GPtrArray*
403 get_domain_assemblies (MonoDomain *domain)
404 {
405         GSList *tmp;
406         GPtrArray *assemblies;
407
408         /*
409          * Make a copy of the list of assemblies because we can't hold the assemblies
410          * lock while creating objects etc.
411          */
412         assemblies = g_ptr_array_new ();
413         mono_domain_assemblies_lock (domain);
414         for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
415                 MonoAssembly *ass = (MonoAssembly *)tmp->data;
416                 if (ass->image->fileio_used)
417                         continue;
418                 g_ptr_array_add (assemblies, ass);
419         }
420         mono_domain_assemblies_unlock (domain);
421
422         return assemblies;
423 }
424
425 static MonoObject*
426 process_add_module (HANDLE process, HMODULE mod, gunichar2 *filename, gunichar2 *modulename, MonoClass *proc_class, MonoError *error)
427 {
428         MonoObject *item, *filever;
429         MonoDomain *domain = mono_domain_get ();
430         MODULEINFO modinfo;
431         BOOL ok;
432
433         mono_error_init (error);
434
435         /* Build a System.Diagnostics.ProcessModule with the data. */
436         item = mono_object_new_checked (domain, proc_class, error);
437         return_val_if_nok (error, NULL);
438
439         filever = mono_object_new_checked (domain, get_file_version_info_class (), error);
440         return_val_if_nok (error, NULL);
441
442         mono_w32process_get_fileversion (filever, filename, error);
443         return_val_if_nok (error, NULL);
444
445         process_set_field_string (filever, "filename", filename, unicode_chars (filename), error);
446         return_val_if_nok (error, NULL);
447
448         ok = mono_w32process_module_get_information (process, mod, &modinfo, sizeof(MODULEINFO));
449         if (ok) {
450                 process_set_field_intptr (item, "baseaddr", modinfo.lpBaseOfDll);
451                 process_set_field_intptr (item, "entryaddr", modinfo.EntryPoint);
452                 process_set_field_int (item, "memory_size", modinfo.SizeOfImage);
453         }
454
455         process_set_field_string (item, "filename", filename, unicode_chars (filename), error);
456         return_val_if_nok (error, NULL);
457
458         process_set_field_string (item, "modulename", modulename, unicode_chars (modulename), error);
459         return_val_if_nok (error, NULL);
460
461         process_set_field_object (item, "version_info", filever);
462
463         return item;
464 }
465
466 static void
467 process_get_assembly_fileversion (MonoObject *filever, MonoAssembly *assembly)
468 {
469         process_set_field_int (filever, "filemajorpart", assembly->aname.major);
470         process_set_field_int (filever, "fileminorpart", assembly->aname.minor);
471         process_set_field_int (filever, "filebuildpart", assembly->aname.build);
472 }
473
474 static MonoObject*
475 process_get_module (MonoAssembly *assembly, MonoClass *proc_class, MonoError *error)
476 {
477         MonoObject *item, *filever;
478         MonoDomain *domain;
479         gchar *filename;
480         const gchar *modulename;
481
482         mono_error_init (error);
483
484         domain = mono_domain_get ();
485
486         modulename = assembly->aname.name;
487
488         /* Build a System.Diagnostics.ProcessModule with the data. */
489         item = mono_object_new_checked (domain, proc_class, error);
490         return_val_if_nok (error, NULL);
491
492         filever = mono_object_new_checked (domain, get_file_version_info_class (), error);
493         return_val_if_nok (error, NULL);
494
495         filename = g_strdup_printf ("[In Memory] %s", modulename);
496
497         process_get_assembly_fileversion (filever, assembly);
498         process_set_field_string_char (filever, "filename", filename);
499         process_set_field_object (item, "version_info", filever);
500
501         process_set_field_intptr (item, "baseaddr", assembly->image->raw_data);
502         process_set_field_int (item, "memory_size", assembly->image->raw_data_len);
503         process_set_field_string_char (item, "filename", filename);
504         process_set_field_string_char (item, "modulename", modulename);
505
506         g_free (filename);
507
508         return item;
509 }
510
511 /* Returns an array of System.Diagnostics.ProcessModule */
512 MonoArray *
513 ves_icall_System_Diagnostics_Process_GetModules_internal (MonoObject *this_obj, HANDLE process)
514 {
515         MonoError error;
516         MonoArray *temp_arr = NULL;
517         MonoArray *arr;
518         HMODULE mods[1024];
519         gunichar2 filename[MAX_PATH];
520         gunichar2 modname[MAX_PATH];
521         DWORD needed;
522         guint32 count = 0, module_count = 0, assembly_count = 0;
523         guint32 i, num_added = 0;
524         GPtrArray *assemblies = NULL;
525
526         stash_system_image (mono_object_class (this_obj)->image);
527
528         if (mono_w32process_get_pid (process) == mono_process_current_pid ()) {
529                 assemblies = get_domain_assemblies (mono_domain_get ());
530                 assembly_count = assemblies->len;
531         }
532
533         if (mono_w32process_try_get_modules (process, mods, sizeof(mods), &needed))
534                 module_count += needed / sizeof(HMODULE);
535
536         count = module_count + assembly_count;
537         temp_arr = mono_array_new_checked (mono_domain_get (), get_process_module_class (), count, &error);
538         if (mono_error_set_pending_exception (&error))
539                 return NULL;
540
541         for (i = 0; i < module_count; i++) {
542                 if (mono_w32process_module_get_name (process, mods[i], modname, MAX_PATH)
543                          && mono_w32process_module_get_filename (process, mods[i], filename, MAX_PATH))
544                 {
545                         MonoObject *module = process_add_module (process, mods[i], filename, modname, get_process_module_class (), &error);
546                         if (!mono_error_ok (&error)) {
547                                 mono_error_set_pending_exception (&error);
548                                 return NULL;
549                         }
550                         mono_array_setref (temp_arr, num_added++, module);
551                 }
552         }
553
554         if (assemblies) {
555                 for (i = 0; i < assembly_count; i++) {
556                         MonoAssembly *ass = (MonoAssembly *)g_ptr_array_index (assemblies, i);
557                         MonoObject *module = process_get_module (ass, get_process_module_class (), &error);
558                         if (!mono_error_ok (&error)) {
559                                 mono_error_set_pending_exception (&error);
560                                 return NULL;
561                         }
562                         mono_array_setref (temp_arr, num_added++, module);
563                 }
564                 g_ptr_array_free (assemblies, TRUE);
565         }
566
567         if (count == num_added) {
568                 arr = temp_arr;
569         } else {
570                 /* shorter version of the array */
571                 arr = mono_array_new_checked (mono_domain_get (), get_process_module_class (), num_added, &error);
572                 if (mono_error_set_pending_exception (&error))
573                         return NULL;
574
575                 for (i = 0; i < num_added; i++)
576                         mono_array_setref (arr, i, mono_array_get (temp_arr, MonoObject*, i));
577         }
578
579         return arr;
580 }
581
582 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
583
584 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
585
586 MonoString *
587 ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process)
588 {
589         MonoError error;
590         MonoString *string;
591         gunichar2 name[MAX_PATH];
592         guint32 len;
593         gboolean ok;
594         HMODULE mod;
595         DWORD needed;
596
597         ok = mono_w32process_try_get_modules (process, &mod, sizeof(mod), &needed);
598         if (!ok)
599                 return NULL;
600
601         len = mono_w32process_module_get_name (process, mod, name, MAX_PATH);
602         if (len == 0)
603                 return NULL;
604
605         string = mono_string_new_utf16_checked (mono_domain_get (), name, len, &error);
606         if (!mono_error_ok (&error))
607                 mono_error_set_pending_exception (&error);
608
609         return string;
610 }
611
612 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
613
614 gint64
615 ves_icall_System_Diagnostics_Process_GetProcessData (int pid, gint32 data_type, gint32 *error)
616 {
617         MonoProcessError perror;
618         guint64 res;
619
620         res = mono_process_get_data_with_error (GINT_TO_POINTER (pid), (MonoProcessData)data_type, &perror);
621         if (error)
622                 *error = perror;
623         return res;
624 }