2 * ICLRMetaHost - discovery and management of available .NET runtimes
4 * Copyright 2010 Vincent Povirk for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/unicode.h"
28 #include "wine/library.h"
41 #include "wine/list.h"
42 #include "mscoree_private.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL( mscoree
);
48 static const struct ICLRRuntimeInfoVtbl CLRRuntimeInfoVtbl
;
50 #define NUM_RUNTIMES 4
52 static struct CLRRuntimeInfo runtimes
[NUM_RUNTIMES
] = {
53 {{&CLRRuntimeInfoVtbl
}, 1, 0, 3705, 0},
54 {{&CLRRuntimeInfoVtbl
}, 1, 1, 4322, 0},
55 {{&CLRRuntimeInfoVtbl
}, 2, 0, 50727, 0},
56 {{&CLRRuntimeInfoVtbl
}, 4, 0, 30319, 0}
59 static CRITICAL_SECTION runtime_list_cs
;
60 static CRITICAL_SECTION_DEBUG runtime_list_cs_debug
=
62 0, 0, &runtime_list_cs
,
63 { &runtime_list_cs_debug
.ProcessLocksList
,
64 &runtime_list_cs_debug
.ProcessLocksList
},
65 0, 0, { (DWORD_PTR
)(__FILE__
": runtime_list_cs") }
67 static CRITICAL_SECTION runtime_list_cs
= { &runtime_list_cs_debug
, -1, 0, 0, 0, 0 };
71 ICLRMetaHost ICLRMetaHost_iface
;
73 RuntimeLoadedCallbackFnPtr callback
;
76 static struct CLRMetaHost GlobalCLRMetaHost
;
78 static HMODULE mono_handle
;
81 static BOOL is_mono_shutdown
;
83 typedef struct _MonoProfilerDesc
*MonoProfilerHandle
;
85 typedef void (CDECL
*MonoProfilerRuntimeShutdownBeginCallback
) (MonoProfiler
*prof
);
87 MonoImage
* (CDECL
*mono_assembly_get_image
)(MonoAssembly
*assembly
);
88 MonoAssembly
* (CDECL
*mono_assembly_load_from
)(MonoImage
*image
, const char *fname
, MonoImageOpenStatus
*status
);
89 MonoAssembly
* (CDECL
*mono_assembly_open
)(const char *filename
, MonoImageOpenStatus
*status
);
90 void (CDECL
*mono_callspec_set_assembly
)(MonoAssembly
*assembly
);
91 MonoClass
* (CDECL
*mono_class_from_mono_type
)(MonoType
*type
);
92 MonoClass
* (CDECL
*mono_class_from_name
)(MonoImage
*image
, const char* name_space
, const char *name
);
93 MonoMethod
* (CDECL
*mono_class_get_method_from_name
)(MonoClass
*klass
, const char *name
, int param_count
);
94 static void (CDECL
*mono_config_parse
)(const char *filename
);
95 MonoAssembly
* (CDECL
*mono_domain_assembly_open
)(MonoDomain
*domain
, const char *name
);
96 MonoDomain
* (CDECL
*mono_domain_get
)(void);
97 MonoDomain
* (CDECL
*mono_domain_get_by_id
)(int id
);
98 BOOL (CDECL
*mono_domain_set
)(MonoDomain
*domain
,BOOL force
);
99 void (CDECL
*mono_domain_set_config
)(MonoDomain
*domain
,const char *base_dir
,const char *config_file_name
);
100 static void (CDECL
*mono_free
)(void *);
101 static MonoImage
* (CDECL
*mono_image_open
)(const char *fname
, MonoImageOpenStatus
*status
);
102 MonoImage
* (CDECL
*mono_image_open_from_module_handle
)(HMODULE module_handle
, char* fname
, UINT has_entry_point
, MonoImageOpenStatus
* status
);
103 static void (CDECL
*mono_install_assembly_preload_hook
)(MonoAssemblyPreLoadFunc func
, void *user_data
);
104 int (CDECL
*mono_jit_exec
)(MonoDomain
*domain
, MonoAssembly
*assembly
, int argc
, char *argv
[]);
105 MonoDomain
* (CDECL
*mono_jit_init_version
)(const char *domain_name
, const char *runtime_version
);
106 static int (CDECL
*mono_jit_set_trace_options
)(const char* options
);
107 void* (CDECL
*mono_marshal_get_vtfixup_ftnptr
)(MonoImage
*image
, DWORD token
, WORD type
);
108 MonoDomain
* (CDECL
*mono_object_get_domain
)(MonoObject
*obj
);
109 MonoMethod
* (CDECL
*mono_object_get_virtual_method
)(MonoObject
*obj
, MonoMethod
*method
);
110 MonoObject
* (CDECL
*mono_object_new
)(MonoDomain
*domain
, MonoClass
*klass
);
111 void* (CDECL
*mono_object_unbox
)(MonoObject
*obj
);
112 static MonoProfilerHandle (CDECL
*mono_profiler_create
)(MonoProfiler
*prof
);
113 static void (CDECL
*mono_profiler_install
)(MonoProfiler
*prof
, MonoProfileFunc shutdown_callback
);
114 static void (CDECL
*mono_profiler_set_runtime_shutdown_begin_callback
)(MonoProfilerHandle handle
, MonoProfilerRuntimeShutdownBeginCallback cb
);
115 MonoType
* (CDECL
*mono_reflection_type_from_name
)(char *name
, MonoImage
*image
);
116 MonoObject
* (CDECL
*mono_runtime_invoke
)(MonoMethod
*method
, void *obj
, void **params
, MonoObject
**exc
);
117 void (CDECL
*mono_runtime_object_init
)(MonoObject
*this_obj
);
118 void (CDECL
*mono_runtime_quit
)(void);
119 static void (CDECL
*mono_set_crash_chaining
)(BOOL chain_signals
);
120 static void (CDECL
*mono_set_dirs
)(const char *assembly_dir
, const char *config_dir
);
121 static void (CDECL
*mono_set_verbose_level
)(DWORD level
);
122 MonoString
* (CDECL
*mono_string_new
)(MonoDomain
*domain
, const char *str
);
123 static char* (CDECL
*mono_stringify_assembly_name
)(MonoAssemblyName
*aname
);
124 MonoThread
* (CDECL
*mono_thread_attach
)(MonoDomain
*domain
);
125 void (CDECL
*mono_thread_manage
)(void);
126 void (CDECL
*mono_trace_set_print_handler
)(MonoPrintCallback callback
);
127 void (CDECL
*mono_trace_set_printerr_handler
)(MonoPrintCallback callback
);
129 static BOOL
get_mono_path(LPWSTR path
);
131 static BOOL
find_mono_dll(LPCWSTR path
, LPWSTR dll_path
);
133 static MonoAssembly
* CDECL
mono_assembly_preload_hook_fn(MonoAssemblyName
*aname
, char **assemblies_path
, void *user_data
);
135 static void CDECL
mono_shutdown_callback_fn(MonoProfiler
*prof
);
137 static void CDECL
mono_print_handler_fn(const char *string
, INT is_stdout
);
139 static MonoImage
* CDECL
image_open_module_handle_dummy(HMODULE module_handle
,
140 char* fname
, UINT has_entry_point
, MonoImageOpenStatus
* status
)
142 return mono_image_open(fname
, status
);
145 static void CDECL
set_crash_chaining_dummy(BOOL crash_chaining
)
149 static void CDECL
set_print_handler_dummy(MonoPrintCallback callback
)
153 static HRESULT
load_mono(LPCWSTR mono_path
)
155 static const WCHAR lib
[] = {'\\','l','i','b',0};
156 static const WCHAR etc
[] = {'\\','e','t','c',0};
157 WCHAR mono_dll_path
[MAX_PATH
+16];
158 WCHAR mono_lib_path
[MAX_PATH
+4], mono_etc_path
[MAX_PATH
+4];
159 char mono_lib_path_a
[MAX_PATH
], mono_etc_path_a
[MAX_PATH
];
161 char trace_setting
[256];
163 char verbose_setting
[256];
165 if (is_mono_shutdown
)
167 ERR("Cannot load Mono after it has been shut down.\n");
173 strcpyW(mono_lib_path
, mono_path
);
174 strcatW(mono_lib_path
, lib
);
175 WideCharToMultiByte(CP_UTF8
, 0, mono_lib_path
, -1, mono_lib_path_a
, MAX_PATH
, NULL
, NULL
);
177 strcpyW(mono_etc_path
, mono_path
);
178 strcatW(mono_etc_path
, etc
);
179 WideCharToMultiByte(CP_UTF8
, 0, mono_etc_path
, -1, mono_etc_path_a
, MAX_PATH
, NULL
, NULL
);
181 if (!find_mono_dll(mono_path
, mono_dll_path
)) goto fail
;
183 mono_handle
= LoadLibraryW(mono_dll_path
);
185 if (!mono_handle
) goto fail
;
187 #define LOAD_MONO_FUNCTION(x) do { \
188 x = (void*)GetProcAddress(mono_handle, #x); \
194 LOAD_MONO_FUNCTION(mono_assembly_get_image
);
195 LOAD_MONO_FUNCTION(mono_assembly_load_from
);
196 LOAD_MONO_FUNCTION(mono_assembly_open
);
197 LOAD_MONO_FUNCTION(mono_config_parse
);
198 LOAD_MONO_FUNCTION(mono_class_from_mono_type
);
199 LOAD_MONO_FUNCTION(mono_class_from_name
);
200 LOAD_MONO_FUNCTION(mono_class_get_method_from_name
);
201 LOAD_MONO_FUNCTION(mono_domain_assembly_open
);
202 LOAD_MONO_FUNCTION(mono_domain_get
);
203 LOAD_MONO_FUNCTION(mono_domain_get_by_id
);
204 LOAD_MONO_FUNCTION(mono_domain_set
);
205 LOAD_MONO_FUNCTION(mono_domain_set_config
);
206 LOAD_MONO_FUNCTION(mono_free
);
207 LOAD_MONO_FUNCTION(mono_image_open
);
208 LOAD_MONO_FUNCTION(mono_install_assembly_preload_hook
);
209 LOAD_MONO_FUNCTION(mono_jit_exec
);
210 LOAD_MONO_FUNCTION(mono_jit_init_version
);
211 LOAD_MONO_FUNCTION(mono_jit_set_trace_options
);
212 LOAD_MONO_FUNCTION(mono_marshal_get_vtfixup_ftnptr
);
213 LOAD_MONO_FUNCTION(mono_object_get_domain
);
214 LOAD_MONO_FUNCTION(mono_object_get_virtual_method
);
215 LOAD_MONO_FUNCTION(mono_object_new
);
216 LOAD_MONO_FUNCTION(mono_object_unbox
);
217 LOAD_MONO_FUNCTION(mono_reflection_type_from_name
);
218 LOAD_MONO_FUNCTION(mono_runtime_invoke
);
219 LOAD_MONO_FUNCTION(mono_runtime_object_init
);
220 LOAD_MONO_FUNCTION(mono_runtime_quit
);
221 LOAD_MONO_FUNCTION(mono_set_dirs
);
222 LOAD_MONO_FUNCTION(mono_set_verbose_level
);
223 LOAD_MONO_FUNCTION(mono_stringify_assembly_name
);
224 LOAD_MONO_FUNCTION(mono_string_new
);
225 LOAD_MONO_FUNCTION(mono_thread_attach
);
226 LOAD_MONO_FUNCTION(mono_thread_manage
);
228 #undef LOAD_MONO_FUNCTION
230 #define LOAD_OPT_MONO_FUNCTION(x, default) do { \
231 x = (void*)GetProcAddress(mono_handle, #x); \
237 LOAD_OPT_MONO_FUNCTION(mono_callspec_set_assembly
, NULL
);
238 LOAD_OPT_MONO_FUNCTION(mono_image_open_from_module_handle
, image_open_module_handle_dummy
);
239 LOAD_OPT_MONO_FUNCTION(mono_profiler_create
, NULL
);
240 LOAD_OPT_MONO_FUNCTION(mono_profiler_install
, NULL
);
241 LOAD_OPT_MONO_FUNCTION(mono_profiler_set_runtime_shutdown_begin_callback
, NULL
);
242 LOAD_OPT_MONO_FUNCTION(mono_set_crash_chaining
, set_crash_chaining_dummy
);
243 LOAD_OPT_MONO_FUNCTION(mono_trace_set_print_handler
, set_print_handler_dummy
);
244 LOAD_OPT_MONO_FUNCTION(mono_trace_set_printerr_handler
, set_print_handler_dummy
);
246 #undef LOAD_OPT_MONO_FUNCTION
248 if (mono_callspec_set_assembly
== NULL
)
250 mono_callspec_set_assembly
= (void*)GetProcAddress(mono_handle
, "mono_trace_set_assembly");
251 if (!mono_callspec_set_assembly
) goto fail
;
254 if (mono_profiler_create
!= NULL
)
256 /* Profiler API v2 */
257 MonoProfilerHandle handle
= mono_profiler_create(NULL
);
258 mono_profiler_set_runtime_shutdown_begin_callback(handle
, mono_shutdown_callback_fn
);
260 else if (mono_profiler_install
!= NULL
)
262 /* Profiler API v1 */
263 mono_profiler_install(NULL
, mono_shutdown_callback_fn
);
266 mono_set_crash_chaining(TRUE
);
268 mono_trace_set_print_handler(mono_print_handler_fn
);
269 mono_trace_set_printerr_handler(mono_print_handler_fn
);
271 mono_set_dirs(mono_lib_path_a
, mono_etc_path_a
);
273 mono_config_parse(NULL
);
275 mono_install_assembly_preload_hook(mono_assembly_preload_hook_fn
, NULL
);
277 trace_size
= GetEnvironmentVariableA("WINE_MONO_TRACE", trace_setting
, sizeof(trace_setting
));
281 mono_jit_set_trace_options(trace_setting
);
284 verbose_size
= GetEnvironmentVariableA("WINE_MONO_VERBOSE", verbose_setting
, sizeof(verbose_setting
));
288 mono_set_verbose_level(verbose_setting
[0] - '0');
295 ERR("Could not load Mono into this process\n");
296 FreeLibrary(mono_handle
);
301 static void CDECL
mono_shutdown_callback_fn(MonoProfiler
*prof
)
303 is_mono_shutdown
= TRUE
;
306 static void CDECL
mono_print_handler_fn(const char *string
, INT is_stdout
)
309 for (; *string
; string
= p
)
311 if ((p
= strstr(string
, "\n"))) p
++;
312 else p
= string
+ strlen(string
);
313 wine_dbg_printf("%.*s", (int)(p
- string
), string
);
317 static HRESULT WINAPI
thread_set_fn(void)
323 static HRESULT WINAPI
thread_unset_fn(void)
329 static HRESULT
CLRRuntimeInfo_GetRuntimeHost(CLRRuntimeInfo
*This
, RuntimeHost
**result
)
332 WCHAR mono_path
[MAX_PATH
];
334 if (This
->loaded_runtime
)
336 *result
= This
->loaded_runtime
;
340 if (!get_mono_path(mono_path
))
342 ERR("Wine Mono is not installed\n");
343 return CLR_E_SHIM_RUNTIME
;
346 EnterCriticalSection(&runtime_list_cs
);
348 if (This
->loaded_runtime
)
350 *result
= This
->loaded_runtime
;
351 LeaveCriticalSection(&runtime_list_cs
);
355 if (GlobalCLRMetaHost
.callback
)
357 GlobalCLRMetaHost
.callback(&This
->ICLRRuntimeInfo_iface
, thread_set_fn
, thread_unset_fn
);
360 hr
= load_mono(mono_path
);
363 hr
= RuntimeHost_Construct(This
, &This
->loaded_runtime
);
365 LeaveCriticalSection(&runtime_list_cs
);
368 *result
= This
->loaded_runtime
;
373 void expect_no_runtimes(void)
375 if (mono_handle
&& is_mono_started
&& !is_mono_shutdown
)
377 ERR("Process exited with a Mono runtime loaded.\n");
382 static inline CLRRuntimeInfo
*impl_from_ICLRRuntimeInfo(ICLRRuntimeInfo
*iface
)
384 return CONTAINING_RECORD(iface
, CLRRuntimeInfo
, ICLRRuntimeInfo_iface
);
387 static HRESULT WINAPI
CLRRuntimeInfo_QueryInterface(ICLRRuntimeInfo
* iface
,
391 TRACE("%p %s %p\n", iface
, debugstr_guid(riid
), ppvObject
);
393 if ( IsEqualGUID( riid
, &IID_ICLRRuntimeInfo
) ||
394 IsEqualGUID( riid
, &IID_IUnknown
) )
400 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
401 return E_NOINTERFACE
;
404 ICLRRuntimeInfo_AddRef( iface
);
409 static ULONG WINAPI
CLRRuntimeInfo_AddRef(ICLRRuntimeInfo
* iface
)
414 static ULONG WINAPI
CLRRuntimeInfo_Release(ICLRRuntimeInfo
* iface
)
419 static HRESULT WINAPI
CLRRuntimeInfo_GetVersionString(ICLRRuntimeInfo
* iface
,
420 LPWSTR pwzBuffer
, DWORD
*pcchBuffer
)
422 struct CLRRuntimeInfo
*This
= impl_from_ICLRRuntimeInfo(iface
);
423 DWORD buffer_size
= *pcchBuffer
;
428 TRACE("%p %p %p\n", iface
, pwzBuffer
, pcchBuffer
);
430 size
= snprintf(version
, sizeof(version
), "v%u.%u.%u", This
->major
, This
->minor
, This
->build
);
432 assert(size
<= sizeof(version
));
434 *pcchBuffer
= MultiByteToWideChar(CP_UTF8
, 0, version
, -1, NULL
, 0);
438 if (buffer_size
>= *pcchBuffer
)
439 MultiByteToWideChar(CP_UTF8
, 0, version
, -1, pwzBuffer
, buffer_size
);
441 hr
= E_NOT_SUFFICIENT_BUFFER
;
447 static BOOL
get_install_root(LPWSTR install_dir
)
449 const WCHAR dotnet_key
[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\','.','N','E','T','F','r','a','m','e','w','o','r','k','\\',0};
450 const WCHAR install_root
[] = {'I','n','s','t','a','l','l','R','o','o','t',0};
455 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, dotnet_key
, 0, KEY_READ
, &key
))
459 if (RegQueryValueExW(key
, install_root
, 0, NULL
, (LPBYTE
)install_dir
, &len
))
469 static HRESULT WINAPI
CLRRuntimeInfo_GetRuntimeDirectory(ICLRRuntimeInfo
* iface
,
470 LPWSTR pwzBuffer
, DWORD
*pcchBuffer
)
472 static const WCHAR slash
[] = {'\\',0};
473 DWORD buffer_size
= *pcchBuffer
;
474 WCHAR system_dir
[MAX_PATH
];
475 WCHAR version
[MAX_PATH
];
476 DWORD version_size
, size
;
479 TRACE("%p %p %p\n", iface
, pwzBuffer
, pcchBuffer
);
481 if (!get_install_root(system_dir
))
483 ERR("error reading registry key for installroot\n");
488 version_size
= MAX_PATH
;
489 ICLRRuntimeInfo_GetVersionString(iface
, version
, &version_size
);
490 lstrcatW(system_dir
, version
);
491 lstrcatW(system_dir
, slash
);
492 size
= lstrlenW(system_dir
) + 1;
499 if (buffer_size
>= size
)
500 strcpyW(pwzBuffer
, system_dir
);
502 hr
= E_NOT_SUFFICIENT_BUFFER
;
508 static HRESULT WINAPI
CLRRuntimeInfo_IsLoaded(ICLRRuntimeInfo
* iface
,
509 HANDLE hndProcess
, BOOL
*pbLoaded
)
511 FIXME("%p %p %p\n", iface
, hndProcess
, pbLoaded
);
516 static HRESULT WINAPI
CLRRuntimeInfo_LoadErrorString(ICLRRuntimeInfo
* iface
,
517 UINT iResourceID
, LPWSTR pwzBuffer
, DWORD
*pcchBuffer
, LONG iLocaleid
)
519 FIXME("%p %u %p %p %x\n", iface
, iResourceID
, pwzBuffer
, pcchBuffer
, iLocaleid
);
524 static HRESULT WINAPI
CLRRuntimeInfo_LoadLibrary(ICLRRuntimeInfo
* iface
,
525 LPCWSTR pwzDllName
, HMODULE
*phndModule
)
527 WCHAR version
[MAX_PATH
];
531 TRACE("%p %s %p\n", iface
, debugstr_w(pwzDllName
), phndModule
);
533 cchBuffer
= MAX_PATH
;
534 hr
= ICLRRuntimeInfo_GetVersionString(iface
, version
, &cchBuffer
);
535 if (FAILED(hr
)) return hr
;
537 return LoadLibraryShim(pwzDllName
, version
, NULL
, phndModule
);
540 static HRESULT WINAPI
CLRRuntimeInfo_GetProcAddress(ICLRRuntimeInfo
* iface
,
541 LPCSTR pszProcName
, LPVOID
*ppProc
)
543 FIXME("%p %s %p\n", iface
, debugstr_a(pszProcName
), ppProc
);
548 static HRESULT WINAPI
CLRRuntimeInfo_GetInterface(ICLRRuntimeInfo
* iface
,
549 REFCLSID rclsid
, REFIID riid
, LPVOID
*ppUnk
)
551 struct CLRRuntimeInfo
*This
= impl_from_ICLRRuntimeInfo(iface
);
555 TRACE("%p %s %s %p\n", iface
, debugstr_guid(rclsid
), debugstr_guid(riid
), ppUnk
);
557 hr
= CLRRuntimeInfo_GetRuntimeHost(This
, &host
);
560 hr
= RuntimeHost_GetInterface(host
, rclsid
, riid
, ppUnk
);
565 static HRESULT WINAPI
CLRRuntimeInfo_IsLoadable(ICLRRuntimeInfo
* iface
,
568 FIXME("%p %p\n", iface
, pbLoadable
);
573 static HRESULT WINAPI
CLRRuntimeInfo_SetDefaultStartupFlags(ICLRRuntimeInfo
* iface
,
574 DWORD dwStartupFlags
, LPCWSTR pwzHostConfigFile
)
576 FIXME("%p %x %s\n", iface
, dwStartupFlags
, debugstr_w(pwzHostConfigFile
));
581 static HRESULT WINAPI
CLRRuntimeInfo_GetDefaultStartupFlags(ICLRRuntimeInfo
* iface
,
582 DWORD
*pdwStartupFlags
, LPWSTR pwzHostConfigFile
, DWORD
*pcchHostConfigFile
)
584 FIXME("%p %p %p %p\n", iface
, pdwStartupFlags
, pwzHostConfigFile
, pcchHostConfigFile
);
589 static HRESULT WINAPI
CLRRuntimeInfo_BindAsLegacyV2Runtime(ICLRRuntimeInfo
* iface
)
591 FIXME("%p\n", iface
);
596 static HRESULT WINAPI
CLRRuntimeInfo_IsStarted(ICLRRuntimeInfo
* iface
,
597 BOOL
*pbStarted
, DWORD
*pdwStartupFlags
)
599 FIXME("%p %p %p\n", iface
, pbStarted
, pdwStartupFlags
);
604 static const struct ICLRRuntimeInfoVtbl CLRRuntimeInfoVtbl
= {
605 CLRRuntimeInfo_QueryInterface
,
606 CLRRuntimeInfo_AddRef
,
607 CLRRuntimeInfo_Release
,
608 CLRRuntimeInfo_GetVersionString
,
609 CLRRuntimeInfo_GetRuntimeDirectory
,
610 CLRRuntimeInfo_IsLoaded
,
611 CLRRuntimeInfo_LoadErrorString
,
612 CLRRuntimeInfo_LoadLibrary
,
613 CLRRuntimeInfo_GetProcAddress
,
614 CLRRuntimeInfo_GetInterface
,
615 CLRRuntimeInfo_IsLoadable
,
616 CLRRuntimeInfo_SetDefaultStartupFlags
,
617 CLRRuntimeInfo_GetDefaultStartupFlags
,
618 CLRRuntimeInfo_BindAsLegacyV2Runtime
,
619 CLRRuntimeInfo_IsStarted
622 HRESULT
ICLRRuntimeInfo_GetRuntimeHost(ICLRRuntimeInfo
*iface
, RuntimeHost
**result
)
624 struct CLRRuntimeInfo
*This
= impl_from_ICLRRuntimeInfo(iface
);
626 assert(This
->ICLRRuntimeInfo_iface
.lpVtbl
== &CLRRuntimeInfoVtbl
);
628 return CLRRuntimeInfo_GetRuntimeHost(This
, result
);
632 static const WCHAR libmono2_arch_dll
[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','-','x','8','6','.','d','l','l',0};
633 #elif defined(__x86_64__)
634 static const WCHAR libmono2_arch_dll
[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','-','x','8','6','_','6','4','.','d','l','l',0};
636 static const WCHAR libmono2_arch_dll
[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','.','d','l','l',0};
639 static BOOL
find_mono_dll(LPCWSTR path
, LPWSTR dll_path
)
641 static const WCHAR mono2_dll
[] = {'\\','b','i','n','\\','m','o','n','o','-','2','.','0','.','d','l','l',0};
642 static const WCHAR libmono2_dll
[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','.','d','l','l',0};
643 DWORD attributes
=INVALID_FILE_ATTRIBUTES
;
645 strcpyW(dll_path
, path
);
646 strcatW(dll_path
, libmono2_arch_dll
);
647 attributes
= GetFileAttributesW(dll_path
);
649 if (attributes
== INVALID_FILE_ATTRIBUTES
)
651 strcpyW(dll_path
, path
);
652 strcatW(dll_path
, mono2_dll
);
653 attributes
= GetFileAttributesW(dll_path
);
656 if (attributes
== INVALID_FILE_ATTRIBUTES
)
658 strcpyW(dll_path
, path
);
659 strcatW(dll_path
, libmono2_dll
);
660 attributes
= GetFileAttributesW(dll_path
);
663 return (attributes
!= INVALID_FILE_ATTRIBUTES
);
666 static BOOL
get_mono_path(LPWSTR path
)
668 static const WCHAR subdir_mono
[] = {'\\','m','o','n','o','\\','m','o','n','o','-','2','.','0', 0};
669 WCHAR base_path
[MAX_PATH
], mono_dll_path
[MAX_PATH
];
671 /* c:\windows\mono\mono-2.0 */
672 GetWindowsDirectoryW(base_path
, MAX_PATH
);
673 strcatW(base_path
, subdir_mono
);
675 if (find_mono_dll(base_path
, mono_dll_path
))
677 strcpyW(path
, base_path
);
684 struct InstalledRuntimeEnum
686 IEnumUnknown IEnumUnknown_iface
;
691 static const struct IEnumUnknownVtbl InstalledRuntimeEnum_Vtbl
;
693 static inline struct InstalledRuntimeEnum
*impl_from_IEnumUnknown(IEnumUnknown
*iface
)
695 return CONTAINING_RECORD(iface
, struct InstalledRuntimeEnum
, IEnumUnknown_iface
);
698 static HRESULT WINAPI
InstalledRuntimeEnum_QueryInterface(IEnumUnknown
* iface
, REFIID riid
,
701 TRACE("%p %s %p\n", iface
, debugstr_guid(riid
), ppvObject
);
703 if ( IsEqualGUID( riid
, &IID_IEnumUnknown
) ||
704 IsEqualGUID( riid
, &IID_IUnknown
) )
710 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
711 return E_NOINTERFACE
;
714 IEnumUnknown_AddRef( iface
);
719 static ULONG WINAPI
InstalledRuntimeEnum_AddRef(IEnumUnknown
* iface
)
721 struct InstalledRuntimeEnum
*This
= impl_from_IEnumUnknown(iface
);
722 ULONG ref
= InterlockedIncrement(&This
->ref
);
724 TRACE("(%p) refcount=%u\n", iface
, ref
);
729 static ULONG WINAPI
InstalledRuntimeEnum_Release(IEnumUnknown
* iface
)
731 struct InstalledRuntimeEnum
*This
= impl_from_IEnumUnknown(iface
);
732 ULONG ref
= InterlockedDecrement(&This
->ref
);
734 TRACE("(%p) refcount=%u\n", iface
, ref
);
738 HeapFree(GetProcessHeap(), 0, This
);
744 static HRESULT WINAPI
InstalledRuntimeEnum_Next(IEnumUnknown
*iface
, ULONG celt
,
745 IUnknown
**rgelt
, ULONG
*pceltFetched
)
747 struct InstalledRuntimeEnum
*This
= impl_from_IEnumUnknown(iface
);
748 ULONG num_fetched
= 0;
752 TRACE("(%p,%u,%p,%p)\n", iface
, celt
, rgelt
, pceltFetched
);
754 while (num_fetched
< celt
)
756 if (This
->pos
>= NUM_RUNTIMES
)
761 item
= (IUnknown
*)&runtimes
[This
->pos
].ICLRRuntimeInfo_iface
;
762 IUnknown_AddRef(item
);
763 rgelt
[num_fetched
] = item
;
769 *pceltFetched
= num_fetched
;
774 static HRESULT WINAPI
InstalledRuntimeEnum_Skip(IEnumUnknown
*iface
, ULONG celt
)
776 struct InstalledRuntimeEnum
*This
= impl_from_IEnumUnknown(iface
);
777 ULONG num_fetched
= 0;
780 TRACE("(%p,%u)\n", iface
, celt
);
782 while (num_fetched
< celt
)
784 if (This
->pos
>= NUM_RUNTIMES
)
796 static HRESULT WINAPI
InstalledRuntimeEnum_Reset(IEnumUnknown
*iface
)
798 struct InstalledRuntimeEnum
*This
= impl_from_IEnumUnknown(iface
);
800 TRACE("(%p)\n", iface
);
807 static HRESULT WINAPI
InstalledRuntimeEnum_Clone(IEnumUnknown
*iface
, IEnumUnknown
**ppenum
)
809 struct InstalledRuntimeEnum
*This
= impl_from_IEnumUnknown(iface
);
810 struct InstalledRuntimeEnum
*new_enum
;
812 TRACE("(%p)\n", iface
);
814 new_enum
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_enum
));
816 return E_OUTOFMEMORY
;
818 new_enum
->IEnumUnknown_iface
.lpVtbl
= &InstalledRuntimeEnum_Vtbl
;
820 new_enum
->pos
= This
->pos
;
822 *ppenum
= &new_enum
->IEnumUnknown_iface
;
827 static const struct IEnumUnknownVtbl InstalledRuntimeEnum_Vtbl
= {
828 InstalledRuntimeEnum_QueryInterface
,
829 InstalledRuntimeEnum_AddRef
,
830 InstalledRuntimeEnum_Release
,
831 InstalledRuntimeEnum_Next
,
832 InstalledRuntimeEnum_Skip
,
833 InstalledRuntimeEnum_Reset
,
834 InstalledRuntimeEnum_Clone
837 static HRESULT WINAPI
CLRMetaHost_QueryInterface(ICLRMetaHost
* iface
,
841 TRACE("%s %p\n", debugstr_guid(riid
), ppvObject
);
843 if ( IsEqualGUID( riid
, &IID_ICLRMetaHost
) ||
844 IsEqualGUID( riid
, &IID_IUnknown
) )
850 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
851 return E_NOINTERFACE
;
854 ICLRMetaHost_AddRef( iface
);
859 static ULONG WINAPI
CLRMetaHost_AddRef(ICLRMetaHost
* iface
)
864 static ULONG WINAPI
CLRMetaHost_Release(ICLRMetaHost
* iface
)
869 static inline BOOL
isDigit(WCHAR c
)
871 return c
>= '0' && c
<= '9';
874 static BOOL
parse_runtime_version(LPCWSTR version
, DWORD
*major
, DWORD
*minor
, DWORD
*build
)
880 if (version
[0] == 'v' || version
[0] == 'V')
883 if (!isDigit(*version
))
886 while (isDigit(*version
))
887 *major
= *major
* 10 + (*version
++ - '0');
892 if (*version
++ != '.' || !isDigit(*version
))
895 while (isDigit(*version
))
896 *minor
= *minor
* 10 + (*version
++ - '0');
901 if (*version
++ != '.' || !isDigit(*version
))
904 while (isDigit(*version
))
905 *build
= *build
* 10 + (*version
++ - '0');
907 return *version
== 0;
913 static HRESULT
get_runtime(LPCWSTR pwzVersion
, BOOL allow_short
,
914 REFIID iid
, LPVOID
*ppRuntime
)
917 DWORD major
, minor
, build
;
922 if (!parse_runtime_version(pwzVersion
, &major
, &minor
, &build
))
924 ERR("Cannot parse %s\n", debugstr_w(pwzVersion
));
925 return CLR_E_SHIM_RUNTIME
;
928 for (i
=0; i
<NUM_RUNTIMES
; i
++)
930 if (runtimes
[i
].major
== major
&& runtimes
[i
].minor
== minor
&&
931 (runtimes
[i
].build
== build
|| (allow_short
&& major
>= 4 && build
== 0)))
933 return ICLRRuntimeInfo_QueryInterface(&runtimes
[i
].ICLRRuntimeInfo_iface
, iid
,
938 FIXME("Unrecognized version %s\n", debugstr_w(pwzVersion
));
939 return CLR_E_SHIM_RUNTIME
;
942 HRESULT WINAPI
CLRMetaHost_GetRuntime(ICLRMetaHost
* iface
,
943 LPCWSTR pwzVersion
, REFIID iid
, LPVOID
*ppRuntime
)
945 TRACE("%s %s %p\n", debugstr_w(pwzVersion
), debugstr_guid(iid
), ppRuntime
);
947 return get_runtime(pwzVersion
, FALSE
, iid
, ppRuntime
);
950 HRESULT WINAPI
CLRMetaHost_GetVersionFromFile(ICLRMetaHost
* iface
,
951 LPCWSTR pwzFilePath
, LPWSTR pwzBuffer
, DWORD
*pcchBuffer
)
956 ULONG buffer_size
=*pcchBuffer
;
958 TRACE("%s %p %p\n", debugstr_w(pwzFilePath
), pwzBuffer
, pcchBuffer
);
960 hr
= assembly_create(&assembly
, pwzFilePath
);
964 hr
= assembly_get_runtime_version(assembly
, &version
);
968 *pcchBuffer
= MultiByteToWideChar(CP_UTF8
, 0, version
, -1, NULL
, 0);
972 if (buffer_size
>= *pcchBuffer
)
973 MultiByteToWideChar(CP_UTF8
, 0, version
, -1, pwzBuffer
, buffer_size
);
975 hr
= E_NOT_SUFFICIENT_BUFFER
;
979 assembly_release(assembly
);
985 static HRESULT WINAPI
CLRMetaHost_EnumerateInstalledRuntimes(ICLRMetaHost
* iface
,
986 IEnumUnknown
**ppEnumerator
)
988 struct InstalledRuntimeEnum
*new_enum
;
990 TRACE("%p\n", ppEnumerator
);
992 new_enum
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_enum
));
994 return E_OUTOFMEMORY
;
996 new_enum
->IEnumUnknown_iface
.lpVtbl
= &InstalledRuntimeEnum_Vtbl
;
1000 *ppEnumerator
= &new_enum
->IEnumUnknown_iface
;
1005 static HRESULT WINAPI
CLRMetaHost_EnumerateLoadedRuntimes(ICLRMetaHost
* iface
,
1006 HANDLE hndProcess
, IEnumUnknown
**ppEnumerator
)
1008 FIXME("%p %p\n", hndProcess
, ppEnumerator
);
1013 static HRESULT WINAPI
CLRMetaHost_RequestRuntimeLoadedNotification(ICLRMetaHost
* iface
,
1014 RuntimeLoadedCallbackFnPtr pCallbackFunction
)
1016 TRACE("%p\n", pCallbackFunction
);
1018 if(!pCallbackFunction
)
1021 if (GlobalCLRMetaHost
.callback
)
1022 return HOST_E_INVALIDOPERATION
;
1024 GlobalCLRMetaHost
.callback
= pCallbackFunction
;
1029 static HRESULT WINAPI
CLRMetaHost_QueryLegacyV2RuntimeBinding(ICLRMetaHost
* iface
,
1030 REFIID riid
, LPVOID
*ppUnk
)
1032 FIXME("%s %p\n", debugstr_guid(riid
), ppUnk
);
1037 HRESULT WINAPI
CLRMetaHost_ExitProcess(ICLRMetaHost
* iface
, INT32 iExitCode
)
1039 TRACE("%i\n", iExitCode
);
1041 EnterCriticalSection(&runtime_list_cs
);
1043 if (is_mono_started
&& !is_mono_shutdown
)
1045 /* search for a runtime and call System.Environment.Exit() */
1048 for (i
=0; i
<NUM_RUNTIMES
; i
++)
1049 if (runtimes
[i
].loaded_runtime
)
1050 RuntimeHost_ExitProcess(runtimes
[i
].loaded_runtime
, iExitCode
);
1053 ExitProcess(iExitCode
);
1056 static const struct ICLRMetaHostVtbl CLRMetaHost_vtbl
=
1058 CLRMetaHost_QueryInterface
,
1060 CLRMetaHost_Release
,
1061 CLRMetaHost_GetRuntime
,
1062 CLRMetaHost_GetVersionFromFile
,
1063 CLRMetaHost_EnumerateInstalledRuntimes
,
1064 CLRMetaHost_EnumerateLoadedRuntimes
,
1065 CLRMetaHost_RequestRuntimeLoadedNotification
,
1066 CLRMetaHost_QueryLegacyV2RuntimeBinding
,
1067 CLRMetaHost_ExitProcess
1070 static struct CLRMetaHost GlobalCLRMetaHost
= {
1071 { &CLRMetaHost_vtbl
}
1074 HRESULT
CLRMetaHost_CreateInstance(REFIID riid
, void **ppobj
)
1076 return ICLRMetaHost_QueryInterface(&GlobalCLRMetaHost
.ICLRMetaHost_iface
, riid
, ppobj
);
1079 struct CLRMetaHostPolicy
1081 ICLRMetaHostPolicy ICLRMetaHostPolicy_iface
;
1084 static struct CLRMetaHostPolicy GlobalCLRMetaHostPolicy
;
1086 static HRESULT WINAPI
metahostpolicy_QueryInterface(ICLRMetaHostPolicy
*iface
, REFIID riid
, void **obj
)
1088 TRACE("%s %p\n", debugstr_guid(riid
), obj
);
1090 if ( IsEqualGUID( riid
, &IID_ICLRMetaHostPolicy
) ||
1091 IsEqualGUID( riid
, &IID_IUnknown
) )
1093 ICLRMetaHostPolicy_AddRef( iface
);
1098 FIXME("Unsupported interface %s\n", debugstr_guid(riid
));
1101 return E_NOINTERFACE
;
1104 static ULONG WINAPI
metahostpolicy_AddRef(ICLRMetaHostPolicy
*iface
)
1109 static ULONG WINAPI
metahostpolicy_Release(ICLRMetaHostPolicy
*iface
)
1114 static HRESULT WINAPI
metahostpolicy_GetRequestedRuntime(ICLRMetaHostPolicy
*iface
, METAHOST_POLICY_FLAGS dwPolicyFlags
,
1115 LPCWSTR pwzBinary
, IStream
*pCfgStream
, LPWSTR pwzVersion
, DWORD
*pcchVersion
,
1116 LPWSTR pwzImageVersion
, DWORD
*pcchImageVersion
, DWORD
*pdwConfigFlags
, REFIID riid
,
1119 ICLRRuntimeInfo
*result
;
1121 WCHAR filename
[MAX_PATH
];
1122 const WCHAR
*path
= NULL
;
1125 TRACE("%d %p %p %p %p %p %p %p %s %p\n", dwPolicyFlags
, pwzBinary
, pCfgStream
,
1126 pwzVersion
, pcchVersion
, pwzImageVersion
, pcchImageVersion
, pdwConfigFlags
,
1127 debugstr_guid(riid
), ppRuntime
);
1130 FIXME("ignoring config file stream\n");
1133 FIXME("ignoring config flags\n");
1135 if(dwPolicyFlags
& METAHOST_POLICY_USE_PROCESS_IMAGE_PATH
)
1137 GetModuleFileNameW(0, filename
, MAX_PATH
);
1145 if(dwPolicyFlags
& METAHOST_POLICY_APPLY_UPGRADE_POLICY
)
1146 flags
|= RUNTIME_INFO_UPGRADE_VERSION
;
1148 hr
= get_runtime_info(path
, pwzImageVersion
, NULL
, 0, flags
, FALSE
, &result
);
1151 if (pwzImageVersion
)
1153 /* Ignoring errors on purpose */
1154 ICLRRuntimeInfo_GetVersionString(result
, pwzImageVersion
, pcchImageVersion
);
1157 hr
= ICLRRuntimeInfo_QueryInterface(result
, riid
, ppRuntime
);
1159 ICLRRuntimeInfo_Release(result
);
1162 TRACE("<- 0x%08x\n", hr
);
1167 static const struct ICLRMetaHostPolicyVtbl CLRMetaHostPolicy_vtbl
=
1169 metahostpolicy_QueryInterface
,
1170 metahostpolicy_AddRef
,
1171 metahostpolicy_Release
,
1172 metahostpolicy_GetRequestedRuntime
1175 static struct CLRMetaHostPolicy GlobalCLRMetaHostPolicy
= {
1176 { &CLRMetaHostPolicy_vtbl
}
1179 HRESULT
CLRMetaHostPolicy_CreateInstance(REFIID riid
, void **ppobj
)
1181 return ICLRMetaHostPolicy_QueryInterface(&GlobalCLRMetaHostPolicy
.ICLRMetaHostPolicy_iface
, riid
, ppobj
);
1184 HRESULT
get_file_from_strongname(WCHAR
* stringnameW
, WCHAR
* assemblies_path
, int path_length
)
1187 IAssemblyCache
*asmcache
;
1189 static const WCHAR fusiondll
[] = {'f','u','s','i','o','n',0};
1190 HMODULE hfusion
=NULL
;
1191 static HRESULT (WINAPI
*pCreateAssemblyCache
)(IAssemblyCache
**,DWORD
);
1193 if (!pCreateAssemblyCache
)
1195 hr
= LoadLibraryShim(fusiondll
, NULL
, NULL
, &hfusion
);
1199 pCreateAssemblyCache
= (void*)GetProcAddress(hfusion
, "CreateAssemblyCache");
1200 if (!pCreateAssemblyCache
)
1206 hr
= pCreateAssemblyCache(&asmcache
, 0);
1210 info
.cbAssemblyInfo
= sizeof(info
);
1211 info
.pszCurrentAssemblyPathBuf
= assemblies_path
;
1212 info
.cchBuf
= path_length
;
1213 assemblies_path
[0] = 0;
1215 hr
= IAssemblyCache_QueryAssemblyInfo(asmcache
, 0, stringnameW
, &info
);
1217 IAssemblyCache_Release(asmcache
);
1223 static MonoAssembly
* CDECL
mono_assembly_preload_hook_fn(MonoAssemblyName
*aname
, char **assemblies_path
, void *user_data
)
1226 MonoAssembly
*result
=NULL
;
1227 char *stringname
=NULL
;
1229 int stringnameW_size
;
1230 WCHAR path
[MAX_PATH
];
1232 MonoImageOpenStatus stat
;
1234 stringname
= mono_stringify_assembly_name(aname
);
1236 TRACE("%s\n", debugstr_a(stringname
));
1238 if (!stringname
) return NULL
;
1240 /* FIXME: We should search the given paths before the GAC. */
1242 stringnameW_size
= MultiByteToWideChar(CP_UTF8
, 0, stringname
, -1, NULL
, 0);
1244 stringnameW
= HeapAlloc(GetProcessHeap(), 0, stringnameW_size
* sizeof(WCHAR
));
1247 MultiByteToWideChar(CP_UTF8
, 0, stringname
, -1, stringnameW
, stringnameW_size
);
1249 hr
= get_file_from_strongname(stringnameW
, path
, MAX_PATH
);
1251 HeapFree(GetProcessHeap(), 0, stringnameW
);
1258 TRACE("found: %s\n", debugstr_w(path
));
1264 result
= mono_assembly_open(pathA
, &stat
);
1267 ERR("Failed to load %s, status=%u\n", debugstr_w(path
), stat
);
1269 HeapFree(GetProcessHeap(), 0, pathA
);
1273 mono_free(stringname
);
1278 HRESULT
get_runtime_info(LPCWSTR exefile
, LPCWSTR version
, LPCWSTR config_file
,
1279 DWORD startup_flags
, DWORD runtimeinfo_flags
, BOOL legacy
, ICLRRuntimeInfo
**result
)
1281 static const WCHAR dotconfig
[] = {'.','c','o','n','f','i','g',0};
1282 static const DWORD supported_startup_flags
= 0;
1283 static const DWORD supported_runtime_flags
= RUNTIME_INFO_UPGRADE_VERSION
;
1285 WCHAR local_version
[MAX_PATH
];
1286 ULONG local_version_size
= MAX_PATH
;
1287 WCHAR local_config_file
[MAX_PATH
];
1289 parsed_config_file parsed_config
;
1291 if (startup_flags
& ~supported_startup_flags
)
1292 FIXME("unsupported startup flags %x\n", startup_flags
& ~supported_startup_flags
);
1294 if (runtimeinfo_flags
& ~supported_runtime_flags
)
1295 FIXME("unsupported runtimeinfo flags %x\n", runtimeinfo_flags
& ~supported_runtime_flags
);
1297 if (exefile
&& !exefile
[0])
1300 if (exefile
&& !config_file
)
1302 strcpyW(local_config_file
, exefile
);
1303 strcatW(local_config_file
, dotconfig
);
1305 config_file
= local_config_file
;
1311 hr
= parse_config_file(config_file
, &parsed_config
);
1315 supported_runtime
*entry
;
1316 LIST_FOR_EACH_ENTRY(entry
, &parsed_config
.supported_runtimes
, supported_runtime
, entry
)
1318 hr
= get_runtime(entry
->version
, TRUE
, &IID_ICLRRuntimeInfo
, (void**)result
);
1328 WARN("failed to parse config file %s, hr=%x\n", debugstr_w(config_file
), hr
);
1331 free_parsed_config_file(&parsed_config
);
1337 if (exefile
&& !version
)
1339 hr
= CLRMetaHost_GetVersionFromFile(0, exefile
, local_version
, &local_version_size
);
1341 version
= local_version
;
1343 if (FAILED(hr
)) return hr
;
1348 hr
= CLRMetaHost_GetRuntime(0, version
, &IID_ICLRRuntimeInfo
, (void**)result
);
1353 if (runtimeinfo_flags
& RUNTIME_INFO_UPGRADE_VERSION
)
1355 DWORD major
, minor
, build
;
1357 if (version
&& !parse_runtime_version(version
, &major
, &minor
, &build
))
1359 ERR("Cannot parse %s\n", debugstr_w(version
));
1360 return CLR_E_SHIM_RUNTIME
;
1370 /* Must be greater or equal to the version passed in. */
1371 if (!version
|| ((runtimes
[i
].major
>= major
&& runtimes
[i
].minor
>= minor
&& runtimes
[i
].build
>= build
) ||
1372 (runtimes
[i
].major
>= major
&& runtimes
[i
].minor
> minor
) ||
1373 (runtimes
[i
].major
> major
)))
1375 return ICLRRuntimeInfo_QueryInterface(&runtimes
[i
].ICLRRuntimeInfo_iface
,
1376 &IID_ICLRRuntimeInfo
, (void **)result
);
1380 return CLR_E_SHIM_RUNTIME
;
1383 return CLR_E_SHIM_RUNTIME
;