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
, "CreateProcessA failed\n");
155 CloseHandle(pi
.hThread
);
157 WaitForSingleObject(pi
.hProcess
, INFINITE
);
159 ret
= GetExitCodeProcess(pi
.hProcess
, &exitcode
);
160 CloseHandle(pi
.hProcess
);
162 ok(ret
, "GetExitCodeProcess failed\n");
164 if (!ret
|| exitcode
!= 0)
166 todo_wine_if(!has_mono
) win_skip(".NET 4.0 runtime is not usable\n");
173 static void test_versioninfo(void)
175 const WCHAR v9_0
[] = {'v','9','.','0','.','3','0','3','1','9',0};
176 const WCHAR v2_0cap
[] = {'V','2','.','0','.','5','0','7','2','7',0};
177 const WCHAR v2_0
[] = {'v','2','.','0','.','5','0','7','2','7',0};
178 const WCHAR v2_0_0
[] = {'v','2','.','0','.','0',0};
179 const WCHAR v1_1
[] = {'v','1','.','1','.','4','3','2','2',0};
180 const WCHAR v1_1_0
[] = {'v','1','.','1','.','0',0};
182 WCHAR version
[MAX_PATH
];
183 WCHAR path
[MAX_PATH
];
184 DWORD size
, path_len
;
187 if (0) /* crashes on <= w2k3 */
189 hr
= pGetCORVersion(NULL
, MAX_PATH
, &size
);
190 ok(hr
== E_POINTER
,"GetCORVersion returned %08lx\n", hr
);
193 hr
= pGetCORVersion(version
, 1, &size
);
194 if (hr
== CLR_E_SHIM_RUNTIME
)
196 no_legacy_runtimes
= TRUE
;
197 win_skip("No legacy .NET runtimes are installed\n");
201 ok(hr
== E_NOT_SUFFICIENT_BUFFER
, "GetCORVersion returned %08lx\n", hr
);
203 hr
= pGetCORVersion(version
, MAX_PATH
, &size
);
204 ok(hr
== S_OK
,"GetCORVersion returned %08lx\n", hr
);
206 trace("latest installed .net runtime: %s\n", wine_dbgstr_w(version
));
208 hr
= pGetCORSystemDirectory(path
, MAX_PATH
, &size
);
209 todo_wine_if(!has_mono
) ok(hr
== S_OK
, "GetCORSystemDirectory returned %08lx\n", hr
);
210 /* size includes terminating null-character */
211 todo_wine_if(!has_mono
) ok(size
== (lstrlenW(path
) + 1),"size is %ld instead of %d\n", size
, (lstrlenW(path
) + 1));
215 hr
= pGetCORSystemDirectory(path
, path_len
-1 , &size
);
216 todo_wine_if(!has_mono
) ok(hr
== E_NOT_SUFFICIENT_BUFFER
, "GetCORSystemDirectory returned %08lx\n", hr
);
218 if (0) /* crashes on <= w2k3 */
220 hr
= pGetCORSystemDirectory(NULL
, MAX_PATH
, &size
);
221 ok(hr
== E_NOT_SUFFICIENT_BUFFER
, "GetCORSystemDirectory returned %08lx\n", hr
);
224 hr
= pGetCORSystemDirectory(path
, MAX_PATH
, NULL
);
225 ok(hr
== E_POINTER
,"GetCORSystemDirectory returned %08lx\n", hr
);
227 trace("latest installed .net installed in directory: %s\n", wine_dbgstr_w(path
));
229 /* test GetRequestedRuntimeInfo, first get info about different versions of runtime */
230 hr
= pGetRequestedRuntimeInfo( NULL
, v2_0
, NULL
, 0, 0, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, &size
);
232 if(hr
== CLR_E_SHIM_RUNTIME
) return; /* skipping rest of tests on win2k as .net 2.0 not installed */
234 todo_wine_if(!has_mono
) ok(hr
== S_OK
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
235 trace(" installed in directory %s is .net version %s\n", wine_dbgstr_w(path
), wine_dbgstr_w(version
));
237 hr
= pGetRequestedRuntimeInfo( NULL
, v1_1
, NULL
, 0, 0, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, &size
);
238 todo_wine_if(!has_mono
) ok(hr
== S_OK
|| hr
== CLR_E_SHIM_RUNTIME
/*v1_1 not installed*/, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
240 trace(" installed in directory %s is .net version %s\n", wine_dbgstr_w(path
), wine_dbgstr_w(version
));
241 /* version number NULL not allowed without RUNTIME_INFO_UPGRADE_VERSION flag */
242 hr
= pGetRequestedRuntimeInfo( NULL
, NULL
, NULL
, 0, 0, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, &size
);
243 ok(hr
== CLR_E_SHIM_RUNTIME
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
244 /* with RUNTIME_INFO_UPGRADE_VERSION flag and version number NULL, latest installed version is returned */
245 hr
= pGetRequestedRuntimeInfo( NULL
, NULL
, NULL
, 0, RUNTIME_INFO_UPGRADE_VERSION
, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, &size
);
246 todo_wine_if(!has_mono
) ok(hr
== S_OK
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
248 hr
= pGetRequestedRuntimeInfo( NULL
, v2_0
, NULL
, 0, 0, path
, 1, &path_len
, version
, MAX_PATH
, &size
);
249 todo_wine_if(!has_mono
) ok(hr
== E_NOT_SUFFICIENT_BUFFER
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
251 /* if one of the buffers is NULL, the other one is still happily filled */
252 memset(version
, 0, sizeof(version
));
253 hr
= pGetRequestedRuntimeInfo( NULL
, v2_0
, NULL
, 0, 0, NULL
, MAX_PATH
, &path_len
, version
, MAX_PATH
, &size
);
254 todo_wine_if(!has_mono
) ok(hr
== S_OK
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
255 ok(!wcscmp(version
, v2_0
), "version is %s , expected %s\n", wine_dbgstr_w(version
), wine_dbgstr_w(v2_0
));
256 /* With NULL-pointer for bufferlength, the buffer itself still gets filled with correct string */
257 memset(version
, 0, sizeof(version
));
258 hr
= pGetRequestedRuntimeInfo( NULL
, v2_0
, NULL
, 0, 0, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, NULL
);
259 todo_wine_if(!has_mono
) ok(hr
== S_OK
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
260 ok(!wcscmp(version
, v2_0
), "version is %s , expected %s\n", wine_dbgstr_w(version
), wine_dbgstr_w(v2_0
));
262 memset(version
, 0, sizeof(version
));
263 hr
= pGetRequestedRuntimeInfo( NULL
, v2_0cap
, NULL
, 0, 0, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, NULL
);
264 todo_wine_if(!has_mono
) ok(hr
== S_OK
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
265 ok(!wcscmp(version
, v2_0cap
), "version is %s , expected %s\n", wine_dbgstr_w(version
), wine_dbgstr_w(v2_0cap
));
267 /* Invalid Version and RUNTIME_INFO_UPGRADE_VERSION flag*/
268 memset(version
, 0, sizeof(version
));
269 hr
= pGetRequestedRuntimeInfo( NULL
, v1_1
, NULL
, 0, RUNTIME_INFO_UPGRADE_VERSION
, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, NULL
);
270 todo_wine_if(!has_mono
) ok(hr
== S_OK
|| hr
== CLR_E_SHIM_RUNTIME
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
273 /* .NET 1.1 may not be installed. */
274 ok(!wcscmp(version
, v1_1
) || !wcscmp(version
, v2_0
),
275 "version is %s , expected %s or %s\n", wine_dbgstr_w(version
), wine_dbgstr_w(v1_1
), wine_dbgstr_w(v2_0
));
279 memset(version
, 0, sizeof(version
));
280 hr
= pGetRequestedRuntimeInfo( NULL
, v9_0
, NULL
, 0, RUNTIME_INFO_UPGRADE_VERSION
, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, NULL
);
281 ok(hr
== CLR_E_SHIM_RUNTIME
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
283 memset(version
, 0, sizeof(version
));
284 hr
= pGetRequestedRuntimeInfo( NULL
, v1_1_0
, NULL
, 0, 0, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, NULL
);
285 ok(hr
== CLR_E_SHIM_RUNTIME
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
287 memset(version
, 0, sizeof(version
));
288 hr
= pGetRequestedRuntimeInfo( NULL
, v1_1_0
, NULL
, 0, RUNTIME_INFO_UPGRADE_VERSION
, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, NULL
);
289 todo_wine_if(!has_mono
) ok(hr
== S_OK
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
290 ok(!wcscmp(version
, v2_0
), "version is %s , expected %s\n", wine_dbgstr_w(version
), wine_dbgstr_w(v2_0
));
292 memset(version
, 0, sizeof(version
));
293 hr
= pGetRequestedRuntimeInfo( NULL
, v2_0_0
, NULL
, 0, 0, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, NULL
);
294 ok(hr
== CLR_E_SHIM_RUNTIME
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
296 memset(version
, 0, sizeof(version
));
297 hr
= pGetRequestedRuntimeInfo( NULL
, v2_0_0
, NULL
, 0, RUNTIME_INFO_UPGRADE_VERSION
, path
, MAX_PATH
, &path_len
, version
, MAX_PATH
, NULL
);
298 todo_wine_if(!has_mono
) ok(hr
== S_OK
, "GetRequestedRuntimeInfo returned %08lx\n", hr
);
299 ok(!wcscmp(version
, v2_0
), "version is %s , expected %s\n", wine_dbgstr_w(version
), wine_dbgstr_w(v2_0
));
301 hr
= pCorIsLatestSvc(NULL
, NULL
);
302 ok(hr
== E_POINTER
, "CorIsLatestSvc returned %08lx\n", hr
);
305 static void test_loadlibraryshim(void)
307 const WCHAR v2_0
[] = {'v','2','.','0','.','5','0','7','2','7',0};
308 const WCHAR v1_1
[] = {'v','1','.','1','.','4','3','2','2',0};
309 const WCHAR vbogus
[] = {'v','b','o','g','u','s',0};
310 const WCHAR fusion
[] = {'f','u','s','i','o','n',0};
311 const WCHAR fusiondll
[] = {'f','u','s','i','o','n','.','d','l','l',0};
312 const WCHAR nosuchdll
[] = {'j','n','v','n','l','.','d','l','l',0};
313 const WCHAR gdidll
[] = {'g','d','i','3','2','.','d','l','l',0};
315 const WCHAR
*latest
= NULL
;
316 CHAR latestA
[MAX_PATH
];
318 CHAR dllpath
[MAX_PATH
];
320 if (no_legacy_runtimes
)
322 win_skip("No legacy .NET runtimes are installed\n");
326 hr
= pLoadLibraryShim(fusion
, v1_1
, NULL
, &hdll
);
327 ok(hr
== S_OK
|| hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
332 GetModuleFileNameA(hdll
, dllpath
, MAX_PATH
);
334 todo_wine_if(!has_mono
) ok(StrStrIA(dllpath
, "v1.1.4322") != 0, "incorrect fusion.dll path %s\n", dllpath
);
335 ok(StrStrIA(dllpath
, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath
);
340 hr
= pLoadLibraryShim(fusion
, v2_0
, NULL
, &hdll
);
341 ok(hr
== S_OK
|| hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
346 GetModuleFileNameA(hdll
, dllpath
, MAX_PATH
);
348 todo_wine_if(!has_mono
) ok(StrStrIA(dllpath
, "v2.0.50727") != 0, "incorrect fusion.dll path %s\n", dllpath
);
349 ok(StrStrIA(dllpath
, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath
);
354 hr
= pLoadLibraryShim(fusion
, v4_0
, NULL
, &hdll
);
355 ok(hr
== S_OK
|| hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
358 /* LoadLibraryShim with a NULL version prefers 2.0 and earlier */
362 GetModuleFileNameA(hdll
, dllpath
, MAX_PATH
);
364 todo_wine_if(!has_mono
) ok(StrStrIA(dllpath
, "v4.0.30319") != 0, "incorrect fusion.dll path %s\n", dllpath
);
365 ok(StrStrIA(dllpath
, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath
);
370 hr
= pLoadLibraryShim(fusion
, vbogus
, NULL
, &hdll
);
371 ok(hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
375 WideCharToMultiByte(CP_ACP
, 0, latest
, -1, latestA
, MAX_PATH
, NULL
, NULL
);
377 hr
= pLoadLibraryShim(fusion
, NULL
, NULL
, &hdll
);
378 ok(hr
== S_OK
, "LoadLibraryShim failed, hr=%lx\n", hr
);
381 GetModuleFileNameA(hdll
, dllpath
, MAX_PATH
);
384 todo_wine_if(!has_mono
) ok(StrStrIA(dllpath
, latestA
) != 0, "incorrect fusion.dll path %s\n", dllpath
);
385 ok(StrStrIA(dllpath
, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath
);
390 hr
= pLoadLibraryShim(fusiondll
, NULL
, NULL
, &hdll
);
391 ok(hr
== S_OK
, "LoadLibraryShim failed, hr=%lx\n", hr
);
394 GetModuleFileNameA(hdll
, dllpath
, MAX_PATH
);
397 todo_wine_if(!has_mono
) ok(StrStrIA(dllpath
, latestA
) != 0, "incorrect fusion.dll path %s\n", dllpath
);
398 ok(StrStrIA(dllpath
, "fusion.dll") != 0, "incorrect fusion.dll path %s\n", dllpath
);
403 hr
= pLoadLibraryShim(nosuchdll
, latest
, NULL
, &hdll
);
404 ok(hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
408 hr
= pLoadLibraryShim(gdidll
, latest
, NULL
, &hdll
);
409 ok(hr
== E_HANDLE
, "LoadLibraryShim failed, hr=%lx\n", hr
);
414 static const char xmldata
[] =
415 "<?xml version=\"1.0\" ?>\n"
416 "<!DOCTYPE Config>\n"
418 " <Name>Test</Name>\n"
419 " <Value>1234</Value>\n"
422 static void create_xml_file(LPCWSTR filename
)
424 DWORD dwNumberOfBytesWritten
;
425 HANDLE hfile
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
,
426 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
427 ok(hfile
!= INVALID_HANDLE_VALUE
, "File creation failed\n");
428 WriteFile(hfile
, xmldata
, sizeof(xmldata
) - 1, &dwNumberOfBytesWritten
, NULL
);
432 static void test_createconfigstream(void)
434 IStream
*stream
= NULL
;
435 WCHAR file
[] = {'c', 'o', 'n', 'f', '.', 'x', 'm', 'l', 0};
436 WCHAR nonexistent
[] = {'n', 'o', 'n', 'e', 'x', 'i', 's', 't', '.', 'x', 'm', 'l', 0};
437 WCHAR path
[MAX_PATH
];
439 char buffer
[256] = {0};
441 if (!pCreateConfigStream
)
443 win_skip("CreateConfigStream not available\n");
447 create_xml_file(file
);
448 GetFullPathNameW(file
, MAX_PATH
, path
, NULL
);
450 hr
= pCreateConfigStream(NULL
, &stream
);
452 broken(hr
== HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND
)) || /* some WinXP, Win2K3 and Win7 */
453 broken(hr
== S_OK
&& !stream
), /* some Win2K3 */
454 "CreateConfigStream returned %lx\n", hr
);
456 hr
= pCreateConfigStream(path
, NULL
);
457 ok(hr
== COR_E_NULLREFERENCE
, "CreateConfigStream returned %lx\n", hr
);
459 hr
= pCreateConfigStream(NULL
, NULL
);
460 ok(hr
== COR_E_NULLREFERENCE
, "CreateConfigStream returned %lx\n", hr
);
462 hr
= pCreateConfigStream(nonexistent
, &stream
);
463 ok(hr
== COR_E_FILENOTFOUND
, "CreateConfigStream returned %lx\n", hr
);
464 ok(stream
== NULL
, "Expected stream to be NULL\n");
466 hr
= pCreateConfigStream(path
, &stream
);
467 ok(hr
== S_OK
, "CreateConfigStream failed, hr=%lx\n", hr
);
468 ok(stream
!= NULL
, "Expected non-NULL stream\n");
475 IStream
*stream2
= NULL
;
478 hr
= IStream_Read(stream
, buffer
, strlen(xmldata
), &count
);
479 ok(hr
== S_OK
, "IStream_Read failed, hr=%lx\n", hr
);
480 ok(count
== strlen(xmldata
), "wrong count: %lu\n", count
);
481 ok(!strcmp(buffer
, xmldata
), "Strings do not match\n");
483 hr
= IStream_Read(stream
, buffer
, sizeof(buffer
), &count
);
484 ok(hr
== S_OK
, "IStream_Read failed, hr=%lx\n", hr
);
485 ok(!count
, "wrong count: %lu\n", count
);
487 hr
= IStream_Write(stream
, xmldata
, strlen(xmldata
), &count
);
488 ok(hr
== E_FAIL
, "IStream_Write returned hr=%lx\n", hr
);
490 pos
.QuadPart
= strlen(xmldata
);
491 hr
= IStream_Seek(stream
, pos
, STREAM_SEEK_SET
, NULL
);
492 ok(hr
== E_NOTIMPL
, "IStream_Seek returned hr=%lx\n", hr
);
494 size
.QuadPart
= strlen(xmldata
);
495 hr
= IStream_SetSize(stream
, size
);
496 ok(hr
== E_NOTIMPL
, "IStream_SetSize returned hr=%lx\n", hr
);
498 hr
= IStream_Clone(stream
, &stream2
);
499 ok(hr
== E_NOTIMPL
, "IStream_Clone returned hr=%lx\n", hr
);
501 hr
= IStream_Commit(stream
, STGC_DEFAULT
);
502 ok(hr
== E_NOTIMPL
, "IStream_Commit returned hr=%lx\n", hr
);
504 hr
= IStream_Revert(stream
);
505 ok(hr
== E_NOTIMPL
, "IStream_Revert returned hr=%lx\n", hr
);
507 ref
= IStream_Release(stream
);
508 ok(!ref
, "IStream_Release returned %lu\n", ref
);
513 static void test_createinstance(void)
518 if (no_legacy_runtimes
)
520 /* If we don't have 1.x or 2.0 runtimes, we should at least have .NET 4. */
521 ok(pCreateInterface
!= NULL
, "no legacy runtimes or .NET 4 interfaces available\n");
524 if(!pCreateInterface
)
526 win_skip("Function CreateInterface not found.\n");
530 hr
= pCreateInterface(&CLSID_CLRMetaHost
, &IID_ICLRMetaHost
, (void**)&host
);
533 ICLRMetaHost_Release(host
);
537 win_skip(".NET 4 not installed.\n");
541 static BOOL
write_resource(const WCHAR
*resource
, const WCHAR
*filename
)
549 rsrc
= FindResourceW(GetModuleHandleW(NULL
), resource
, MAKEINTRESOURCEW(RT_RCDATA
));
550 if (!rsrc
) return FALSE
;
552 data
= LockResource(LoadResource(GetModuleHandleA(NULL
), rsrc
));
553 if (!data
) return FALSE
;
555 size
= SizeofResource(GetModuleHandleA(NULL
), rsrc
);
556 if (!size
) return FALSE
;
558 file
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
559 if (file
== INVALID_HANDLE_VALUE
) return FALSE
;
561 ret
= WriteFile(file
, data
, size
, &size
, NULL
);
566 static BOOL
compile_cs(const WCHAR
*source
, const WCHAR
*target
, const WCHAR
*type
, const WCHAR
*args
)
568 static const WCHAR
*csc
= L
"C:\\windows\\Microsoft.NET\\Framework\\v2.0.50727\\csc.exe";
569 WCHAR cmdline
[2 * MAX_PATH
+ 74];
570 PROCESS_INFORMATION pi
;
571 STARTUPINFOW si
= { 0 };
574 if (!PathFileExistsW(csc
))
576 skip("Can't find csc.exe\n");
580 swprintf(cmdline
, ARRAY_SIZE(cmdline
), L
"%s /t:%s %s /out:\"%s\" \"%s\"", csc
, type
, args
, target
, source
);
583 ret
= CreateProcessW(csc
, cmdline
, NULL
, NULL
, FALSE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
);
584 ok(ret
, "Could not create process: %lu\n", GetLastError());
586 wait_child_process(pi
.hProcess
);
587 CloseHandle(pi
.hThread
);
588 CloseHandle(pi
.hProcess
);
590 ret
= PathFileExistsW(target
);
591 ok(ret
, "Compilation failed\n");
596 static void test_loadpaths_execute(const WCHAR
*exe_name
, const WCHAR
*dll_name
, const WCHAR
*cfg_name
,
597 const WCHAR
*dll_dest
, BOOL expect_failure
, BOOL todo
)
599 WCHAR tmp
[MAX_PATH
], tmpdir
[MAX_PATH
], tmpexe
[MAX_PATH
], tmpcfg
[MAX_PATH
], tmpdll
[MAX_PATH
];
600 PROCESS_INFORMATION pi
;
601 STARTUPINFOW si
= { 0 };
603 DWORD exit_code
= 0xdeadbeef;
607 GetTempPathW(MAX_PATH
, tmp
);
608 ret
= AllocateLocallyUniqueId(&id
);
609 ok(ret
, "AllocateLocallyUniqueId failed: %lu\n", GetLastError());
610 ret
= GetTempFileNameW(tmp
, L
"loadpaths", id
.LowPart
, tmpdir
);
611 ok(ret
, "GetTempFileNameW failed: %lu\n", GetLastError());
613 ret
= CreateDirectoryW(tmpdir
, NULL
);
614 ok(ret
, "CreateDirectoryW(%s) failed: %lu\n", debugstr_w(tmpdir
), GetLastError());
616 wcscpy(tmpexe
, tmpdir
);
617 PathAppendW(tmpexe
, exe_name
);
618 ret
= CopyFileW(exe_name
, tmpexe
, FALSE
);
619 ok(ret
, "CopyFileW(%s) failed: %lu\n", debugstr_w(tmpexe
), GetLastError());
623 wcscpy(tmpcfg
, tmpdir
);
624 PathAppendW(tmpcfg
, cfg_name
);
625 ret
= CopyFileW(cfg_name
, tmpcfg
, FALSE
);
626 ok(ret
, "CopyFileW(%s) failed: %lu\n", debugstr_w(tmpcfg
), GetLastError());
629 ptr
= tmpdir
+ wcslen(tmpdir
);
630 PathAppendW(tmpdir
, dll_dest
);
631 while (*ptr
&& (ptr
= wcschr(ptr
+ 1, '\\')))
634 ret
= CreateDirectoryW(tmpdir
, NULL
);
635 ok(ret
, "CreateDirectoryW(%s) failed: %lu\n", debugstr_w(tmpdir
), GetLastError());
639 wcscpy(tmpdll
, tmpdir
);
640 if ((ptr
= wcsrchr(tmpdir
, '\\'))) *ptr
= '\0';
642 ret
= CopyFileW(dll_name
, tmpdll
, FALSE
);
643 ok(ret
, "CopyFileW(%s) failed: %lu\n", debugstr_w(tmpdll
), GetLastError());
646 ret
= CreateProcessW(tmpexe
, tmpexe
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
647 ok(ret
, "CreateProcessW(%s) failed: %lu\n", debugstr_w(tmpexe
), GetLastError());
649 if (expect_failure
) ret
= WaitForSingleObject(pi
.hProcess
, 2000);
652 ret
= WaitForSingleObject(pi
.hProcess
, 5000);
653 ok(ret
== WAIT_OBJECT_0
, "%s: WaitForSingleObject returned %d: %lu\n", debugstr_w(dll_dest
), ret
, GetLastError());
656 GetExitCodeProcess(pi
.hProcess
, &exit_code
);
657 if (ret
== WAIT_TIMEOUT
) TerminateProcess(pi
.hProcess
, 0xdeadbeef);
658 CloseHandle(pi
.hThread
);
659 CloseHandle(pi
.hProcess
);
661 if (expect_failure
) todo_wine_if(todo
) ok(exit_code
!= 0, "%s: Succeeded to execute process\n", debugstr_w(dll_dest
));
662 else ok(exit_code
== 0, "%s: Failed to execute process\n", debugstr_w(dll_dest
));
664 /* sometimes the failing process never returns, in which case cleaning up won't work */
665 if (ret
== WAIT_TIMEOUT
&& expect_failure
) return;
669 ret
= DeleteFileW(tmpcfg
);
670 ok(ret
, "DeleteFileW(%s) failed: %lu\n", debugstr_w(tmpcfg
), GetLastError());
672 ret
= DeleteFileW(tmpdll
);
673 ok(ret
, "DeleteFileW(%s) failed: %lu\n", debugstr_w(tmpdll
), GetLastError());
674 ret
= DeleteFileW(tmpexe
);
675 ok(ret
, "DeleteFileW(%s) failed: %lu\n", debugstr_w(tmpexe
), GetLastError());
677 end
= tmpdir
+ wcslen(tmp
);
678 ptr
= tmpdir
+ wcslen(tmpdir
) - 1;
679 while (ptr
> end
&& (ptr
= wcsrchr(tmpdir
, '\\')))
681 ret
= RemoveDirectoryW(tmpdir
);
682 ok(ret
, "RemoveDirectoryW(%s) failed: %lu\n", debugstr_w(tmpdir
), GetLastError());
687 static void test_loadpaths(BOOL neutral
)
689 static const WCHAR
*loadpaths
[] = {L
"", L
"en", L
"libloadpaths", L
"en\\libloadpaths"};
690 static const WCHAR
*dll_source
= L
"loadpaths.dll.cs";
691 static const WCHAR
*dll_name
= L
"libloadpaths.dll";
692 static const WCHAR
*exe_source
= L
"loadpaths.exe.cs";
693 static const WCHAR
*exe_name
= L
"loadpaths.exe";
694 static const WCHAR
*cfg_name
= L
"loadpaths.exe.config";
699 DeleteFileW(dll_source
);
700 ret
= write_resource(dll_source
, dll_source
);
701 ok(ret
, "Could not write resource: %lu\n", GetLastError());
702 DeleteFileW(dll_name
);
703 ret
= compile_cs(dll_source
, dll_name
, L
"library", neutral
? L
"-define:NEUTRAL" : L
"");
705 ret
= DeleteFileW(dll_source
);
706 ok(ret
, "DeleteFileW failed: %lu\n", GetLastError());
708 DeleteFileW(exe_source
);
709 ret
= write_resource(exe_source
, exe_source
);
710 ok(ret
, "Could not write resource: %lu\n", GetLastError());
711 DeleteFileW(exe_name
);
712 ret
= compile_cs(exe_source
, exe_name
, L
"winexe", L
"/reference:libloadpaths.dll");
714 ret
= DeleteFileW(exe_source
);
715 ok(ret
, "DeleteFileW failed: %lu\n", GetLastError());
717 DeleteFileW(cfg_name
);
718 ret
= write_resource(cfg_name
, cfg_name
);
719 ok(ret
, "Could not write resource: %lu\n", GetLastError());
721 for (i
= 0; i
< ARRAY_SIZE(loadpaths
); ++i
)
723 const WCHAR
*path
= loadpaths
[i
];
724 BOOL expect_failure
= neutral
? wcsstr(path
, L
"en") != NULL
725 : wcsstr(path
, L
"en") == NULL
;
728 PathAppendW(tmp
, dll_name
);
729 test_loadpaths_execute(exe_name
, dll_name
, NULL
, tmp
, expect_failure
, !neutral
&& !*path
);
731 wcscpy(tmp
, L
"private");
732 if (*path
) PathAppendW(tmp
, path
);
733 PathAppendW(tmp
, dll_name
);
735 test_loadpaths_execute(exe_name
, dll_name
, NULL
, tmp
, TRUE
, FALSE
);
736 test_loadpaths_execute(exe_name
, dll_name
, cfg_name
, tmp
, expect_failure
, FALSE
);
738 /* exe name for dll should work too */
742 PathAppendW(tmp
, dll_name
);
743 wcscpy(tmp
+ wcslen(tmp
) - 4, L
".exe");
744 test_loadpaths_execute(exe_name
, dll_name
, NULL
, tmp
, expect_failure
, FALSE
);
747 wcscpy(tmp
, L
"private");
748 if (*path
) PathAppendW(tmp
, path
);
749 PathAppendW(tmp
, dll_name
);
750 wcscpy(tmp
+ wcslen(tmp
) - 4, L
".exe");
752 test_loadpaths_execute(exe_name
, dll_name
, NULL
, tmp
, TRUE
, FALSE
);
753 test_loadpaths_execute(exe_name
, dll_name
, cfg_name
, tmp
, expect_failure
, FALSE
);
756 ret
= DeleteFileW(cfg_name
);
757 ok(ret
, "DeleteFileW failed: %lu\n", GetLastError());
758 ret
= DeleteFileW(exe_name
);
759 ok(ret
, "DeleteFileW failed: %lu\n", GetLastError());
760 ret
= DeleteFileW(dll_name
);
761 ok(ret
, "DeleteFileW failed: %lu\n", GetLastError());
764 static void test_createdomain(void)
766 static const WCHAR test_name
[] = {'t','e','s','t',0};
767 static const WCHAR test2_name
[] = {'t','e','s','t','2',0};
768 ICLRMetaHost
*metahost
;
769 ICLRRuntimeInfo
*runtimeinfo
;
770 ICorRuntimeHost
*runtimehost
;
771 IUnknown
*domain
, *defaultdomain_unk
, *defaultdomain
, *newdomain_unk
, *newdomain
, *domainsetup
,
772 *newdomain2_unk
, *newdomain2
;
775 if (!pCLRCreateInstance
)
777 win_skip("Function CLRCreateInstance not found.\n");
781 hr
= pCLRCreateInstance(&CLSID_CLRMetaHost
, &IID_ICLRMetaHost
, (void **)&metahost
);
782 ok(SUCCEEDED(hr
), "CLRCreateInstance failed, hr=%#.8lx\n", hr
);
784 hr
= ICLRMetaHost_GetRuntime(metahost
, v4_0
, &IID_ICLRRuntimeInfo
, (void **)&runtimeinfo
);
785 ok(SUCCEEDED(hr
), "ICLRMetaHost::GetRuntime failed, hr=%#.8lx\n", hr
);
787 hr
= ICLRRuntimeInfo_GetInterface(runtimeinfo
, &CLSID_CorRuntimeHost
, &IID_ICorRuntimeHost
,
788 (void **)&runtimehost
);
789 ok(SUCCEEDED(hr
), "ICLRRuntimeInfo::GetInterface failed, hr=%#.8lx\n", hr
);
791 hr
= ICorRuntimeHost_Start(runtimehost
);
792 ok(SUCCEEDED(hr
), "ICorRuntimeHost::Start failed, hr=%#.8lx\n", hr
);
794 hr
= ICorRuntimeHost_GetDefaultDomain(runtimehost
, &domain
);
795 ok(SUCCEEDED(hr
), "ICorRuntimeHost::GetDefaultDomain failed, hr=%#.8lx\n", hr
);
797 hr
= IUnknown_QueryInterface(domain
, &IID_IUnknown
, (void **)&defaultdomain_unk
);
798 ok(SUCCEEDED(hr
), "COM object doesn't support IUnknown?!\n");
800 hr
= IUnknown_QueryInterface(domain
, &IID__AppDomain
, (void **)&defaultdomain
);
801 ok(SUCCEEDED(hr
), "AppDomain object doesn't support _AppDomain interface\n");
803 IUnknown_Release(domain
);
805 hr
= ICorRuntimeHost_CreateDomain(runtimehost
, test_name
, NULL
, &domain
);
806 ok(SUCCEEDED(hr
), "ICorRuntimeHost::CreateDomain failed, hr=%#.8lx\n", hr
);
808 hr
= IUnknown_QueryInterface(domain
, &IID_IUnknown
, (void **)&newdomain_unk
);
809 ok(SUCCEEDED(hr
), "COM object doesn't support IUnknown?!\n");
811 hr
= IUnknown_QueryInterface(domain
, &IID__AppDomain
, (void **)&newdomain
);
812 ok(SUCCEEDED(hr
), "AppDomain object doesn't support _AppDomain interface\n");
814 IUnknown_Release(domain
);
816 ok(defaultdomain_unk
!= newdomain_unk
, "New and default domain objects are the same\n");
818 hr
= ICorRuntimeHost_CreateDomainSetup(runtimehost
, &domainsetup
);
819 ok(SUCCEEDED(hr
), "ICorRuntimeHost::CreateDomainSetup failed, hr=%#.8lx\n", hr
);
821 hr
= ICorRuntimeHost_CreateDomainEx(runtimehost
, test2_name
, domainsetup
, NULL
, &domain
);
822 ok(SUCCEEDED(hr
), "ICorRuntimeHost::CreateDomainEx failed, hr=%#.8lx\n", hr
);
824 hr
= IUnknown_QueryInterface(domain
, &IID_IUnknown
, (void **)&newdomain2_unk
);
825 ok(SUCCEEDED(hr
), "COM object doesn't support IUnknown?!\n");
827 hr
= IUnknown_QueryInterface(domain
, &IID__AppDomain
, (void **)&newdomain2
);
828 ok(SUCCEEDED(hr
), "AppDomain object doesn't support _AppDomain interface\n");
830 IUnknown_Release(domain
);
832 ok(defaultdomain_unk
!= newdomain2_unk
, "New and default domain objects are the same\n");
833 ok(newdomain_unk
!= newdomain2_unk
, "Both new domain objects are the same\n");
835 IUnknown_Release(newdomain2
);
836 IUnknown_Release(newdomain2_unk
);
837 IUnknown_Release(domainsetup
);
838 IUnknown_Release(newdomain
);
839 IUnknown_Release(newdomain_unk
);
840 IUnknown_Release(defaultdomain
);
841 IUnknown_Release(defaultdomain_unk
);
843 ICorRuntimeHost_Release(runtimehost
);
845 ICLRRuntimeInfo_Release(runtimeinfo
);
847 ICLRMetaHost_Release(metahost
);
855 if (!init_functionpointers())
858 argc
= winetest_get_mainargs(&argv
);
859 if (argc
>= 3 && !strcmp(argv
[2], "check_runtime"))
861 int result
= check_runtime();
862 FreeLibrary(hmscoree
);
867 test_loadlibraryshim();
868 test_createconfigstream();
869 test_createinstance();
871 if (runtime_is_usable())
876 test_loadpaths(FALSE
);
877 test_loadpaths(TRUE
);
879 FreeLibrary(hmscoree
);