1 /*
2 * Copyright 2008 James Hawkins
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 #define COBJMACROS
20
21 #include <stdio.h>
22
23 #include <windows.h>
24 #include <shlwapi.h>
25 #include <mscoree.h>
26 #include <fusion.h>
27 #include <corerror.h>
28
29 #include "wine/test.h"
30 #include "wine/list.h"
31
32 static HRESULT (WINAPI *pCreateAssemblyEnum)(IAssemblyEnum **pEnum,
33 IUnknown *pUnkReserved,
34 IAssemblyName *pName,
35 DWORD dwFlags, LPVOID pvReserved);
36 static HRESULT (WINAPI *pCreateAssemblyNameObject)(IAssemblyName **ppAssemblyNameObj,
37 LPCWSTR szAssemblyName, DWORD dwFlags,
38 LPVOID pvReserved);
39 static HRESULT (WINAPI *pGetCachePath)(ASM_CACHE_FLAGS dwCacheFlags,
40 LPWSTR pwzCachePath, PDWORD pcchPath);
41 static HRESULT (WINAPI *pLoadLibraryShim)(LPCWSTR szDllName, LPCWSTR szVersion,
42 LPVOID pvReserved, HMODULE *phModDll);
43
init_functionpointers(void)44 static BOOL init_functionpointers(void)
45 {
46 HRESULT hr;
47 HMODULE hfusion;
48 HMODULE hmscoree;
49
50 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
51
52 hmscoree = LoadLibraryA("mscoree.dll");
53 if (!hmscoree)
54 {
55 win_skip("mscoree.dll not available\n");
56 return FALSE;
57 }
58
59 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
60 if (!pLoadLibraryShim)
61 {
62 win_skip("LoadLibraryShim not available\n");
63 FreeLibrary(hmscoree);
64 return FALSE;
65 }
66
67 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
68 if (FAILED(hr))
69 {
70 win_skip("fusion.dll not available\n");
71 FreeLibrary(hmscoree);
72 return FALSE;
73 }
74
75 pCreateAssemblyEnum = (void *)GetProcAddress(hfusion, "CreateAssemblyEnum");
76 pCreateAssemblyNameObject = (void *)GetProcAddress(hfusion, "CreateAssemblyNameObject");
77 pGetCachePath = (void *)GetProcAddress(hfusion, "GetCachePath");
78
79 if (!pCreateAssemblyEnum ||
80 !pCreateAssemblyNameObject || !pGetCachePath)
81 {
82 win_skip("fusion.dll not implemented\n");
83 return FALSE;
84 }
85
86 FreeLibrary(hmscoree);
87 return TRUE;
88 }
89
to_widechar(LPWSTR dest,LPCSTR src)90 static inline void to_widechar(LPWSTR dest, LPCSTR src)
91 {
92 MultiByteToWideChar(CP_ACP, 0, src, -1, dest, MAX_PATH);
93 }
94
to_multibyte(LPSTR dest,LPWSTR src)95 static inline void to_multibyte(LPSTR dest, LPWSTR src)
96 {
97 WideCharToMultiByte(CP_ACP, 0, src, -1, dest, MAX_PATH, NULL, NULL);
98 }
99
create_full_path(LPCSTR path)100 static BOOL create_full_path(LPCSTR path)
101 {
102 LPSTR new_path;
103 BOOL ret = TRUE;
104 int len;
105
106 new_path = HeapAlloc(GetProcessHeap(), 0, lstrlenA(path) + 1);
107 if (!new_path)
108 return FALSE;
109
110 lstrcpyA(new_path, path);
111
112 while ((len = lstrlenA(new_path)) && new_path[len - 1] == '\\')
113 new_path[len - 1] = 0;
114
115 while (!CreateDirectoryA(new_path, NULL))
116 {
117 LPSTR slash;
118 DWORD last_error = GetLastError();
119
120 if(last_error == ERROR_ALREADY_EXISTS)
121 break;
122
123 if(last_error != ERROR_PATH_NOT_FOUND)
124 {
125 ret = FALSE;
126 break;
127 }
128
129 if(!(slash = strrchr(new_path, '\\')))
130 {
131 ret = FALSE;
132 break;
133 }
134
135 len = slash - new_path;
136 new_path[len] = 0;
137 if(!create_full_path(new_path))
138 {
139 ret = FALSE;
140 break;
141 }
142
143 new_path[len] = '\\';
144 }
145
146 HeapFree(GetProcessHeap(), 0, new_path);
147 return ret;
148 }
149
create_file_data(LPCSTR name,LPCSTR data,DWORD size)150 static BOOL create_file_data(LPCSTR name, LPCSTR data, DWORD size)
151 {
152 HANDLE file;
153 DWORD written;
154
155 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
156 if (file == INVALID_HANDLE_VALUE)
157 return FALSE;
158
159 WriteFile(file, data, strlen(data), &written, NULL);
160
161 if (size)
162 {
163 SetFilePointer(file, size, NULL, FILE_BEGIN);
164 SetEndOfFile(file);
165 }
166
167 CloseHandle(file);
168 return TRUE;
169 }
170
test_CreateAssemblyEnum(void)171 static void test_CreateAssemblyEnum(void)
172 {
173 HRESULT hr;
174 WCHAR namestr[MAX_PATH];
175 IAssemblyEnum *asmenum;
176 IAssemblyName *asmname;
177
178 to_widechar(namestr, "wine");
179 asmname = NULL;
180 hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
181 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
182 ok(asmname != NULL, "Expected non-NULL asmname\n");
183
184 /* pEnum is NULL */
185 if (0)
186 {
187 /* Crashes on .NET 1.x */
188 hr = pCreateAssemblyEnum(NULL, NULL, asmname, ASM_CACHE_GAC, NULL);
189 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
190 }
191
192 /* pName is NULL */
193 asmenum = NULL;
194 hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_GAC, NULL);
195 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
196 ok(asmenum != NULL, "Expected non-NULL asmenum\n");
197
198 IAssemblyEnum_Release(asmenum);
199
200 /* dwFlags is ASM_CACHE_ROOT */
201 asmenum = (IAssemblyEnum *)0xdeadbeef;
202 hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_ROOT, NULL);
203 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
204 ok(asmenum == (IAssemblyEnum *)0xdeadbeef,
205 "Expected asmenum to be unchanged, got %p\n", asmenum);
206
207 /* invalid dwFlags */
208 asmenum = (IAssemblyEnum *)0xdeadbeef;
209 hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, 0, NULL);
210 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
211 ok(asmenum == (IAssemblyEnum *)0xdeadbeef,
212 "Expected asmenum to be unchanged, got %p\n", asmenum);
213
214 IAssemblyName_Release(asmname);
215 }
216
217 typedef struct _tagASMNAME
218 {
219 struct list entry;
220 char data[1];
221 } ASMNAME;
222
enum_gac_assembly_dirs(struct list * assemblies,const char * parent,char path[MAX_PATH])223 static void enum_gac_assembly_dirs(struct list *assemblies, const char *parent, char path[MAX_PATH])
224 {
225 static const char format[] = "%s, Version=%s, Culture=%s, PublicKeyToken=%s";
226 WIN32_FIND_DATAA ffd;
227 ASMNAME *name;
228 HANDLE hfind;
229 int len;
230 char *ptr, *end = path + strlen( path );
231
232 lstrcpynA( end, "\\*", path + MAX_PATH - end );
233 hfind = FindFirstFileA(path, &ffd);
234 if (hfind == INVALID_HANDLE_VALUE) return;
235 end++;
236
237 do
238 {
239 char culture[MAX_PATH];
240
241 if (!strcmp(ffd.cFileName, ".") || !strcmp(ffd.cFileName, "..")) continue;
242
243 *end = 0;
244 /* Directories with no dll or exe will not be enumerated */
245 sprintf(end, "%s\\%s.dll", ffd.cFileName, parent);
246 if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES)
247 {
248 sprintf(end, "%s\\%s.exe", ffd.cFileName, parent);
249 if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES) continue;
250 }
251
252 if (!(ptr = strchr(ffd.cFileName, '_'))) continue;
253 *ptr++ = 0;
254
255 if (*ptr != '_')
256 {
257 lstrcpyA(culture, ptr);
258 *strchr(culture, '_') = 0;
259 }
260 else
261 lstrcpyA(culture, "neutral");
262
263 ptr = strchr(ptr, '_');
264 ptr++;
265 len = sizeof(format) + strlen(parent) + strlen(ffd.cFileName) + strlen(culture) + strlen(ptr);
266
267 name = HeapAlloc(GetProcessHeap(), 0, offsetof( ASMNAME, data[len] ));
268 sprintf( name->data, format, parent, ffd.cFileName, culture, ptr);
269 list_add_tail(assemblies, &name->entry);
270 } while (FindNextFileA(hfind, &ffd) != 0);
271
272 FindClose(hfind);
273 }
274
enum_gac_assemblies(struct list * assemblies,char path[MAX_PATH])275 static void enum_gac_assemblies(struct list *assemblies, char path[MAX_PATH])
276 {
277 WIN32_FIND_DATAA ffd;
278 HANDLE hfind;
279 char *end = path + strlen( path );
280
281 lstrcpynA( end, "\\*", path + MAX_PATH - end );
282 hfind = FindFirstFileA(path, &ffd);
283 if (hfind == INVALID_HANDLE_VALUE) return;
284 end++;
285
286 do
287 {
288 if (!strcmp(ffd.cFileName, ".") || !strcmp(ffd.cFileName, "..")) continue;
289 lstrcpynA( end, ffd.cFileName, path + MAX_PATH - end );
290 enum_gac_assembly_dirs( assemblies, ffd.cFileName, path );
291 } while (FindNextFileA(hfind, &ffd) != 0);
292
293 FindClose(hfind);
294 }
295
test_enumerate(void)296 static void test_enumerate(void)
297 {
298 struct list assemblies = LIST_INIT(assemblies);
299 struct list *item, *cursor;
300 IAssemblyEnum *asmenum;
301 IAssemblyName *next;
302 WCHAR buf[MAX_PATH];
303 CHAR path[MAX_PATH];
304 CHAR disp[MAX_PATH];
305 HRESULT hr;
306 BOOL found;
307 DWORD size;
308
309 size = MAX_PATH;
310 hr = pGetCachePath(ASM_CACHE_GAC, buf, &size);
311 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
312
313 to_multibyte(path, buf);
314 lstrcatA(path, "_32");
315 enum_gac_assemblies(&assemblies, path);
316
317 to_multibyte(path, buf);
318 lstrcatA(path, "_64");
319 enum_gac_assemblies(&assemblies, path);
320
321 to_multibyte(path, buf);
322 lstrcatA(path, "_MSIL");
323 enum_gac_assemblies(&assemblies, path);
324
325 to_multibyte(path, buf);
326 enum_gac_assemblies(&assemblies, path);
327
328 asmenum = NULL;
329 hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_GAC, NULL);
330 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
331 ok(asmenum != NULL, "Expected non-NULL asmenum\n");
332
333 while (IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0) == S_OK)
334 {
335 size = MAX_PATH;
336 IAssemblyName_GetDisplayName(next, buf, &size, 0);
337 to_multibyte(disp, buf);
338
339 found = FALSE;
340 LIST_FOR_EACH_SAFE(item, cursor, &assemblies)
341 {
342 ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry);
343
344 if (!lstrcmpA(asmname->data, disp))
345 {
346 found = TRUE;
347
348 list_remove(&asmname->entry);
349 HeapFree(GetProcessHeap(), 0, asmname);
350 break;
351 }
352 }
353
354 ok(found, "Extra assembly enumerated: %s\n", disp);
355 IAssemblyName_Release(next);
356 }
357
358 /* enumeration is exhausted */
359 next = (IAssemblyName *)0xdeadbeef;
360 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
361 ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
362 ok(next == (IAssemblyName *)0xdeadbeef,
363 "Expected next to be unchanged, got %p\n", next);
364
365 LIST_FOR_EACH_SAFE(item, cursor, &assemblies)
366 {
367 ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry);
368
369 ok(FALSE, "Assembly not enumerated: %s\n", asmname->data);
370
371 list_remove(&asmname->entry);
372 HeapFree(GetProcessHeap(), 0, asmname);
373 }
374
375 IAssemblyEnum_Release(asmenum);
376 }
377
test_enumerate_name(void)378 static void test_enumerate_name(void)
379 {
380 IAssemblyEnum *asmenum;
381 IAssemblyName *asmname, *next;
382 WCHAR buf[MAX_PATH];
383 CHAR gac[MAX_PATH];
384 CHAR path[MAX_PATH];
385 CHAR disp[MAX_PATH];
386 WCHAR namestr[MAX_PATH];
387 CHAR exp[6][MAX_PATH];
388 HRESULT hr;
389 DWORD size;
390
391 lstrcpyA(exp[0], "wine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d");
392 lstrcpyA(exp[1], "wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=123456789abcdef0");
393 lstrcpyA(exp[2], "wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d");
394 lstrcpyA(exp[3], "Wine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d");
395 lstrcpyA(exp[4], "Wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=123456789abcdef0");
396 lstrcpyA(exp[5], "Wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d");
397
398 size = MAX_PATH;
399 hr = pGetCachePath(ASM_CACHE_GAC, buf, &size);
400 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
401
402 to_multibyte(gac, buf);
403 create_full_path(gac);
404
405 sprintf(path, "%s\\Wine", gac);
406 CreateDirectoryA(path, NULL);
407
408 sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d", gac);
409 CreateDirectoryA(path, NULL);
410
411 lstrcatA(path, "\\Wine.dll");
412 if (!create_file_data(path, path, 100))
413 {
414 win_skip("Failed to open file %s, skipping name enumeration tests\n", path);
415 goto done;
416 }
417
418 sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac);
419 CreateDirectoryA(path, NULL);
420
421 lstrcatA(path, "\\Wine.dll");
422 if (!create_file_data(path, path, 100))
423 {
424 win_skip("Failed to open file %s, skipping name enumeration tests\n", path);
425 goto done;
426 }
427
428 sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac);
429 CreateDirectoryA(path, NULL);
430
431 lstrcatA(path, "\\Wine.dll");
432 if (!create_file_data(path, path, 100))
433 {
434 win_skip("Failed to open file %s, skipping name enumeration tests\n", path);
435 goto done;
436 }
437
438 /* test case sensitivity */
439 to_widechar(namestr, "wine");
440 asmname = NULL;
441 hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
442 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
443 ok(asmname != NULL, "Expected non-NULL asmname\n");
444
445 asmenum = NULL;
446 hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
447 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
448 ok(asmenum != NULL, "Expected non-NULL asmenum\n");
449
450 next = NULL;
451 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
452 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
453 ok(next != NULL, "Expected non-NULL next\n");
454
455 size = MAX_PATH;
456 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
457 to_multibyte(disp, buf);
458 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
459 ok(!lstrcmpA(disp, exp[0]),
460 "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[0], exp[1], disp);
461
462 IAssemblyName_Release(next);
463
464 next = NULL;
465 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
466 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
467 ok(next != NULL, "Expected non-NULL next\n");
468
469 size = MAX_PATH;
470 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
471 to_multibyte(disp, buf);
472 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
473 ok(!lstrcmpA(disp, exp[1]) ||
474 !lstrcmpA(disp, exp[2]), /* Win98 */
475 "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp);
476
477 IAssemblyName_Release(next);
478
479 next = NULL;
480 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
481 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
482 ok(next != NULL, "Expected non-NULL next\n");
483
484 size = MAX_PATH;
485 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
486 to_multibyte(disp, buf);
487 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
488 ok(!lstrcmpA(disp, exp[2]) ||
489 !lstrcmpA(disp, exp[1]), /* Win98 */
490 "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[2], exp[1], disp);
491
492 IAssemblyName_Release(next);
493
494 next = (IAssemblyName *)0xdeadbeef;
495 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
496 ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
497 ok(next == (IAssemblyName *)0xdeadbeef,
498 "Expected next to be unchanged, got %p\n", next);
499
500 IAssemblyEnum_Release(asmenum);
501 IAssemblyName_Release(asmname);
502
503 /* only Version */
504 to_widechar(namestr, "Wine, Version=1.0.1.2");
505 asmname = NULL;
506 hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
507 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
508 ok(asmname != NULL, "Expected non-NULL asmname\n");
509
510 asmenum = NULL;
511 hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
512 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
513 ok(asmenum != NULL, "Expected non-NULL asmenum\n");
514
515 next = NULL;
516 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
517 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
518 ok(next != NULL, "Expected non-NULL next\n");
519
520 size = MAX_PATH;
521 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
522 to_multibyte(disp, buf);
523 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
524 ok(!lstrcmpA(disp, exp[4]) ||
525 !lstrcmpA(disp, exp[5]), /* Win98 */
526 "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[4], exp[5], disp);
527
528 IAssemblyName_Release(next);
529
530 next = NULL;
531 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
532 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
533 ok(next != NULL, "Expected non-NULL next\n");
534
535 size = MAX_PATH;
536 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
537 to_multibyte(disp, buf);
538 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
539 ok(!lstrcmpA(disp, exp[5]) ||
540 !lstrcmpA(disp, exp[4]), /* Win98 */
541 "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[5], exp[4], disp);
542
543 IAssemblyName_Release(next);
544
545 next = (IAssemblyName *)0xdeadbeef;
546 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
547 ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
548 ok(next == (IAssemblyName *)0xdeadbeef,
549 "Expected next to be unchanged, got %p\n", next);
550
551 IAssemblyEnum_Release(asmenum);
552 IAssemblyName_Release(asmname);
553
554 /* only PublicKeyToken */
555 to_widechar(namestr, "Wine, PublicKeyToken=16a3fcd171e93a8d");
556 asmname = NULL;
557 hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
558 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
559 ok(asmname != NULL, "Expected non-NULL asmname\n");
560
561 asmenum = NULL;
562 hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
563 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
564 ok(asmenum != NULL, "Expected non-NULL asmenum\n");
565
566 next = NULL;
567 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
568 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
569 ok(next != NULL, "Expected non-NULL next\n");
570
571 size = MAX_PATH;
572 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
573 to_multibyte(disp, buf);
574 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
575 ok(!lstrcmpA(disp, exp[3]), "Expected \"%s\", got \"%s\"\n", exp[3], disp);
576
577 IAssemblyName_Release(next);
578
579 next = NULL;
580 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
581 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
582 ok(next != NULL, "Expected non-NULL next\n");
583
584 size = MAX_PATH;
585 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
586 to_multibyte(disp, buf);
587 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
588 ok(!lstrcmpA(disp, exp[5]), "Expected \"%s\", got \"%s\"\n", exp[5], disp);
589
590 IAssemblyName_Release(next);
591
592 next = (IAssemblyName *)0xdeadbeef;
593 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
594 ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
595 ok(next == (IAssemblyName *)0xdeadbeef,
596 "Expected next to be unchanged, got %p\n", next);
597
598 IAssemblyEnum_Release(asmenum);
599 IAssemblyName_Release(asmname);
600
601 /* only Culture */
602 to_widechar(namestr, "wine, Culture=neutral");
603 asmname = NULL;
604 hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
605 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
606 ok(asmname != NULL, "Expected non-NULL asmname\n");
607
608 asmenum = NULL;
609 hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
610 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
611 ok(asmenum != NULL, "Expected non-NULL asmenum\n");
612
613 next = NULL;
614 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
615 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
616 ok(next != NULL, "Expected non-NULL next\n");
617
618 size = MAX_PATH;
619 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
620 to_multibyte(disp, buf);
621 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
622 ok(!lstrcmpA(disp, exp[0]), "Expected \"%s\", got \"%s\"\n", exp[0], disp);
623
624 IAssemblyName_Release(next);
625
626 next = NULL;
627 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
628 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
629 ok(next != NULL, "Expected non-NULL next\n");
630
631 size = MAX_PATH;
632 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
633 to_multibyte(disp, buf);
634 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
635 ok(!lstrcmpA(disp, exp[1]) ||
636 !lstrcmpA(disp, exp[2]), /* Win98 */
637 "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp);
638
639 IAssemblyName_Release(next);
640
641 next = NULL;
642 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
643 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
644 ok(next != NULL, "Expected non-NULL next\n");
645
646 size = MAX_PATH;
647 hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
648 to_multibyte(disp, buf);
649 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
650 ok(!lstrcmpA(disp, exp[2]) ||
651 !lstrcmpA(disp, exp[1]), /* Win98 */
652 "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[2], exp[1], disp);
653
654 IAssemblyName_Release(next);
655
656 next = (IAssemblyName *)0xdeadbeef;
657 hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
658 ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
659 ok(next == (IAssemblyName *)0xdeadbeef,
660 "Expected next to be unchanged, got %p\n", next);
661
662 IAssemblyEnum_Release(asmenum);
663 IAssemblyName_Release(asmname);
664
665 done:
666 sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d\\Wine.dll", gac);
667 DeleteFileA(path);
668 sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d\\Wine.dll", gac);
669 DeleteFileA(path);
670 sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0\\Wine.dll", gac);
671 DeleteFileA(path);
672 sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d", gac);
673 RemoveDirectoryA(path);
674 sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac);
675 RemoveDirectoryA(path);
676 sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac);
677 RemoveDirectoryA(path);
678 sprintf(path, "%s\\Wine", gac);
679 RemoveDirectoryA(path);
680 }
681
START_TEST(asmenum)682 START_TEST(asmenum)
683 {
684 if (!init_functionpointers())
685 return;
686
687 test_CreateAssemblyEnum();
688 test_enumerate();
689 test_enumerate_name();
690 }
691