mscoree: Implement LoadLibraryShim.
[wine] / dlls / mscoree / tests / mscoree.c
1 /*
2  * Copyright 2010 Louis Lenders
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "corerror.h"
20 #include "mscoree.h"
21 #include "wine/test.h"
22
23 static HMODULE hmscoree;
24
25 static HRESULT (WINAPI *pGetCORVersion)(LPWSTR, DWORD, DWORD*);
26 static HRESULT (WINAPI *pGetCORSystemDirectory)(LPWSTR, DWORD, DWORD*);
27 static HRESULT (WINAPI *pGetRequestedRuntimeInfo)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, DWORD, LPWSTR, DWORD, DWORD*, LPWSTR, DWORD, DWORD*);
28 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR, LPCWSTR, LPVOID, HMODULE*);
29
30 static WCHAR tolowerW( WCHAR ch )
31 {
32     if (ch >= 'A' && ch <= 'Z') return ch|32;
33     else return ch;
34 }
35
36 static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub )
37 {
38     while (*str)
39     {
40         const WCHAR *p1 = str, *p2 = sub;
41         while (*p1 && *p2 && tolowerW(*p1) == tolowerW(*p2)) { p1++; p2++; }
42         if (!*p2) return (WCHAR *)str;
43         str++;
44     }
45     return NULL;
46 }
47
48 static BOOL init_functionpointers(void)
49 {
50     hmscoree = LoadLibraryA("mscoree.dll");
51
52     if (!hmscoree)
53     {
54         win_skip("mscoree.dll not available\n");
55         return FALSE;
56     }
57
58     pGetCORVersion = (void *)GetProcAddress(hmscoree, "GetCORVersion");
59     pGetCORSystemDirectory = (void *)GetProcAddress(hmscoree, "GetCORSystemDirectory");
60     pGetRequestedRuntimeInfo = (void *)GetProcAddress(hmscoree, "GetRequestedRuntimeInfo");
61     pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
62
63     if (!pGetCORVersion || !pGetCORSystemDirectory || !pGetRequestedRuntimeInfo || !pLoadLibraryShim)
64     {
65         win_skip("functions not available\n");
66         FreeLibrary(hmscoree);
67         return FALSE;
68     }
69
70     return TRUE;
71 }
72
73 static void test_versioninfo(void)
74 {
75     const WCHAR v2_0[] = {'v','2','.','0','.','5','0','7','2','7',0};
76     const WCHAR v1_1[] = {'v','1','.','1','.','4','3','2','2',0};
77
78     WCHAR version[MAX_PATH];
79     WCHAR path[MAX_PATH];
80     DWORD size, path_len;
81     HRESULT hr;
82
83     if (0)  /* crashes on <= w2k3 */
84     {
85         hr = pGetCORVersion(NULL, MAX_PATH, &size);
86         ok(hr == E_POINTER,"GetCORVersion returned %08x\n", hr);
87     }
88
89     hr =  pGetCORVersion(version, 1, &size);
90     ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER),"GetCORVersion returned %08x\n", hr);
91
92     hr =  pGetCORVersion(version, MAX_PATH, &size);
93     ok(hr == S_OK,"GetCORVersion returned %08x\n", hr);
94
95     trace("latest installed .net runtime: %s\n", wine_dbgstr_w(version));
96
97     hr = pGetCORSystemDirectory(path, MAX_PATH , &size);
98     ok(hr == S_OK, "GetCORSystemDirectory returned %08x\n", hr);
99     /* size includes terminating null-character */
100     ok(size == (lstrlenW(path) + 1),"size is %d instead of %d\n", size, (lstrlenW(path) + 1));
101
102     path_len = size;
103
104     hr = pGetCORSystemDirectory(path, path_len-1 , &size);
105     ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "GetCORSystemDirectory returned %08x\n", hr);
106
107     if (0)  /* crashes on <= w2k3 */
108     {
109         hr = pGetCORSystemDirectory(NULL, MAX_PATH , &size);
110         ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "GetCORSystemDirectory returned %08x\n", hr);
111     }
112
113     hr = pGetCORSystemDirectory(path, MAX_PATH , NULL);
114     ok(hr == E_POINTER,"GetCORSystemDirectory returned %08x\n", hr);
115
116     trace("latest installed .net installed in directory: %s\n", wine_dbgstr_w(path));
117
118     /* test GetRequestedRuntimeInfo, first get info about different versions of runtime */
119     hr = pGetRequestedRuntimeInfo( NULL, v2_0, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, &size);
120
121     if(hr == CLR_E_SHIM_RUNTIME) return; /* skipping rest of tests on win2k as .net 2.0 not installed */
122
123     ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08x\n", hr);
124     trace(" installed in directory %s is .net version %s\n", wine_dbgstr_w(path), wine_dbgstr_w(version));
125
126     hr = pGetRequestedRuntimeInfo( NULL, v1_1, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, &size);
127     ok(hr == S_OK || CLR_E_SHIM_RUNTIME /*v1_1 not installed*/, "GetRequestedRuntimeInfo returned %08x\n", hr);
128     if(hr == S_OK)
129         trace(" installed in directory %s is .net version %s\n", wine_dbgstr_w(path), wine_dbgstr_w(version));
130     /* version number NULL not allowed without RUNTIME_INFO_UPGRADE_VERSION flag */
131     hr = pGetRequestedRuntimeInfo( NULL, NULL, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, &size);
132     ok(hr == CLR_E_SHIM_RUNTIME, "GetRequestedRuntimeInfo returned %08x\n", hr);
133     /* with RUNTIME_INFO_UPGRADE_VERSION flag and version number NULL, latest installed version is returned */
134     hr = pGetRequestedRuntimeInfo( NULL, NULL, NULL, 0, RUNTIME_INFO_UPGRADE_VERSION, path, MAX_PATH, &path_len, version, MAX_PATH, &size);
135     ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08x\n", hr);
136
137     hr = pGetRequestedRuntimeInfo( NULL, v2_0, NULL, 0, 0, path, 1, &path_len, version, MAX_PATH, &size);
138     ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "GetRequestedRuntimeInfo returned %08x\n", hr);
139
140     /* if one of the buffers is NULL, the other one is still happily filled */
141     memset(version, 0, sizeof(version));
142     hr = pGetRequestedRuntimeInfo( NULL, v2_0, NULL, 0, 0, NULL, MAX_PATH, &path_len, version, MAX_PATH, &size);
143     ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08x\n", hr);
144     ok(!lstrcmpW(version, v2_0), "version is %s , expected %s\n", wine_dbgstr_w(version), wine_dbgstr_w(v2_0));
145     /* With NULL-pointer for bufferlength, the buffer itsself still gets filled with correct string */
146     memset(version, 0, sizeof(version));
147     hr = pGetRequestedRuntimeInfo( NULL, v2_0, NULL, 0, 0, path, MAX_PATH, &path_len, version, MAX_PATH, NULL);
148     ok(hr == S_OK, "GetRequestedRuntimeInfo returned %08x\n", hr);
149     ok(!lstrcmpW(version, v2_0), "version is %s , expected %s\n", wine_dbgstr_w(version), wine_dbgstr_w(v2_0));
150 }
151
152 static void test_loadlibraryshim(void)
153 {
154     const WCHAR v4_0[] = {'v','4','.','0','.','3','0','3','1','9',0};
155     const WCHAR v2_0[] = {'v','2','.','0','.','5','0','7','2','7',0};
156     const WCHAR v1_1[] = {'v','1','.','1','.','4','3','2','2',0};
157     const WCHAR vbogus[] = {'v','b','o','g','u','s',0};
158     const WCHAR fusion[] = {'f','u','s','i','o','n',0};
159     const WCHAR fusiondll[] = {'f','u','s','i','o','n','.','d','l','l',0};
160     const WCHAR nosuchdll[] = {'j','n','v','n','l','.','d','l','l',0};
161     const WCHAR gdipdll[] = {'g','d','i','p','l','u','s','.','d','l','l',0};
162     const WCHAR gdidll[] = {'g','d','i','3','2','.','d','l','l',0};
163     HRESULT hr;
164     const WCHAR *latest = NULL;
165     HMODULE hdll;
166     WCHAR dllpath[MAX_PATH];
167
168     hr = pLoadLibraryShim(fusion, v1_1, NULL, &hdll);
169     ok(hr == S_OK || hr == E_HANDLE, "LoadLibraryShim failed, hr=%x\n", hr);
170     if (SUCCEEDED(hr))
171     {
172         latest = v1_1;
173
174         GetModuleFileNameW(hdll, dllpath, MAX_PATH);
175
176         todo_wine ok(strstriW(dllpath, v1_1) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
177         ok(strstriW(dllpath, fusiondll) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
178
179         FreeLibrary(hdll);
180     }
181
182     hr = pLoadLibraryShim(fusion, v2_0, NULL, &hdll);
183     ok(hr == S_OK || hr == E_HANDLE, "LoadLibraryShim failed, hr=%x\n", hr);
184     if (SUCCEEDED(hr))
185     {
186         latest = v2_0;
187
188         GetModuleFileNameW(hdll, dllpath, MAX_PATH);
189
190         todo_wine ok(strstriW(dllpath, v2_0) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
191         ok(strstriW(dllpath, fusiondll) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
192
193         FreeLibrary(hdll);
194     }
195
196     hr = pLoadLibraryShim(fusion, v4_0, NULL, &hdll);
197     ok(hr == S_OK || hr == E_HANDLE, "LoadLibraryShim failed, hr=%x\n", hr);
198     if (SUCCEEDED(hr))
199     {
200         /* LoadLibraryShim with a NULL version prefers 2.0 and earlier */
201         if (!latest)
202             latest = v4_0;
203
204         GetModuleFileNameW(hdll, dllpath, MAX_PATH);
205
206         todo_wine ok(strstriW(dllpath, v4_0) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
207         ok(strstriW(dllpath, fusiondll) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
208
209         FreeLibrary(hdll);
210     }
211
212     hr = pLoadLibraryShim(fusion, vbogus, NULL, &hdll);
213     todo_wine ok(hr == E_HANDLE, "LoadLibraryShim failed, hr=%x\n", hr);
214     if (SUCCEEDED(hr))
215         FreeLibrary(hdll);
216
217     hr = pLoadLibraryShim(fusion, NULL, NULL, &hdll);
218     ok(hr == S_OK, "LoadLibraryShim failed, hr=%x\n", hr);
219     if (SUCCEEDED(hr))
220     {
221         GetModuleFileNameW(hdll, dllpath, MAX_PATH);
222
223         if (latest)
224             todo_wine ok(strstriW(dllpath, latest) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
225         ok(strstriW(dllpath, fusiondll) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
226
227         FreeLibrary(hdll);
228     }
229
230     hr = pLoadLibraryShim(fusiondll, NULL, NULL, &hdll);
231     ok(hr == S_OK, "LoadLibraryShim failed, hr=%x\n", hr);
232     if (SUCCEEDED(hr))
233     {
234         GetModuleFileNameW(hdll, dllpath, MAX_PATH);
235
236         if (latest)
237             todo_wine ok(strstriW(dllpath, latest) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
238         ok(strstriW(dllpath, fusiondll) != 0, "incorrect fusion.dll path %s\n", wine_dbgstr_w(dllpath));
239
240         FreeLibrary(hdll);
241     }
242
243     hr = pLoadLibraryShim(nosuchdll, latest, NULL, &hdll);
244     ok(hr == E_HANDLE, "LoadLibraryShim failed, hr=%x\n", hr);
245     if (SUCCEEDED(hr))
246         FreeLibrary(hdll);
247
248     hr = pLoadLibraryShim(gdipdll, latest, NULL, &hdll);
249     todo_wine ok(hr == E_HANDLE, "LoadLibraryShim failed, hr=%x\n", hr);
250     if (SUCCEEDED(hr))
251         FreeLibrary(hdll);
252
253     hr = pLoadLibraryShim(gdidll, latest, NULL, &hdll);
254     todo_wine ok(hr == E_HANDLE, "LoadLibraryShim failed, hr=%x\n", hr);
255     if (SUCCEEDED(hr))
256         FreeLibrary(hdll);
257 }
258
259 START_TEST(mscoree)
260 {
261     if (!init_functionpointers())
262         return;
263
264     test_versioninfo();
265     test_loadlibraryshim();
266
267     FreeLibrary(hmscoree);
268 }