comctl32/tests: Use CRT allocation functions.
[wine.git] / dlls / mscoree / tests / mscoree.c
blobbfcbc78db55e1f241477a57e699ebb2371839d0f
1 /*
2 * Copyright 2010 Louis Lenders
3 * Copyright 2011 André Hentschel
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdio.h>
22 #define COBJMACROS
24 #include "corerror.h"
25 #include "mscoree.h"
26 #include "metahost.h"
27 #include "shlwapi.h"
28 #include "initguid.h"
29 #include "wine/test.h"
31 #if !defined(__i386__) && !defined(__x86_64__)
32 static int has_mono = 0;
33 #else
34 static int has_mono = 1;
35 #endif
37 DEFINE_GUID(IID__AppDomain, 0x05f696dc,0x2b29,0x3663,0xad,0x8b,0xc4,0x38,0x9c,0xf2,0xa7,0x13);
39 static const WCHAR v4_0[] = {'v','4','.','0','.','3','0','3','1','9',0};
41 static HMODULE hmscoree;
43 static HRESULT (WINAPI *pGetCORVersion)(LPWSTR, DWORD, DWORD*);
44 static HRESULT (WINAPI *pCorIsLatestSvc)(INT*, INT*);
45 static HRESULT (WINAPI *pGetCORSystemDirectory)(LPWSTR, DWORD, DWORD*);
46 static HRESULT (WINAPI *pGetRequestedRuntimeInfo)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, DWORD, LPWSTR, DWORD, DWORD*, LPWSTR, DWORD, DWORD*);
47 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR, LPCWSTR, LPVOID, HMODULE*);
48 static HRESULT (WINAPI *pCreateConfigStream)(LPCWSTR, IStream**);
49 static HRESULT (WINAPI *pCreateInterface)(REFCLSID, REFIID, VOID**);
50 static HRESULT (WINAPI *pCLRCreateInstance)(REFCLSID, REFIID, VOID**);
52 static BOOL no_legacy_runtimes;
54 static BOOL init_functionpointers(void)
56 hmscoree = LoadLibraryA("mscoree.dll");
58 if (!hmscoree)
60 win_skip("mscoree.dll not available\n");
61 return FALSE;
64 pGetCORVersion = (void *)GetProcAddress(hmscoree, "GetCORVersion");
65 pCorIsLatestSvc = (void *)GetProcAddress(hmscoree, "CorIsLatestSvc");
66 pGetCORSystemDirectory = (void *)GetProcAddress(hmscoree, "GetCORSystemDirectory");
67 pGetRequestedRuntimeInfo = (void *)GetProcAddress(hmscoree, "GetRequestedRuntimeInfo");
68 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
69 pCreateConfigStream = (void *)GetProcAddress(hmscoree, "CreateConfigStream");
70 pCreateInterface = (void *)GetProcAddress(hmscoree, "CreateInterface");
71 pCLRCreateInstance = (void *)GetProcAddress(hmscoree, "CLRCreateInstance");
73 if (!pGetCORVersion || !pGetCORSystemDirectory || !pGetRequestedRuntimeInfo || !pLoadLibraryShim ||
74 !pCreateInterface || !pCLRCreateInstance || !pCorIsLatestSvc
77 win_skip("functions not available\n");
78 FreeLibrary(hmscoree);
79 return FALSE;
82 return TRUE;
85 static int check_runtime(void)
87 ICLRMetaHost *metahost;
88 ICLRRuntimeInfo *runtimeinfo;
89 ICorRuntimeHost *runtimehost;
90 HRESULT hr;
92 if (!pCLRCreateInstance)
94 win_skip("Function CLRCreateInstance not found.\n");
95 return 1;
98 hr = pCLRCreateInstance(&CLSID_CLRMetaHost, &IID_ICLRMetaHost, (void **)&metahost);
99 if (hr == E_NOTIMPL)
101 win_skip("CLRCreateInstance not implemented\n");
102 return 1;
104 ok(SUCCEEDED(hr), "CLRCreateInstance failed, hr=%#.8lx\n", hr);
105 if (FAILED(hr))
106 return 1;
108 hr = ICLRMetaHost_GetRuntime(metahost, v4_0, &IID_ICLRRuntimeInfo, (void **)&runtimeinfo);
109 ok(SUCCEEDED(hr), "ICLRMetaHost::GetRuntime failed, hr=%#.8lx\n", hr);
110 if (FAILED(hr))
111 return 1;
113 hr = ICLRRuntimeInfo_GetInterface(runtimeinfo, &CLSID_CorRuntimeHost, &IID_ICorRuntimeHost,
114 (void **)&runtimehost);
115 todo_wine_if(!has_mono) ok(SUCCEEDED(hr), "ICLRRuntimeInfo::GetInterface failed, hr=%#.8lx\n", hr);
116 if (FAILED(hr))
117 return 1;
119 hr = ICorRuntimeHost_Start(runtimehost);
120 ok(SUCCEEDED(hr), "ICorRuntimeHost::Start failed, hr=%#.8lx\n", hr);
121 if (FAILED(hr))
122 return 1;
124 ICorRuntimeHost_Release(runtimehost);
126 ICLRRuntimeInfo_Release(runtimeinfo);
128 ICLRMetaHost_ExitProcess(metahost, 0);
130 ok(0, "ICLRMetaHost_ExitProcess is not supposed to return\n");
131 return 1;
134 static BOOL runtime_is_usable(void)
136 static const char cmdline_format[] = "\"%s\" mscoree check_runtime";
137 char** argv;
138 char cmdline[MAX_PATH + sizeof(cmdline_format)];
139 STARTUPINFOA si = {0};
140 PROCESS_INFORMATION pi;
141 BOOL ret;
142 DWORD exitcode;
144 winetest_get_mainargs(&argv);
146 sprintf(cmdline, cmdline_format, argv[0]);
148 si.cb = sizeof(si);
150 ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
151 ok(ret, "Could not create process: %lu\n", GetLastError());
152 if (!ret)
153 return FALSE;
155 CloseHandle(pi.hThread);
157 WaitForSingleObject(pi.hProcess, INFINITE);
159 ret = GetExitCodeProcess(pi.hProcess, &exitcode);
160 ok(ret, "GetExitCodeProcess failed: %lu\n", GetLastError());
161 CloseHandle(pi.hProcess);
163 if (!ret || exitcode != 0)
165 todo_wine_if(!has_mono) win_skip(".NET 4.0 runtime is not usable\n");
166 return FALSE;
169 return TRUE;
172 static void test_versioninfo(void)
174 const WCHAR v9_0[] = {'v','9','.','0','.','3','0','3','1','9',0};
175 const WCHAR v2_0cap[] = {'V','2','.','0','.','5','0','7','2','7',0};
176 const WCHAR v2_0[] = {'v','2','.','0','.','5','0','7','2','7',0};
177 const WCHAR v2_0_0[] = {'v','2','.','0','.','0',0};
178 const WCHAR v1_1[] = {'v','1','.','1','.','4','3','2','2',0};
179 const WCHAR v1_1_0[] = {'v','1','.','1','.','0',0};
181 WCHAR version[MAX_PATH];
182 WCHAR path[MAX_PATH];
183 DWORD size, path_len;
184 HRESULT hr;
186 if (0) /* crashes on <= w2k3 */
188 hr = pGetCORVersion(NULL, MAX_PATH, &size);
189 ok(hr == E_POINTER,"GetCORVersion returned %08lx\n", hr);
192 hr = pGetCORVersion(version, 1, &size);
193 if (hr == CLR_E_SHIM_RUNTIME)
195 no_legacy_runtimes = TRUE;
196 win_skip("No legacy .NET runtimes are installed\n");
197 return;
200 ok(hr == E_NOT_SUFFICIENT_BUFFER, "GetCORVersion returned %08lx\n", hr);
202 hr = pGetCORVersion(version, MAX_PATH, &size);
203 ok(hr == S_OK,"GetCORVersion returned %08lx\n", hr);
205 trace("latest installed .net runtime: %s\n", wine_dbgstr_w(version));
207 hr = pGetCORSystemDirectory(path, MAX_PATH , &size);
208 todo_wine_if(!has_mono) ok(hr == S_OK, "GetCORSystemDirectory returned %08lx\n", hr);
209 /* size includes terminating null-character */
210 todo_wine_if(!has_mono) ok(size == (lstrlenW(path) + 1),"size is %ld instead of %d\n", size, (lstrlenW(path) + 1));
212 path_len = size;
214 hr = pGetCORSystemDirectory(path, path_len-1 , &size);
215 todo_wine_if(!has_mono) ok(hr == E_NOT_SUFFICIENT_BUFFER, "GetCORSystemDirectory returned %08lx\n", hr);
217 if (0) /* crashes on <= w2k3 */
219 hr = pGetCORSystemDirectory(NULL, MAX_PATH , &size);
220 ok(hr == E_NOT_SUFFICIENT_BUFFER, "GetCORSystemDirectory returned %08lx\n", hr);
223 hr = pGetCORSystemDirectory(path, MAX_PATH , NULL);
224 ok(hr == E_POINTER,"GetCORSystemDirectory returned %08lx\n", hr);
226 trace("latest installed .net installed in directory: %s\n", wine_dbgstr_w(path));
228 /* test GetRequestedRuntimeInfo, first get info about different versions of runtime */
229 hr = pGetRequestedRuntimeInfo( NULL, v2_0, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, &size);
231 if(hr == CLR_E_SHIM_RUNTIME) return; /* skipping rest of tests on win2k as .net 2.0 not installed */
233 todo_wine_if(!has_mono) ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08lx\n", hr);
234 trace(" installed in directory %s is .net version %s\n", wine_dbgstr_w(path), wine_dbgstr_w(version));
236 hr = pGetRequestedRuntimeInfo( NULL, v1_1, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, &size);
237 todo_wine_if(!has_mono) ok(hr == S_OK || hr == CLR_E_SHIM_RUNTIME /*v1_1 not installed*/, "GetRequestedRuntimeInfo returned %08lx\n", hr);
238 if(hr == S_OK)
239 trace(" installed in directory %s is .net version %s\n", wine_dbgstr_w(path), wine_dbgstr_w(version));
240 /* version number NULL not allowed without RUNTIME_INFO_UPGRADE_VERSION flag */
241 hr = pGetRequestedRuntimeInfo( NULL, NULL, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, &size);
242 ok(hr == CLR_E_SHIM_RUNTIME, "GetRequestedRuntimeInfo returned %08lx\n", hr);
243 /* with RUNTIME_INFO_UPGRADE_VERSION flag and version number NULL, latest installed version is returned */
244 hr = pGetRequestedRuntimeInfo( NULL, NULL, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, path, MAX_PATH, &path_len, version, MAX_PATH, &size);
245 todo_wine_if(!has_mono) ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08lx\n", hr);
247 hr = pGetRequestedRuntimeInfo( NULL, v2_0, NULL, 0, 0, path, 1, &path_len, version, MAX_PATH, &size);
248 todo_wine_if(!has_mono) ok(hr == E_NOT_SUFFICIENT_BUFFER, "GetRequestedRuntimeInfo returned %08lx\n", hr);
250 /* if one of the buffers is NULL, the other one is still happily filled */
251 memset(version, 0, sizeof(version));
252 hr = pGetRequestedRuntimeInfo( NULL, v2_0, NULL, 0, 0, NULL, MAX_PATH, &path_len, version, MAX_PATH, &size);
253 todo_wine_if(!has_mono) ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08lx\n", hr);
254 ok(!wcscmp(version, v2_0), "version is %s , expected %s\n", wine_dbgstr_w(version), wine_dbgstr_w(v2_0));
255 /* With NULL-pointer for bufferlength, the buffer itself still gets filled with correct string */
256 memset(version, 0, sizeof(version));
257 hr = pGetRequestedRuntimeInfo( NULL, v2_0, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
258 todo_wine_if(!has_mono) ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08lx\n", hr);
259 ok(!wcscmp(version, v2_0), "version is %s , expected %s\n", wine_dbgstr_w(version), wine_dbgstr_w(v2_0));
261 memset(version, 0, sizeof(version));
262 hr = pGetRequestedRuntimeInfo( NULL, v2_0cap, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
263 todo_wine_if(!has_mono) ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08lx\n", hr);
264 ok(!wcscmp(version, v2_0cap), "version is %s , expected %s\n", wine_dbgstr_w(version), wine_dbgstr_w(v2_0cap));
266 /* Invalid Version and RUNTIME_INFO_UPGRADE_VERSION flag*/
267 memset(version, 0, sizeof(version));
268 hr = pGetRequestedRuntimeInfo( NULL, v1_1, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
269 todo_wine_if(!has_mono) ok(hr == S_OK || hr == CLR_E_SHIM_RUNTIME , "GetRequestedRuntimeInfo returned %08lx\n", hr);
270 if(hr == S_OK)
272 /* .NET 1.1 may not be installed. */
273 ok(!wcscmp(version, v1_1) || !wcscmp(version, v2_0),
274 "version is %s , expected %s or %s\n", wine_dbgstr_w(version), wine_dbgstr_w(v1_1), wine_dbgstr_w(v2_0));
278 memset(version, 0, sizeof(version));
279 hr = pGetRequestedRuntimeInfo( NULL, v9_0, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
280 ok(hr == CLR_E_SHIM_RUNTIME, "GetRequestedRuntimeInfo returned %08lx\n", hr);
282 memset(version, 0, sizeof(version));
283 hr = pGetRequestedRuntimeInfo( NULL, v1_1_0, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
284 ok(hr == CLR_E_SHIM_RUNTIME, "GetRequestedRuntimeInfo returned %08lx\n", hr);
286 memset(version, 0, sizeof(version));
287 hr = pGetRequestedRuntimeInfo( NULL, v1_1_0, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
288 todo_wine_if(!has_mono) ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08lx\n", hr);
289 ok(!wcscmp(version, v2_0), "version is %s , expected %s\n", wine_dbgstr_w(version), wine_dbgstr_w(v2_0));
291 memset(version, 0, sizeof(version));
292 hr = pGetRequestedRuntimeInfo( NULL, v2_0_0, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
293 ok(hr == CLR_E_SHIM_RUNTIME, "GetRequestedRuntimeInfo returned %08lx\n", hr);
295 memset(version, 0, sizeof(version));
296 hr = pGetRequestedRuntimeInfo( NULL, v2_0_0, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
297 todo_wine_if(!has_mono) ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08lx\n", hr);
298 ok(!wcscmp(version, v2_0), "version is %s , expected %s\n", wine_dbgstr_w(version), wine_dbgstr_w(v2_0));
300 hr = pCorIsLatestSvc(NULL, NULL);
301 ok(hr == E_POINTER, "CorIsLatestSvc returned %08lx\n", hr);
304 static void test_loadlibraryshim(void)
306 const WCHAR v2_0[] = {'v','2','.','0','.','5','0','7','2','7',0};
307 const WCHAR v1_1[] = {'v','1','.','1','.','4','3','2','2',0};
308 const WCHAR vbogus[] = {'v','b','o','g','u','s',0};
309 const WCHAR fusion[] = {'f','u','s','i','o','n',0};
310 const WCHAR fusiondll[] = {'f','u','s','i','o','n','.','d','l','l',0};
311 const WCHAR nosuchdll[] = {'j','n','v','n','l','.','d','l','l',0};
312 const WCHAR gdidll[] = {'g','d','i','3','2','.','d','l','l',0};
313 HRESULT hr;
314 const WCHAR *latest = NULL;
315 CHAR latestA[MAX_PATH];
316 HMODULE hdll;
317 CHAR dllpath[MAX_PATH];
319 if (no_legacy_runtimes)
321 win_skip("No legacy .NET runtimes are installed\n");
322 return;
325 hr = pLoadLibraryShim(fusion, v1_1, NULL, &hdll);
326 ok(hr == S_OK || hr == E_HANDLE, "LoadLibraryShim failed, hr=%lx\n", hr);
327 if (SUCCEEDED(hr))
329 latest = v1_1;
331 GetModuleFileNameA(hdll, dllpath, MAX_PATH);
333 todo_wine_if(!has_mono) ok(StrStrIA(dllpath, "v1.1.4322") != 0, "incorrect fusion.dll path %s\n", dllpath);
334 ok(StrStrIA(dllpath, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath);
336 FreeLibrary(hdll);
339 hr = pLoadLibraryShim(fusion, v2_0, NULL, &hdll);
340 ok(hr == S_OK || hr == E_HANDLE, "LoadLibraryShim failed, hr=%lx\n", hr);
341 if (SUCCEEDED(hr))
343 latest = v2_0;
345 GetModuleFileNameA(hdll, dllpath, MAX_PATH);
347 todo_wine_if(!has_mono) ok(StrStrIA(dllpath, "v2.0.50727") != 0, "incorrect fusion.dll path %s\n", dllpath);
348 ok(StrStrIA(dllpath, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath);
350 FreeLibrary(hdll);
353 hr = pLoadLibraryShim(fusion, v4_0, NULL, &hdll);
354 ok(hr == S_OK || hr == E_HANDLE, "LoadLibraryShim failed, hr=%lx\n", hr);
355 if (SUCCEEDED(hr))
357 /* LoadLibraryShim with a NULL version prefers 2.0 and earlier */
358 if (!latest)
359 latest = v4_0;
361 GetModuleFileNameA(hdll, dllpath, MAX_PATH);
363 todo_wine_if(!has_mono) ok(StrStrIA(dllpath, "v4.0.30319") != 0, "incorrect fusion.dll path %s\n", dllpath);
364 ok(StrStrIA(dllpath, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath);
366 FreeLibrary(hdll);
369 hr = pLoadLibraryShim(fusion, vbogus, NULL, &hdll);
370 ok(hr == E_HANDLE, "LoadLibraryShim failed, hr=%lx\n", hr);
371 if (SUCCEEDED(hr))
372 FreeLibrary(hdll);
374 WideCharToMultiByte(CP_ACP, 0, latest, -1, latestA, MAX_PATH, NULL, NULL);
376 hr = pLoadLibraryShim(fusion, NULL, NULL, &hdll);
377 ok(hr == S_OK, "LoadLibraryShim failed, hr=%lx\n", hr);
378 if (SUCCEEDED(hr))
380 GetModuleFileNameA(hdll, dllpath, MAX_PATH);
382 if (latest)
383 todo_wine_if(!has_mono) ok(StrStrIA(dllpath, latestA) != 0, "incorrect fusion.dll path %s\n", dllpath);
384 ok(StrStrIA(dllpath, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath);
386 FreeLibrary(hdll);
389 hr = pLoadLibraryShim(fusiondll, NULL, NULL, &hdll);
390 ok(hr == S_OK, "LoadLibraryShim failed, hr=%lx\n", hr);
391 if (SUCCEEDED(hr))
393 GetModuleFileNameA(hdll, dllpath, MAX_PATH);
395 if (latest)
396 todo_wine_if(!has_mono) ok(StrStrIA(dllpath, latestA) != 0, "incorrect fusion.dll path %s\n", dllpath);
397 ok(StrStrIA(dllpath, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath);
399 FreeLibrary(hdll);
402 hr = pLoadLibraryShim(nosuchdll, latest, NULL, &hdll);
403 ok(hr == E_HANDLE, "LoadLibraryShim failed, hr=%lx\n", hr);
404 if (SUCCEEDED(hr))
405 FreeLibrary(hdll);
407 hr = pLoadLibraryShim(gdidll, latest, NULL, &hdll);
408 ok(hr == E_HANDLE, "LoadLibraryShim failed, hr=%lx\n", hr);
409 if (SUCCEEDED(hr))
410 FreeLibrary(hdll);
413 static const char xmldata[] =
414 "<?xml version=\"1.0\" ?>\n"
415 "<!DOCTYPE Config>\n"
416 "<Configuration>\n"
417 " <Name>Test</Name>\n"
418 " <Value>1234</Value>\n"
419 "</Configuration>";
421 static void create_xml_file(LPCWSTR filename)
423 DWORD dwNumberOfBytesWritten;
424 HANDLE hfile = CreateFileW(filename, GENERIC_WRITE, 0, NULL,
425 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
426 ok(hfile != INVALID_HANDLE_VALUE, "Could not open %s for writing: %lu\n", wine_dbgstr_w(filename), GetLastError());
427 WriteFile(hfile, xmldata, sizeof(xmldata) - 1, &dwNumberOfBytesWritten, NULL);
428 CloseHandle(hfile);
431 static void test_createconfigstream(void)
433 IStream *stream = NULL;
434 WCHAR file[] = {'c', 'o', 'n', 'f', '.', 'x', 'm', 'l', 0};
435 WCHAR nonexistent[] = {'n', 'o', 'n', 'e', 'x', 'i', 's', 't', '.', 'x', 'm', 'l', 0};
436 WCHAR path[MAX_PATH];
437 HRESULT hr;
438 char buffer[256] = {0};
440 if (!pCreateConfigStream)
442 win_skip("CreateConfigStream not available\n");
443 return;
446 create_xml_file(file);
447 GetFullPathNameW(file, MAX_PATH, path, NULL);
449 hr = pCreateConfigStream(NULL, &stream);
450 ok(hr == E_FAIL ||
451 broken(hr == HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND)) || /* some WinXP, Win2K3 and Win7 */
452 broken(hr == S_OK && !stream), /* some Win2K3 */
453 "CreateConfigStream returned %lx\n", hr);
455 hr = pCreateConfigStream(path, NULL);
456 ok(hr == COR_E_NULLREFERENCE, "CreateConfigStream returned %lx\n", hr);
458 hr = pCreateConfigStream(NULL, NULL);
459 ok(hr == COR_E_NULLREFERENCE, "CreateConfigStream returned %lx\n", hr);
461 hr = pCreateConfigStream(nonexistent, &stream);
462 ok(hr == COR_E_FILENOTFOUND, "CreateConfigStream returned %lx\n", hr);
463 ok(stream == NULL, "Expected stream to be NULL\n");
465 hr = pCreateConfigStream(path, &stream);
466 ok(hr == S_OK, "CreateConfigStream failed, hr=%lx\n", hr);
467 ok(stream != NULL, "Expected non-NULL stream\n");
469 if (stream)
471 DWORD count;
472 LARGE_INTEGER pos;
473 ULARGE_INTEGER size;
474 IStream *stream2 = NULL;
475 ULONG ref;
477 hr = IStream_Read(stream, buffer, strlen(xmldata), &count);
478 ok(hr == S_OK, "IStream_Read failed, hr=%lx\n", hr);
479 ok(count == strlen(xmldata), "wrong count: %lu\n", count);
480 ok(!strcmp(buffer, xmldata), "Strings do not match\n");
482 hr = IStream_Read(stream, buffer, sizeof(buffer), &count);
483 ok(hr == S_OK, "IStream_Read failed, hr=%lx\n", hr);
484 ok(!count, "wrong count: %lu\n", count);
486 hr = IStream_Write(stream, xmldata, strlen(xmldata), &count);
487 ok(hr == E_FAIL, "IStream_Write returned hr=%lx\n", hr);
489 pos.QuadPart = strlen(xmldata);
490 hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
491 ok(hr == E_NOTIMPL, "IStream_Seek returned hr=%lx\n", hr);
493 size.QuadPart = strlen(xmldata);
494 hr = IStream_SetSize(stream, size);
495 ok(hr == E_NOTIMPL, "IStream_SetSize returned hr=%lx\n", hr);
497 hr = IStream_Clone(stream, &stream2);
498 ok(hr == E_NOTIMPL, "IStream_Clone returned hr=%lx\n", hr);
500 hr = IStream_Commit(stream, STGC_DEFAULT);
501 ok(hr == E_NOTIMPL, "IStream_Commit returned hr=%lx\n", hr);
503 hr = IStream_Revert(stream);
504 ok(hr == E_NOTIMPL, "IStream_Revert returned hr=%lx\n", hr);
506 ref = IStream_Release(stream);
507 ok(!ref, "IStream_Release returned %lu\n", ref);
509 DeleteFileW(file);
512 static void test_createinstance(void)
514 HRESULT hr;
515 ICLRMetaHost *host;
517 if (no_legacy_runtimes)
519 /* If we don't have 1.x or 2.0 runtimes, we should at least have .NET 4. */
520 ok(pCreateInterface != NULL, "no legacy runtimes or .NET 4 interfaces available\n");
523 if(!pCreateInterface)
525 win_skip("Function CreateInterface not found.\n");
526 return;
529 hr = pCreateInterface(&CLSID_CLRMetaHost, &IID_ICLRMetaHost, (void**)&host);
530 if(SUCCEEDED(hr))
532 ICLRMetaHost_Release(host);
534 else
536 win_skip(".NET 4 not installed.\n");
540 static BOOL write_resource(const WCHAR *resource, const WCHAR *filename)
542 HANDLE file;
543 HRSRC rsrc;
544 void *data;
545 DWORD size;
546 BOOL ret;
548 rsrc = FindResourceW(GetModuleHandleW(NULL), resource, MAKEINTRESOURCEW(RT_RCDATA));
549 if (!rsrc) return FALSE;
551 data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc));
552 if (!data) return FALSE;
554 size = SizeofResource(GetModuleHandleA(NULL), rsrc);
555 if (!size) return FALSE;
557 file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
558 if (file == INVALID_HANDLE_VALUE) return FALSE;
560 ret = WriteFile(file, data, size, &size, NULL);
561 CloseHandle(file);
562 return ret;
565 static BOOL compile_cs(const WCHAR *source, const WCHAR *target, const WCHAR *type, const WCHAR *args)
567 static const WCHAR *csc = L"C:\\windows\\Microsoft.NET\\Framework\\v2.0.50727\\csc.exe";
568 WCHAR cmdline[2 * MAX_PATH + 74];
569 PROCESS_INFORMATION pi;
570 STARTUPINFOW si = { 0 };
571 BOOL ret;
573 if (!PathFileExistsW(csc))
575 skip("Can't find csc.exe\n");
576 return FALSE;
579 swprintf(cmdline, ARRAY_SIZE(cmdline), L"%s /t:%s %s /out:\"%s\" \"%s\"", csc, type, args, target, source);
581 si.cb = sizeof(si);
582 ret = CreateProcessW(csc, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi);
583 ok(ret, "Could not create process: %lu\n", GetLastError());
585 wait_child_process(pi.hProcess);
586 CloseHandle(pi.hThread);
587 CloseHandle(pi.hProcess);
589 ret = PathFileExistsW(target);
590 ok(ret, "Compilation failed\n");
592 return ret;
595 static BOOL create_new_dir(WCHAR newdir[MAX_PATH], const WCHAR* prefix)
597 WCHAR path[MAX_PATH];
598 BOOL try_tmpdir = TRUE;
599 static unsigned i = 0;
601 GetCurrentDirectoryW(ARRAY_SIZE(path), path);
603 while (1)
605 swprintf(newdir, MAX_PATH, L"%s\\%s%04d", path, prefix, i);
606 if (CreateDirectoryW(newdir, NULL))
607 return TRUE;
608 switch (GetLastError())
610 case ERROR_ACCESS_DENIED:
611 if (!try_tmpdir)
612 return FALSE;
613 try_tmpdir = FALSE;
614 GetTempPathW(ARRAY_SIZE(path), path);
615 path[wcslen(path) - 1] = 0; /* redundant trailing backslash */
616 break;
617 case ERROR_ALREADY_EXISTS:
618 i++;
619 break;
620 default:
621 return FALSE;
626 static void test_loadpaths_execute(const WCHAR *exe_name, const WCHAR *dll_name, const WCHAR *cfg_name,
627 const WCHAR *dll_dest, BOOL expect_failure, BOOL todo)
629 WCHAR tmpdir[MAX_PATH], tmpexe[MAX_PATH], tmpcfg[MAX_PATH], tmpdll[MAX_PATH];
630 PROCESS_INFORMATION pi;
631 STARTUPINFOW si = { 0 };
632 WCHAR *ptr, *end;
633 DWORD exit_code = 0xdeadbeef;
634 BOOL ret;
636 ok(create_new_dir(tmpdir, L"loadpaths"),
637 "failed to create a new dir %lu\n", GetLastError());
638 end = tmpdir + wcslen(tmpdir);
640 wcscpy(tmpexe, tmpdir);
641 PathAppendW(tmpexe, exe_name);
642 ret = CopyFileW(exe_name, tmpexe, FALSE);
643 ok(ret, "CopyFileW(%s) failed: %lu\n", debugstr_w(tmpexe), GetLastError());
645 if (cfg_name)
647 wcscpy(tmpcfg, tmpdir);
648 PathAppendW(tmpcfg, cfg_name);
649 ret = CopyFileW(cfg_name, tmpcfg, FALSE);
650 ok(ret, "CopyFileW(%s) failed: %lu\n", debugstr_w(tmpcfg), GetLastError());
653 ptr = tmpdir + wcslen(tmpdir);
654 PathAppendW(tmpdir, dll_dest);
655 while (*ptr && (ptr = wcschr(ptr + 1, '\\')))
657 *ptr = '\0';
658 ret = CreateDirectoryW(tmpdir, NULL);
659 ok(ret, "CreateDirectoryW(%s) failed: %lu\n", debugstr_w(tmpdir), GetLastError());
660 *ptr = '\\';
663 wcscpy(tmpdll, tmpdir);
664 if ((ptr = wcsrchr(tmpdir, '\\'))) *ptr = '\0';
666 ret = CopyFileW(dll_name, tmpdll, FALSE);
667 ok(ret, "CopyFileW(%s) failed: %lu\n", debugstr_w(tmpdll), GetLastError());
669 si.cb = sizeof(si);
670 ret = CreateProcessW(tmpexe, tmpexe, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
671 ok(ret, "CreateProcessW(%s) failed: %lu\n", debugstr_w(tmpexe), GetLastError());
673 if (expect_failure) ret = WaitForSingleObject(pi.hProcess, 2000);
674 else
676 ret = WaitForSingleObject(pi.hProcess, 5000);
677 ok(ret == WAIT_OBJECT_0, "%s: WaitForSingleObject returned %d: %lu\n", debugstr_w(dll_dest), ret, GetLastError());
680 GetExitCodeProcess(pi.hProcess, &exit_code);
681 if (ret == WAIT_TIMEOUT) TerminateProcess(pi.hProcess, 0xdeadbeef);
682 CloseHandle(pi.hThread);
683 CloseHandle(pi.hProcess);
685 if (expect_failure) todo_wine_if(todo) ok(exit_code != 0, "%s: Succeeded to execute process\n", debugstr_w(dll_dest));
686 else ok(exit_code == 0, "%s: Failed to execute process\n", debugstr_w(dll_dest));
688 /* sometimes the failing process never returns, in which case cleaning up won't work */
689 if (ret == WAIT_TIMEOUT && expect_failure) return;
691 if (cfg_name)
693 ret = DeleteFileW(tmpcfg);
694 ok(ret, "DeleteFileW(%s) failed: %lu\n", debugstr_w(tmpcfg), GetLastError());
696 ret = DeleteFileW(tmpdll);
697 ok(ret, "DeleteFileW(%s) failed: %lu\n", debugstr_w(tmpdll), GetLastError());
698 ret = DeleteFileW(tmpexe);
699 ok(ret, "DeleteFileW(%s) failed: %lu\n", debugstr_w(tmpexe), GetLastError());
701 ptr = end;
702 while (ptr >= end && (ptr = wcsrchr(tmpdir, '\\')))
704 ret = RemoveDirectoryW(tmpdir);
705 ok(ret, "RemoveDirectoryW(%s) failed: %lu\n", debugstr_w(tmpdir), GetLastError());
706 *ptr = '\0';
710 static void test_loadpaths(BOOL neutral)
712 static const WCHAR *loadpaths[] = {L"", L"en", L"libloadpaths", L"en\\libloadpaths"};
713 static const WCHAR *dll_source = L"loadpaths.dll.cs";
714 static const WCHAR *dll_name = L"libloadpaths.dll";
715 static const WCHAR *exe_source = L"loadpaths.exe.cs";
716 static const WCHAR *exe_name = L"loadpaths.exe";
717 static const WCHAR *cfg_name = L"loadpaths.exe.config";
718 WCHAR tmp[MAX_PATH];
719 BOOL ret;
720 int i;
722 DeleteFileW(dll_source);
723 ret = write_resource(dll_source, dll_source);
724 ok(ret, "Could not write resource: %lu\n", GetLastError());
725 DeleteFileW(dll_name);
726 ret = compile_cs(dll_source, dll_name, L"library", neutral ? L"-define:NEUTRAL" : L"");
727 if (!ret) return;
728 ret = DeleteFileW(dll_source);
729 ok(ret, "DeleteFileW failed: %lu\n", GetLastError());
731 DeleteFileW(exe_source);
732 ret = write_resource(exe_source, exe_source);
733 ok(ret, "Could not write resource: %lu\n", GetLastError());
734 DeleteFileW(exe_name);
735 ret = compile_cs(exe_source, exe_name, L"winexe", L"/reference:libloadpaths.dll");
736 if (!ret) return;
737 ret = DeleteFileW(exe_source);
738 ok(ret, "DeleteFileW failed: %lu\n", GetLastError());
740 DeleteFileW(cfg_name);
741 ret = write_resource(cfg_name, cfg_name);
742 ok(ret, "Could not write resource: %lu\n", GetLastError());
744 for (i = 0; i < ARRAY_SIZE(loadpaths); ++i)
746 const WCHAR *path = loadpaths[i];
747 BOOL expect_failure = neutral ? wcsstr(path, L"en") != NULL
748 : wcsstr(path, L"en") == NULL;
750 wcscpy(tmp, path);
751 PathAppendW(tmp, dll_name);
752 test_loadpaths_execute(exe_name, dll_name, NULL, tmp, expect_failure, !neutral && !*path);
754 wcscpy(tmp, L"private");
755 if (*path) PathAppendW(tmp, path);
756 PathAppendW(tmp, dll_name);
758 test_loadpaths_execute(exe_name, dll_name, NULL, tmp, TRUE, FALSE);
759 test_loadpaths_execute(exe_name, dll_name, cfg_name, tmp, expect_failure, FALSE);
761 /* exe name for dll should work too */
762 if (*path)
764 wcscpy(tmp, path);
765 PathAppendW(tmp, dll_name);
766 wcscpy(tmp + wcslen(tmp) - 4, L".exe");
767 test_loadpaths_execute(exe_name, dll_name, NULL, tmp, expect_failure, FALSE);
770 wcscpy(tmp, L"private");
771 if (*path) PathAppendW(tmp, path);
772 PathAppendW(tmp, dll_name);
773 wcscpy(tmp + wcslen(tmp) - 4, L".exe");
775 test_loadpaths_execute(exe_name, dll_name, NULL, tmp, TRUE, FALSE);
776 test_loadpaths_execute(exe_name, dll_name, cfg_name, tmp, expect_failure, FALSE);
779 ret = DeleteFileW(cfg_name);
780 ok(ret, "DeleteFileW failed: %lu\n", GetLastError());
781 ret = DeleteFileW(exe_name);
782 ok(ret, "DeleteFileW failed: %lu\n", GetLastError());
783 ret = DeleteFileW(dll_name);
784 ok(ret, "DeleteFileW failed: %lu\n", GetLastError());
787 static void test_createdomain(void)
789 static const WCHAR test_name[] = {'t','e','s','t',0};
790 static const WCHAR test2_name[] = {'t','e','s','t','2',0};
791 ICLRMetaHost *metahost;
792 ICLRRuntimeInfo *runtimeinfo;
793 ICorRuntimeHost *runtimehost;
794 IUnknown *domain, *defaultdomain_unk, *defaultdomain, *newdomain_unk, *newdomain, *domainsetup,
795 *newdomain2_unk, *newdomain2;
796 HRESULT hr;
798 if (!pCLRCreateInstance)
800 win_skip("Function CLRCreateInstance not found.\n");
801 return;
804 hr = pCLRCreateInstance(&CLSID_CLRMetaHost, &IID_ICLRMetaHost, (void **)&metahost);
805 ok(SUCCEEDED(hr), "CLRCreateInstance failed, hr=%#.8lx\n", hr);
807 hr = ICLRMetaHost_GetRuntime(metahost, v4_0, &IID_ICLRRuntimeInfo, (void **)&runtimeinfo);
808 ok(SUCCEEDED(hr), "ICLRMetaHost::GetRuntime failed, hr=%#.8lx\n", hr);
810 hr = ICLRRuntimeInfo_GetInterface(runtimeinfo, &CLSID_CorRuntimeHost, &IID_ICorRuntimeHost,
811 (void **)&runtimehost);
812 ok(SUCCEEDED(hr), "ICLRRuntimeInfo::GetInterface failed, hr=%#.8lx\n", hr);
814 hr = ICorRuntimeHost_Start(runtimehost);
815 ok(SUCCEEDED(hr), "ICorRuntimeHost::Start failed, hr=%#.8lx\n", hr);
817 hr = ICorRuntimeHost_GetDefaultDomain(runtimehost, &domain);
818 ok(SUCCEEDED(hr), "ICorRuntimeHost::GetDefaultDomain failed, hr=%#.8lx\n", hr);
820 hr = IUnknown_QueryInterface(domain, &IID_IUnknown, (void **)&defaultdomain_unk);
821 ok(SUCCEEDED(hr), "COM object doesn't support IUnknown?!\n");
823 hr = IUnknown_QueryInterface(domain, &IID__AppDomain, (void **)&defaultdomain);
824 ok(SUCCEEDED(hr), "AppDomain object doesn't support _AppDomain interface\n");
826 IUnknown_Release(domain);
828 hr = ICorRuntimeHost_CreateDomain(runtimehost, test_name, NULL, &domain);
829 ok(SUCCEEDED(hr), "ICorRuntimeHost::CreateDomain failed, hr=%#.8lx\n", hr);
831 hr = IUnknown_QueryInterface(domain, &IID_IUnknown, (void **)&newdomain_unk);
832 ok(SUCCEEDED(hr), "COM object doesn't support IUnknown?!\n");
834 hr = IUnknown_QueryInterface(domain, &IID__AppDomain, (void **)&newdomain);
835 ok(SUCCEEDED(hr), "AppDomain object doesn't support _AppDomain interface\n");
837 IUnknown_Release(domain);
839 ok(defaultdomain_unk != newdomain_unk, "New and default domain objects are the same\n");
841 hr = ICorRuntimeHost_CreateDomainSetup(runtimehost, &domainsetup);
842 ok(SUCCEEDED(hr), "ICorRuntimeHost::CreateDomainSetup failed, hr=%#.8lx\n", hr);
844 hr = ICorRuntimeHost_CreateDomainEx(runtimehost, test2_name, domainsetup, NULL, &domain);
845 ok(SUCCEEDED(hr), "ICorRuntimeHost::CreateDomainEx failed, hr=%#.8lx\n", hr);
847 hr = IUnknown_QueryInterface(domain, &IID_IUnknown, (void **)&newdomain2_unk);
848 ok(SUCCEEDED(hr), "COM object doesn't support IUnknown?!\n");
850 hr = IUnknown_QueryInterface(domain, &IID__AppDomain, (void **)&newdomain2);
851 ok(SUCCEEDED(hr), "AppDomain object doesn't support _AppDomain interface\n");
853 IUnknown_Release(domain);
855 ok(defaultdomain_unk != newdomain2_unk, "New and default domain objects are the same\n");
856 ok(newdomain_unk != newdomain2_unk, "Both new domain objects are the same\n");
858 IUnknown_Release(newdomain2);
859 IUnknown_Release(newdomain2_unk);
860 IUnknown_Release(domainsetup);
861 IUnknown_Release(newdomain);
862 IUnknown_Release(newdomain_unk);
863 IUnknown_Release(defaultdomain);
864 IUnknown_Release(defaultdomain_unk);
866 ICorRuntimeHost_Release(runtimehost);
868 ICLRRuntimeInfo_Release(runtimeinfo);
870 ICLRMetaHost_Release(metahost);
873 START_TEST(mscoree)
875 int argc;
876 char** argv;
878 if (!init_functionpointers())
879 return;
881 argc = winetest_get_mainargs(&argv);
882 if (argc >= 3 && !strcmp(argv[2], "check_runtime"))
884 int result = check_runtime();
885 FreeLibrary(hmscoree);
886 exit(result);
889 test_versioninfo();
890 test_loadlibraryshim();
891 test_createconfigstream();
892 test_createinstance();
894 if (runtime_is_usable())
896 test_createdomain();
899 test_loadpaths(FALSE);
900 test_loadpaths(TRUE);
902 FreeLibrary(hmscoree);