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
29 #include "wine/test.h"
31 #if !defined(__i386__) && !defined(__x86_64__)
32 static int has_mono
= 0;
34 static int has_mono
= 1;
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");
60 win_skip("mscoree.dll not available\n");
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
);
85 static int check_runtime(void)
87 ICLRMetaHost
*metahost
;
88 ICLRRuntimeInfo
*runtimeinfo
;
89 ICorRuntimeHost
*runtimehost
;
92 if (!pCLRCreateInstance
)
94 win_skip("Function CLRCreateInstance not found.\n");
98 hr
= pCLRCreateInstance(&CLSID_CLRMetaHost
, &IID_ICLRMetaHost
, (void **)&metahost
);
101 win_skip("CLRCreateInstance not implemented\n");
104 ok(SUCCEEDED(hr
), "CLRCreateInstance failed, hr=%#.8lx\n", hr
);
108 hr
= ICLRMetaHost_GetRuntime(metahost
, v4_0
, &IID_ICLRRuntimeInfo
, (void **)&runtimeinfo
);
109 ok(SUCCEEDED(hr
), "ICLRMetaHost::GetRuntime failed, hr=%#.8lx\n", hr
);
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
);
119 hr
= ICorRuntimeHost_Start(runtimehost
);
120 ok(SUCCEEDED(hr
), "ICorRuntimeHost::Start failed, hr=%#.8lx\n", hr
);
124 ICorRuntimeHost_Release(runtimehost
);
126 ICLRRuntimeInfo_Release(runtimeinfo
);
128 ICLRMetaHost_ExitProcess(metahost
, 0);
130 ok(0, "ICLRMetaHost_ExitProcess is not supposed to return\n");
134 static BOOL
runtime_is_usable(void)
136 static const char cmdline_format
[] = "\"%s\" mscoree check_runtime";
138 char cmdline
[MAX_PATH
+ sizeof(cmdline_format
)];
139 STARTUPINFOA si
= {0};
140 PROCESS_INFORMATION pi
;
144 winetest_get_mainargs(&argv
);
146 sprintf(cmdline
, cmdline_format
, argv
[0]);
150 ret
= CreateProcessA(NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
151 ok(ret
, "Could not create process: %lu\n", GetLastError());
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");
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
;
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");
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));
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
);
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
);
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};
314 const WCHAR
*latest
= NULL
;
315 CHAR latestA
[MAX_PATH
];
317 CHAR dllpath
[MAX_PATH
];
319 if (no_legacy_runtimes
)
321 win_skip("No legacy .NET runtimes are installed\n");
325 hr
= pLoadLibraryShim(fusion
, v1_1
, NULL
, &hdll
);
326 ok(hr
== S_OK
|| hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
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
);
339 hr
= pLoadLibraryShim(fusion
, v2_0
, NULL
, &hdll
);
340 ok(hr
== S_OK
|| hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
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
);
353 hr
= pLoadLibraryShim(fusion
, v4_0
, NULL
, &hdll
);
354 ok(hr
== S_OK
|| hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
357 /* LoadLibraryShim with a NULL version prefers 2.0 and earlier */
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
);
369 hr
= pLoadLibraryShim(fusion
, vbogus
, NULL
, &hdll
);
370 ok(hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
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
);
380 GetModuleFileNameA(hdll
, dllpath
, MAX_PATH
);
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
);
389 hr
= pLoadLibraryShim(fusiondll
, NULL
, NULL
, &hdll
);
390 ok(hr
== S_OK
, "LoadLibraryShim failed, hr=%lx\n", hr
);
393 GetModuleFileNameA(hdll
, dllpath
, MAX_PATH
);
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
);
402 hr
= pLoadLibraryShim(nosuchdll
, latest
, NULL
, &hdll
);
403 ok(hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
407 hr
= pLoadLibraryShim(gdidll
, latest
, NULL
, &hdll
);
408 ok(hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
413 static const char xmldata
[] =
414 "<?xml version=\"1.0\" ?>\n"
415 "<!DOCTYPE Config>\n"
417 " <Name>Test</Name>\n"
418 " <Value>1234</Value>\n"
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
);
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
];
438 char buffer
[256] = {0};
440 if (!pCreateConfigStream
)
442 win_skip("CreateConfigStream not available\n");
446 create_xml_file(file
);
447 GetFullPathNameW(file
, MAX_PATH
, path
, NULL
);
449 hr
= pCreateConfigStream(NULL
, &stream
);
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");
474 IStream
*stream2
= NULL
;
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
);
512 static void test_createinstance(void)
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");
529 hr
= pCreateInterface(&CLSID_CLRMetaHost
, &IID_ICLRMetaHost
, (void**)&host
);
532 ICLRMetaHost_Release(host
);
536 win_skip(".NET 4 not installed.\n");
540 static BOOL
write_resource(const WCHAR
*resource
, const WCHAR
*filename
)
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
);
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 };
573 if (!PathFileExistsW(csc
))
575 skip("Can't find csc.exe\n");
579 swprintf(cmdline
, ARRAY_SIZE(cmdline
), L
"%s /t:%s %s /out:\"%s\" \"%s\"", csc
, type
, args
, target
, source
);
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");
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
);
605 swprintf(newdir
, MAX_PATH
, L
"%s\\%s%04d", path
, prefix
, i
);
606 if (CreateDirectoryW(newdir
, NULL
))
608 switch (GetLastError())
610 case ERROR_ACCESS_DENIED
:
614 GetTempPathW(ARRAY_SIZE(path
), path
);
615 path
[wcslen(path
) - 1] = 0; /* redundant trailing backslash */
617 case ERROR_ALREADY_EXISTS
:
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 };
633 DWORD exit_code
= 0xdeadbeef;
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());
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, '\\')))
658 ret
= CreateDirectoryW(tmpdir
, NULL
);
659 ok(ret
, "CreateDirectoryW(%s) failed: %lu\n", debugstr_w(tmpdir
), GetLastError());
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());
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);
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;
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());
702 while (ptr
>= end
&& (ptr
= wcsrchr(tmpdir
, '\\')))
704 ret
= RemoveDirectoryW(tmpdir
);
705 ok(ret
, "RemoveDirectoryW(%s) failed: %lu\n", debugstr_w(tmpdir
), GetLastError());
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";
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
"");
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");
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
;
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 */
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
;
798 if (!pCLRCreateInstance
)
800 win_skip("Function CLRCreateInstance not found.\n");
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
);
878 if (!init_functionpointers())
881 argc
= winetest_get_mainargs(&argv
);
882 if (argc
>= 3 && !strcmp(argv
[2], "check_runtime"))
884 int result
= check_runtime();
885 FreeLibrary(hmscoree
);
890 test_loadlibraryshim();
891 test_createconfigstream();
892 test_createinstance();
894 if (runtime_is_usable())
899 test_loadpaths(FALSE
);
900 test_loadpaths(TRUE
);
902 FreeLibrary(hmscoree
);