fusion/tests: Don't crash if we have a culture attribute.
[wine] / dlls / fusion / tests / asmenum.c
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)(LPASSEMBLYNAME *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
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         skip("mscoree.dll not available\n");
56         return FALSE;
57     }
58
59     pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
60     if (!pLoadLibraryShim)
61     {
62         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         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         skip("fusion.dll not implemented\n");
83         return FALSE;
84     }
85
86     FreeLibrary(hmscoree);
87     return TRUE;
88 }
89
90 static inline void to_widechar(LPWSTR dest, LPCSTR src)
91 {
92     MultiByteToWideChar(CP_ACP, 0, src, -1, dest, MAX_PATH);
93 }
94
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
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
150 static void 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     ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
157     WriteFile(file, data, strlen(data), &written, NULL);
158
159     if (size)
160     {
161         SetFilePointer(file, size, NULL, FILE_BEGIN);
162         SetEndOfFile(file);
163     }
164
165     CloseHandle(file);
166 }
167
168 #define create_file(name, size) create_file_data(name, name, size)
169
170 static void test_CreateAssemblyEnum(void)
171 {
172     HRESULT hr;
173     WCHAR namestr[MAX_PATH];
174     IAssemblyEnum *asmenum;
175     IAssemblyName *asmname;
176
177     to_widechar(namestr, "wine");
178     asmname = NULL;
179     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
180     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
181     ok(asmname != NULL, "Expected non-NULL asmname\n");
182
183     /* pEnum is NULL */
184     if (0)
185     {
186         /* Crashes on .NET 1.x */
187         hr = pCreateAssemblyEnum(NULL, NULL, asmname, ASM_CACHE_GAC, NULL);
188         ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
189     }
190
191     /* pName is NULL */
192     asmenum = NULL;
193     hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_GAC, NULL);
194     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
195     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
196
197     IAssemblyEnum_Release(asmenum);
198
199     /* dwFlags is ASM_CACHE_ROOT */
200     asmenum = (IAssemblyEnum *)0xdeadbeef;
201     hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_ROOT, NULL);
202     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
203     ok(asmenum == (IAssemblyEnum *)0xdeadbeef,
204        "Expected asmenum to be unchanged, got %p\n", asmenum);
205
206     /* invalid dwFlags */
207     asmenum = (IAssemblyEnum *)0xdeadbeef;
208     hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, 0, NULL);
209     ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
210     ok(asmenum == (IAssemblyEnum *)0xdeadbeef,
211        "Expected asmenum to be unchanged, got %p\n", asmenum);
212 }
213
214 typedef struct _tagASMNAME
215 {
216     struct list entry;
217     LPSTR data;
218 } ASMNAME;
219
220 static BOOL enum_gac_assemblies(struct list *assemblies, int depth, LPSTR path)
221 {
222     WIN32_FIND_DATAA ffd;
223     CHAR buf[MAX_PATH];
224     CHAR disp[MAX_PATH];
225     ASMNAME *name;
226     HANDLE hfind;
227     LPSTR ptr;
228
229     static CHAR parent[MAX_PATH];
230
231     sprintf(buf, "%s\\*", path);
232     hfind = FindFirstFileA(buf, &ffd);
233     if (hfind == INVALID_HANDLE_VALUE)
234         return FALSE;
235
236     do
237     {
238         if (!lstrcmpA(ffd.cFileName, ".") || !lstrcmpA(ffd.cFileName, ".."))
239             continue;
240
241         if (depth == 0)
242         {
243             sprintf(parent, "%s, ", ffd.cFileName);
244         }
245         else if (depth == 1)
246         {
247             char culture[MAX_PATH];
248
249             ptr = strstr(ffd.cFileName, "_");
250             *ptr = '\0';
251             ptr++;
252
253             if (*ptr != '_')
254             {
255                 lstrcpyA(culture, ptr);
256                 *strstr(culture, "_") = '\0';
257             }
258             else
259                 lstrcpyA(culture, "neutral");
260
261             ptr = strchr(ptr, '_');
262             ptr++;
263             sprintf(buf, "Version=%s, Culture=%s, PublicKeyToken=%s",
264                     ffd.cFileName, culture, ptr);
265             lstrcpyA(disp, parent);
266             lstrcatA(disp, buf);
267
268             name = HeapAlloc(GetProcessHeap(), 0, sizeof(ASMNAME));
269             name->data = HeapAlloc(GetProcessHeap(), 0, lstrlenA(disp) + 1);
270             lstrcpyA(name->data, disp);
271             list_add_tail(assemblies, &name->entry);
272
273             continue;
274         }
275
276         sprintf(buf, "%s\\%s", path, ffd.cFileName);
277         enum_gac_assemblies(assemblies, depth + 1, buf);
278     } while (FindNextFileA(hfind, &ffd) != 0);
279
280     FindClose(hfind);
281     return TRUE;
282 }
283
284 static void test_enumerate(void)
285 {
286     struct list assemblies = LIST_INIT(assemblies);
287     struct list *item, *cursor;
288     IAssemblyEnum *asmenum;
289     IAssemblyName *next;
290     WCHAR buf[MAX_PATH];
291     CHAR path[MAX_PATH];
292     CHAR disp[MAX_PATH];
293     HRESULT hr;
294     BOOL found;
295     DWORD size;
296
297     size = MAX_PATH;
298     hr = pGetCachePath(ASM_CACHE_GAC, buf, &size);
299     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
300
301     to_multibyte(path, buf);
302     lstrcatA(path, "_32");
303     enum_gac_assemblies(&assemblies, 0, path);
304
305     to_multibyte(path, buf);
306     lstrcatA(path, "_MSIL");
307     enum_gac_assemblies(&assemblies, 0, path);
308
309     to_multibyte(path, buf);
310     enum_gac_assemblies(&assemblies, 0, path);
311
312     asmenum = NULL;
313     hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_GAC, NULL);
314     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
315     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
316
317     while (IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0) == S_OK)
318     {
319         size = MAX_PATH;
320         IAssemblyName_GetDisplayName(next, buf, &size, 0);
321         to_multibyte(disp, buf);
322
323         found = FALSE;
324         LIST_FOR_EACH_SAFE(item, cursor, &assemblies)
325         {
326             ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry);
327
328             if (!lstrcmpA(asmname->data, disp))
329             {
330                 found = TRUE;
331
332                 list_remove(&asmname->entry);
333                 HeapFree(GetProcessHeap(), 0, asmname->data);
334                 HeapFree(GetProcessHeap(), 0, asmname);
335                 break;
336             }
337         }
338
339         ok(found, "Extra assembly enumerated: %s\n", disp);
340         IAssemblyName_Release(next);
341     }
342
343     /* enumeration is exhausted */
344     next = (IAssemblyName *)0xdeadbeef;
345     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
346     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
347     ok(next == (IAssemblyName *)0xdeadbeef,
348        "Expected next to be unchanged, got %p\n", next);
349
350     LIST_FOR_EACH_SAFE(item, cursor, &assemblies)
351     {
352         ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry);
353
354         ok(FALSE, "Assembly not enumerated: %s\n", asmname->data);
355
356         list_remove(&asmname->entry);
357         HeapFree(GetProcessHeap(), 0, asmname->data);
358         HeapFree(GetProcessHeap(), 0, asmname);
359     }
360
361     IAssemblyEnum_Release(asmenum);
362 }
363
364 static void test_enumerate_name(void)
365 {
366     IAssemblyEnum *asmenum;
367     IAssemblyName *asmname, *next;
368     WCHAR buf[MAX_PATH];
369     CHAR gac[MAX_PATH];
370     CHAR path[MAX_PATH];
371     CHAR disp[MAX_PATH];
372     WCHAR namestr[MAX_PATH];
373     CHAR exp[6][MAX_PATH];
374     HRESULT hr;
375     DWORD size;
376
377     lstrcpyA(exp[0], "wine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d");
378     lstrcpyA(exp[1], "wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=123456789abcdef0");
379     lstrcpyA(exp[2], "wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d");
380     lstrcpyA(exp[3], "Wine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d");
381     lstrcpyA(exp[4], "Wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=123456789abcdef0");
382     lstrcpyA(exp[5], "Wine, Version=1.0.1.2, Culture=neutral, PublicKeyToken=16a3fcd171e93a8d");
383
384     size = MAX_PATH;
385     hr = pGetCachePath(ASM_CACHE_GAC, buf, &size);
386     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
387
388     to_multibyte(gac, buf);
389     create_full_path(gac);
390
391     sprintf(path, "%s\\Wine", gac);
392     CreateDirectoryA(path, NULL);
393
394     sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d", gac);
395     CreateDirectoryA(path, NULL);
396
397     lstrcatA(path, "\\Wine.dll");
398     create_file(path, 100);
399
400     sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac);
401     CreateDirectoryA(path, NULL);
402
403     lstrcatA(path, "\\Wine.dll");
404     create_file(path, 100);
405
406     sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac);
407     CreateDirectoryA(path, NULL);
408
409     lstrcatA(path, "\\Wine.dll");
410     create_file(path, 100);
411
412     /* test case sensitivity */
413     to_widechar(namestr, "wine");
414     asmname = NULL;
415     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
416     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
417     ok(asmname != NULL, "Expected non-NULL asmname\n");
418
419     asmenum = NULL;
420     hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
421     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
422     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
423
424     next = NULL;
425     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
426     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
427     ok(next != NULL, "Expected non-NULL next\n");
428
429     size = MAX_PATH;
430     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
431     to_multibyte(disp, buf);
432     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
433     ok(!lstrcmpA(disp, exp[0]) ||
434        !lstrcmpA(disp, exp[1]),
435        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[0], exp[1], disp);
436
437     IAssemblyName_Release(next);
438
439     next = NULL;
440     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
441     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
442     ok(next != NULL, "Expected non-NULL next\n");
443
444     size = MAX_PATH;
445     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
446     to_multibyte(disp, buf);
447     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
448     ok(!lstrcmpA(disp, exp[1]) ||
449        !lstrcmpA(disp, exp[2]),
450        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp);
451
452     IAssemblyName_Release(next);
453
454     next = NULL;
455     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
456     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
457     ok(next != NULL, "Expected non-NULL next\n");
458
459     size = MAX_PATH;
460     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
461     to_multibyte(disp, buf);
462     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
463     ok(!lstrcmpA(disp, exp[2]), "Expected \"%s\", got \"%s\"\n", exp[2], disp);
464
465     IAssemblyName_Release(next);
466
467     next = (IAssemblyName *)0xdeadbeef;
468     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
469     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
470     ok(next == (IAssemblyName *)0xdeadbeef,
471        "Expected next to be unchanged, got %p\n", next);
472
473     IAssemblyEnum_Release(asmenum);
474     IAssemblyName_Release(asmname);
475
476     /* only Version */
477     to_widechar(namestr, "Wine, Version=1.0.1.2");
478     asmname = NULL;
479     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
480     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
481     ok(asmname != NULL, "Expected non-NULL asmname\n");
482
483     asmenum = NULL;
484     hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
485     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
486     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
487
488     next = NULL;
489     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
490     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
491     ok(next != NULL, "Expected non-NULL next\n");
492
493     size = MAX_PATH;
494     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
495     to_multibyte(disp, buf);
496     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
497     ok(!lstrcmpA(disp, exp[4]), "Expected \"%s\", got \"%s\"\n", exp[4], disp);
498
499     IAssemblyName_Release(next);
500
501     next = NULL;
502     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
503     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
504     ok(next != NULL, "Expected non-NULL next\n");
505
506     size = MAX_PATH;
507     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
508     to_multibyte(disp, buf);
509     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
510     ok(!lstrcmpA(disp, exp[5]), "Expected \"%s\", got \"%s\"\n", exp[5], disp);
511
512     IAssemblyName_Release(next);
513
514     next = (IAssemblyName *)0xdeadbeef;
515     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
516     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
517     ok(next == (IAssemblyName *)0xdeadbeef,
518        "Expected next to be unchanged, got %p\n", next);
519
520     IAssemblyEnum_Release(asmenum);
521     IAssemblyName_Release(asmname);
522
523     /* only PublicKeyToken */
524     to_widechar(namestr, "Wine, PublicKeyToken=16a3fcd171e93a8d");
525     asmname = NULL;
526     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
527     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
528     ok(asmname != NULL, "Expected non-NULL asmname\n");
529
530     asmenum = NULL;
531     hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
532     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
533     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
534
535     next = NULL;
536     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
537     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
538     ok(next != NULL, "Expected non-NULL next\n");
539
540     size = MAX_PATH;
541     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
542     to_multibyte(disp, buf);
543     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
544     ok(!lstrcmpA(disp, exp[3]), "Expected \"%s\", got \"%s\"\n", exp[3], disp);
545
546     IAssemblyName_Release(next);
547
548     next = NULL;
549     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
550     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
551     ok(next != NULL, "Expected non-NULL next\n");
552
553     size = MAX_PATH;
554     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
555     to_multibyte(disp, buf);
556     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
557     ok(!lstrcmpA(disp, exp[5]), "Expected \"%s\", got \"%s\"\n", exp[5], disp);
558
559     IAssemblyName_Release(next);
560
561     next = (IAssemblyName *)0xdeadbeef;
562     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
563     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
564     ok(next == (IAssemblyName *)0xdeadbeef,
565        "Expected next to be unchanged, got %p\n", next);
566
567     IAssemblyEnum_Release(asmenum);
568     IAssemblyName_Release(asmname);
569
570     /* only Culture */
571     to_widechar(namestr, "wine, Culture=neutral");
572     asmname = NULL;
573     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
574     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
575     ok(asmname != NULL, "Expected non-NULL asmname\n");
576
577     asmenum = NULL;
578     hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
579     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
580     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
581
582     next = NULL;
583     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
584     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
585     ok(next != NULL, "Expected non-NULL next\n");
586
587     size = MAX_PATH;
588     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
589     to_multibyte(disp, buf);
590     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
591     ok(!lstrcmpA(disp, exp[0]), "Expected \"%s\", got \"%s\"\n", exp[0], disp);
592
593     IAssemblyName_Release(next);
594
595     next = NULL;
596     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
597     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
598     ok(next != NULL, "Expected non-NULL next\n");
599
600     size = MAX_PATH;
601     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
602     to_multibyte(disp, buf);
603     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
604     ok(!lstrcmpA(disp, exp[1]) ||
605        !lstrcmpA(disp, exp[2]),
606        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp);
607
608     IAssemblyName_Release(next);
609
610     next = NULL;
611     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
612     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
613     ok(next != NULL, "Expected non-NULL next\n");
614
615     size = MAX_PATH;
616     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
617     to_multibyte(disp, buf);
618     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
619     ok(!lstrcmpA(disp, exp[1]) ||
620        !lstrcmpA(disp, exp[2]),
621        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp);
622
623     IAssemblyName_Release(next);
624
625     next = (IAssemblyName *)0xdeadbeef;
626     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
627     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
628     ok(next == (IAssemblyName *)0xdeadbeef,
629        "Expected next to be unchanged, got %p\n", next);
630
631     IAssemblyEnum_Release(asmenum);
632     IAssemblyName_Release(asmname);
633
634     sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d\\Wine.dll", gac);
635     DeleteFileA(path);
636     sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d\\Wine.dll", gac);
637     DeleteFileA(path);
638     sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0\\Wine.dll", gac);
639     DeleteFileA(path);
640     sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d", gac);
641     RemoveDirectoryA(path);
642     sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac);
643     RemoveDirectoryA(path);
644     sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac);
645     RemoveDirectoryA(path);
646     sprintf(path, "%s\\Wine", gac);
647     RemoveDirectoryA(path);
648 }
649
650 START_TEST(asmenum)
651 {
652     if (!init_functionpointers())
653         return;
654
655     test_CreateAssemblyEnum();
656     test_enumerate();
657     test_enumerate_name();
658 }