wined3d: Update the swapchain's present parameters when changing the backbuffer.
[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         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
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     IAssemblyName_Release(asmname);
214 }
215
216 typedef struct _tagASMNAME
217 {
218     struct list entry;
219     LPSTR data;
220 } ASMNAME;
221
222 static BOOL enum_gac_assemblies(struct list *assemblies, int depth, LPSTR path)
223 {
224     WIN32_FIND_DATAA ffd;
225     CHAR buf[MAX_PATH];
226     CHAR disp[MAX_PATH];
227     ASMNAME *name;
228     HANDLE hfind;
229     LPSTR ptr;
230
231     static CHAR parent[MAX_PATH];
232
233     sprintf(buf, "%s\\*", path);
234     hfind = FindFirstFileA(buf, &ffd);
235     if (hfind == INVALID_HANDLE_VALUE)
236         return FALSE;
237
238     do
239     {
240         if (!lstrcmpA(ffd.cFileName, ".") || !lstrcmpA(ffd.cFileName, ".."))
241             continue;
242
243         if (depth == 0)
244         {
245             lstrcpyA(parent, ffd.cFileName);
246         }
247         else if (depth == 1)
248         {
249             char culture[MAX_PATH];
250             char dll[MAX_PATH], exe[MAX_PATH];
251
252             /* Directories with no dll or exe will not be enumerated */
253             sprintf(dll, "%s\\%s\\%s.dll", path, ffd.cFileName, parent);
254             sprintf(exe, "%s\\%s\\%s.exe", path, ffd.cFileName, parent);
255             if (GetFileAttributesA(dll) == INVALID_FILE_ATTRIBUTES &&
256                 GetFileAttributesA(exe) == INVALID_FILE_ATTRIBUTES)
257                 continue;
258
259             ptr = strstr(ffd.cFileName, "_");
260             *ptr = '\0';
261             ptr++;
262
263             if (*ptr != '_')
264             {
265                 lstrcpyA(culture, ptr);
266                 *strstr(culture, "_") = '\0';
267             }
268             else
269                 lstrcpyA(culture, "neutral");
270
271             ptr = strchr(ptr, '_');
272             ptr++;
273             sprintf(buf, ", Version=%s, Culture=%s, PublicKeyToken=%s",
274                     ffd.cFileName, culture, ptr);
275             lstrcpyA(disp, parent);
276             lstrcatA(disp, buf);
277
278             name = HeapAlloc(GetProcessHeap(), 0, sizeof(ASMNAME));
279             name->data = HeapAlloc(GetProcessHeap(), 0, lstrlenA(disp) + 1);
280             lstrcpyA(name->data, disp);
281             list_add_tail(assemblies, &name->entry);
282
283             continue;
284         }
285
286         sprintf(buf, "%s\\%s", path, ffd.cFileName);
287         enum_gac_assemblies(assemblies, depth + 1, buf);
288     } while (FindNextFileA(hfind, &ffd) != 0);
289
290     FindClose(hfind);
291     return TRUE;
292 }
293
294 static void test_enumerate(void)
295 {
296     struct list assemblies = LIST_INIT(assemblies);
297     struct list *item, *cursor;
298     IAssemblyEnum *asmenum;
299     IAssemblyName *next;
300     WCHAR buf[MAX_PATH];
301     CHAR path[MAX_PATH];
302     CHAR disp[MAX_PATH];
303     HRESULT hr;
304     BOOL found;
305     DWORD size;
306
307     size = MAX_PATH;
308     hr = pGetCachePath(ASM_CACHE_GAC, buf, &size);
309     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
310
311     to_multibyte(path, buf);
312     lstrcatA(path, "_32");
313     enum_gac_assemblies(&assemblies, 0, path);
314
315     to_multibyte(path, buf);
316     lstrcatA(path, "_64");
317     enum_gac_assemblies(&assemblies, 0, path);
318
319     to_multibyte(path, buf);
320     lstrcatA(path, "_MSIL");
321     enum_gac_assemblies(&assemblies, 0, path);
322
323     to_multibyte(path, buf);
324     enum_gac_assemblies(&assemblies, 0, path);
325
326     asmenum = NULL;
327     hr = pCreateAssemblyEnum(&asmenum, NULL, NULL, ASM_CACHE_GAC, NULL);
328     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
329     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
330
331     while (IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0) == S_OK)
332     {
333         size = MAX_PATH;
334         IAssemblyName_GetDisplayName(next, buf, &size, 0);
335         to_multibyte(disp, buf);
336
337         found = FALSE;
338         LIST_FOR_EACH_SAFE(item, cursor, &assemblies)
339         {
340             ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry);
341
342             if (!lstrcmpA(asmname->data, disp))
343             {
344                 found = TRUE;
345
346                 list_remove(&asmname->entry);
347                 HeapFree(GetProcessHeap(), 0, asmname->data);
348                 HeapFree(GetProcessHeap(), 0, asmname);
349                 break;
350             }
351         }
352
353         ok(found, "Extra assembly enumerated: %s\n", disp);
354         IAssemblyName_Release(next);
355     }
356
357     /* enumeration is exhausted */
358     next = (IAssemblyName *)0xdeadbeef;
359     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
360     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
361     ok(next == (IAssemblyName *)0xdeadbeef,
362        "Expected next to be unchanged, got %p\n", next);
363
364     LIST_FOR_EACH_SAFE(item, cursor, &assemblies)
365     {
366         ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry);
367
368         ok(FALSE, "Assembly not enumerated: %s\n", asmname->data);
369
370         list_remove(&asmname->entry);
371         HeapFree(GetProcessHeap(), 0, asmname->data);
372         HeapFree(GetProcessHeap(), 0, asmname);
373     }
374
375     IAssemblyEnum_Release(asmenum);
376 }
377
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     create_file(path, 100);
413
414     sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac);
415     CreateDirectoryA(path, NULL);
416
417     lstrcatA(path, "\\Wine.dll");
418     create_file(path, 100);
419
420     sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac);
421     CreateDirectoryA(path, NULL);
422
423     lstrcatA(path, "\\Wine.dll");
424     create_file(path, 100);
425
426     /* test case sensitivity */
427     to_widechar(namestr, "wine");
428     asmname = NULL;
429     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
430     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
431     ok(asmname != NULL, "Expected non-NULL asmname\n");
432
433     asmenum = NULL;
434     hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
435     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
436     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
437
438     next = NULL;
439     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
440     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
441     ok(next != NULL, "Expected non-NULL next\n");
442
443     size = MAX_PATH;
444     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
445     to_multibyte(disp, buf);
446     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
447     ok(!lstrcmpA(disp, exp[0]),
448        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[0], exp[1], disp);
449
450     IAssemblyName_Release(next);
451
452     next = NULL;
453     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
454     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
455     ok(next != NULL, "Expected non-NULL next\n");
456
457     size = MAX_PATH;
458     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
459     to_multibyte(disp, buf);
460     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
461     ok(!lstrcmpA(disp, exp[1]) ||
462        !lstrcmpA(disp, exp[2]), /* Win98 */
463        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp);
464
465     IAssemblyName_Release(next);
466
467     next = NULL;
468     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
469     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
470     ok(next != NULL, "Expected non-NULL next\n");
471
472     size = MAX_PATH;
473     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
474     to_multibyte(disp, buf);
475     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
476     ok(!lstrcmpA(disp, exp[2]) ||
477        !lstrcmpA(disp, exp[1]), /* Win98 */
478        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[2], exp[1], disp);
479
480     IAssemblyName_Release(next);
481
482     next = (IAssemblyName *)0xdeadbeef;
483     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
484     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
485     ok(next == (IAssemblyName *)0xdeadbeef,
486        "Expected next to be unchanged, got %p\n", next);
487
488     IAssemblyEnum_Release(asmenum);
489     IAssemblyName_Release(asmname);
490
491     /* only Version */
492     to_widechar(namestr, "Wine, Version=1.0.1.2");
493     asmname = NULL;
494     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
495     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
496     ok(asmname != NULL, "Expected non-NULL asmname\n");
497
498     asmenum = NULL;
499     hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
500     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
501     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
502
503     next = NULL;
504     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
505     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
506     ok(next != NULL, "Expected non-NULL next\n");
507
508     size = MAX_PATH;
509     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
510     to_multibyte(disp, buf);
511     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
512     ok(!lstrcmpA(disp, exp[4]) ||
513        !lstrcmpA(disp, exp[5]), /* Win98 */
514        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[4], exp[5], disp);
515
516     IAssemblyName_Release(next);
517
518     next = NULL;
519     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
520     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
521     ok(next != NULL, "Expected non-NULL next\n");
522
523     size = MAX_PATH;
524     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
525     to_multibyte(disp, buf);
526     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
527     ok(!lstrcmpA(disp, exp[5]) ||
528        !lstrcmpA(disp, exp[4]), /* Win98 */
529        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[5], exp[4], disp);
530
531     IAssemblyName_Release(next);
532
533     next = (IAssemblyName *)0xdeadbeef;
534     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
535     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
536     ok(next == (IAssemblyName *)0xdeadbeef,
537        "Expected next to be unchanged, got %p\n", next);
538
539     IAssemblyEnum_Release(asmenum);
540     IAssemblyName_Release(asmname);
541
542     /* only PublicKeyToken */
543     to_widechar(namestr, "Wine, PublicKeyToken=16a3fcd171e93a8d");
544     asmname = NULL;
545     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
546     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
547     ok(asmname != NULL, "Expected non-NULL asmname\n");
548
549     asmenum = NULL;
550     hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
551     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
552     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
553
554     next = NULL;
555     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
556     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
557     ok(next != NULL, "Expected non-NULL next\n");
558
559     size = MAX_PATH;
560     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
561     to_multibyte(disp, buf);
562     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
563     ok(!lstrcmpA(disp, exp[3]), "Expected \"%s\", got \"%s\"\n", exp[3], disp);
564
565     IAssemblyName_Release(next);
566
567     next = NULL;
568     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
569     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
570     ok(next != NULL, "Expected non-NULL next\n");
571
572     size = MAX_PATH;
573     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
574     to_multibyte(disp, buf);
575     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
576     ok(!lstrcmpA(disp, exp[5]), "Expected \"%s\", got \"%s\"\n", exp[5], disp);
577
578     IAssemblyName_Release(next);
579
580     next = (IAssemblyName *)0xdeadbeef;
581     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
582     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
583     ok(next == (IAssemblyName *)0xdeadbeef,
584        "Expected next to be unchanged, got %p\n", next);
585
586     IAssemblyEnum_Release(asmenum);
587     IAssemblyName_Release(asmname);
588
589     /* only Culture */
590     to_widechar(namestr, "wine, Culture=neutral");
591     asmname = NULL;
592     hr = pCreateAssemblyNameObject(&asmname, namestr, CANOF_PARSE_DISPLAY_NAME, NULL);
593     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
594     ok(asmname != NULL, "Expected non-NULL asmname\n");
595
596     asmenum = NULL;
597     hr = pCreateAssemblyEnum(&asmenum, NULL, asmname, ASM_CACHE_GAC, NULL);
598     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
599     ok(asmenum != NULL, "Expected non-NULL asmenum\n");
600
601     next = NULL;
602     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
603     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
604     ok(next != NULL, "Expected non-NULL next\n");
605
606     size = MAX_PATH;
607     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
608     to_multibyte(disp, buf);
609     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
610     ok(!lstrcmpA(disp, exp[0]), "Expected \"%s\", got \"%s\"\n", exp[0], disp);
611
612     IAssemblyName_Release(next);
613
614     next = NULL;
615     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
616     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
617     ok(next != NULL, "Expected non-NULL next\n");
618
619     size = MAX_PATH;
620     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
621     to_multibyte(disp, buf);
622     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
623     ok(!lstrcmpA(disp, exp[1]) ||
624        !lstrcmpA(disp, exp[2]), /* Win98 */
625        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[1], exp[2], disp);
626
627     IAssemblyName_Release(next);
628
629     next = NULL;
630     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
631     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
632     ok(next != NULL, "Expected non-NULL next\n");
633
634     size = MAX_PATH;
635     hr = IAssemblyName_GetDisplayName(next, buf, &size, 0);
636     to_multibyte(disp, buf);
637     ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
638     ok(!lstrcmpA(disp, exp[2]) ||
639        !lstrcmpA(disp, exp[1]), /* Win98 */
640        "Expected \"%s\" or \"%s\", got \"%s\"\n", exp[2], exp[1], disp);
641
642     IAssemblyName_Release(next);
643
644     next = (IAssemblyName *)0xdeadbeef;
645     hr = IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0);
646     ok(hr == S_FALSE, "Expected S_FALSE, got %08x\n", hr);
647     ok(next == (IAssemblyName *)0xdeadbeef,
648        "Expected next to be unchanged, got %p\n", next);
649
650     IAssemblyEnum_Release(asmenum);
651     IAssemblyName_Release(asmname);
652
653     sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d\\Wine.dll", gac);
654     DeleteFileA(path);
655     sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d\\Wine.dll", gac);
656     DeleteFileA(path);
657     sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0\\Wine.dll", gac);
658     DeleteFileA(path);
659     sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d", gac);
660     RemoveDirectoryA(path);
661     sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac);
662     RemoveDirectoryA(path);
663     sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac);
664     RemoveDirectoryA(path);
665     sprintf(path, "%s\\Wine", gac);
666     RemoveDirectoryA(path);
667 }
668
669 START_TEST(asmenum)
670 {
671     if (!init_functionpointers())
672         return;
673
674     test_CreateAssemblyEnum();
675     test_enumerate();
676     test_enumerate_name();
677 }