2 * Copyright 2008 James Hawkins
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.
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.
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
29 #include "wine/test.h"
30 #include "wine/list.h"
32 static HRESULT (WINAPI *pCreateAssemblyEnum)(IAssemblyEnum **pEnum,
33 IUnknown *pUnkReserved,
35 DWORD dwFlags, LPVOID pvReserved);
36 static HRESULT (WINAPI *pCreateAssemblyNameObject)(LPASSEMBLYNAME *ppAssemblyNameObj,
37 LPCWSTR szAssemblyName, DWORD dwFlags,
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);
44 static BOOL init_functionpointers(void)
50 static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0};
52 hmscoree = LoadLibraryA("mscoree.dll");
55 skip("mscoree.dll not available\n");
59 pLoadLibraryShim = (void *)GetProcAddress(hmscoree, "LoadLibraryShim");
60 if (!pLoadLibraryShim)
62 skip("LoadLibraryShim not available\n");
63 FreeLibrary(hmscoree);
67 hr = pLoadLibraryShim(szFusion, NULL, NULL, &hfusion);
70 skip("fusion.dll not available\n");
71 FreeLibrary(hmscoree);
75 pCreateAssemblyEnum = (void *)GetProcAddress(hfusion, "CreateAssemblyEnum");
76 pCreateAssemblyNameObject = (void *)GetProcAddress(hfusion, "CreateAssemblyNameObject");
77 pGetCachePath = (void *)GetProcAddress(hfusion, "GetCachePath");
79 if (!pCreateAssemblyEnum ||
80 !pCreateAssemblyNameObject || !pGetCachePath)
82 skip("fusion.dll not implemented\n");
86 FreeLibrary(hmscoree);
90 static inline void to_widechar(LPWSTR dest, LPCSTR src)
92 MultiByteToWideChar(CP_ACP, 0, src, -1, dest, MAX_PATH);
95 static inline void to_multibyte(LPSTR dest, LPWSTR src)
97 WideCharToMultiByte(CP_ACP, 0, src, -1, dest, MAX_PATH, NULL, NULL);
100 static BOOL create_full_path(LPCSTR path)
106 new_path = HeapAlloc(GetProcessHeap(), 0, lstrlenA(path) + 1);
110 lstrcpyA(new_path, path);
112 while ((len = lstrlenA(new_path)) && new_path[len - 1] == '\\')
113 new_path[len - 1] = 0;
115 while (!CreateDirectoryA(new_path, NULL))
118 DWORD last_error = GetLastError();
120 if(last_error == ERROR_ALREADY_EXISTS)
123 if(last_error != ERROR_PATH_NOT_FOUND)
129 if(!(slash = strrchr(new_path, '\\')))
135 len = slash - new_path;
137 if(!create_full_path(new_path))
143 new_path[len] = '\\';
146 HeapFree(GetProcessHeap(), 0, new_path);
150 static void create_file_data(LPCSTR name, LPCSTR data, DWORD size)
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);
161 SetFilePointer(file, size, NULL, FILE_BEGIN);
168 #define create_file(name, size) create_file_data(name, name, size)
170 static void test_CreateAssemblyEnum(void)
173 WCHAR namestr[MAX_PATH];
174 IAssemblyEnum *asmenum;
175 IAssemblyName *asmname;
177 to_widechar(namestr, "wine");
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");
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);
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");
197 IAssemblyEnum_Release(asmenum);
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);
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);
214 typedef struct _tagASMNAME
220 static BOOL enum_gac_assemblies(struct list *assemblies, int depth, LPSTR path)
222 WIN32_FIND_DATAA ffd;
229 static CHAR parent[MAX_PATH];
231 sprintf(buf, "%s\\*", path);
232 hfind = FindFirstFileA(buf, &ffd);
233 if (hfind == INVALID_HANDLE_VALUE)
238 if (!lstrcmpA(ffd.cFileName, ".") || !lstrcmpA(ffd.cFileName, ".."))
243 sprintf(parent, "%s, ", ffd.cFileName);
247 char culture[MAX_PATH];
249 ptr = strstr(ffd.cFileName, "_");
255 lstrcpyA(culture, ptr);
256 *strstr(culture, "_") = '\0';
259 lstrcpyA(culture, "neutral");
261 ptr = strchr(ptr, '_');
263 sprintf(buf, "Version=%s, Culture=%s, PublicKeyToken=%s",
264 ffd.cFileName, culture, ptr);
265 lstrcpyA(disp, parent);
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);
276 sprintf(buf, "%s\\%s", path, ffd.cFileName);
277 enum_gac_assemblies(assemblies, depth + 1, buf);
278 } while (FindNextFileA(hfind, &ffd) != 0);
284 static void test_enumerate(void)
286 struct list assemblies = LIST_INIT(assemblies);
287 struct list *item, *cursor;
288 IAssemblyEnum *asmenum;
298 hr = pGetCachePath(ASM_CACHE_GAC, buf, &size);
299 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
301 to_multibyte(path, buf);
302 lstrcatA(path, "_32");
303 enum_gac_assemblies(&assemblies, 0, path);
305 to_multibyte(path, buf);
306 lstrcatA(path, "_MSIL");
307 enum_gac_assemblies(&assemblies, 0, path);
309 to_multibyte(path, buf);
310 enum_gac_assemblies(&assemblies, 0, path);
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");
317 while (IAssemblyEnum_GetNextAssembly(asmenum, NULL, &next, 0) == S_OK)
320 IAssemblyName_GetDisplayName(next, buf, &size, 0);
321 to_multibyte(disp, buf);
324 LIST_FOR_EACH_SAFE(item, cursor, &assemblies)
326 ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry);
328 if (!lstrcmpA(asmname->data, disp))
332 list_remove(&asmname->entry);
333 HeapFree(GetProcessHeap(), 0, asmname->data);
334 HeapFree(GetProcessHeap(), 0, asmname);
339 ok(found, "Extra assembly enumerated: %s\n", disp);
340 IAssemblyName_Release(next);
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);
350 LIST_FOR_EACH_SAFE(item, cursor, &assemblies)
352 ASMNAME *asmname = LIST_ENTRY(item, ASMNAME, entry);
354 ok(FALSE, "Assembly not enumerated: %s\n", asmname->data);
356 list_remove(&asmname->entry);
357 HeapFree(GetProcessHeap(), 0, asmname->data);
358 HeapFree(GetProcessHeap(), 0, asmname);
361 IAssemblyEnum_Release(asmenum);
364 static void test_enumerate_name(void)
366 IAssemblyEnum *asmenum;
367 IAssemblyName *asmname, *next;
372 WCHAR namestr[MAX_PATH];
373 CHAR exp[6][MAX_PATH];
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");
385 hr = pGetCachePath(ASM_CACHE_GAC, buf, &size);
386 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
388 to_multibyte(gac, buf);
389 create_full_path(gac);
391 sprintf(path, "%s\\Wine", gac);
392 CreateDirectoryA(path, NULL);
394 sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d", gac);
395 CreateDirectoryA(path, NULL);
397 lstrcatA(path, "\\Wine.dll");
398 create_file(path, 100);
400 sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d", gac);
401 CreateDirectoryA(path, NULL);
403 lstrcatA(path, "\\Wine.dll");
404 create_file(path, 100);
406 sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0", gac);
407 CreateDirectoryA(path, NULL);
409 lstrcatA(path, "\\Wine.dll");
410 create_file(path, 100);
412 /* test case sensitivity */
413 to_widechar(namestr, "wine");
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");
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");
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");
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);
437 IAssemblyName_Release(next);
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");
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);
452 IAssemblyName_Release(next);
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");
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);
465 IAssemblyName_Release(next);
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);
473 IAssemblyEnum_Release(asmenum);
474 IAssemblyName_Release(asmname);
477 to_widechar(namestr, "Wine, Version=1.0.1.2");
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");
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");
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");
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);
499 IAssemblyName_Release(next);
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");
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);
512 IAssemblyName_Release(next);
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);
520 IAssemblyEnum_Release(asmenum);
521 IAssemblyName_Release(asmname);
523 /* only PublicKeyToken */
524 to_widechar(namestr, "Wine, PublicKeyToken=16a3fcd171e93a8d");
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");
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");
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");
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);
546 IAssemblyName_Release(next);
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");
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);
559 IAssemblyName_Release(next);
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);
567 IAssemblyEnum_Release(asmenum);
568 IAssemblyName_Release(asmname);
571 to_widechar(namestr, "wine, Culture=neutral");
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");
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");
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");
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);
593 IAssemblyName_Release(next);
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");
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);
608 IAssemblyName_Release(next);
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");
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);
623 IAssemblyName_Release(next);
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);
631 IAssemblyEnum_Release(asmenum);
632 IAssemblyName_Release(asmname);
634 sprintf(path, "%s\\Wine\\1.0.0.0__16a3fcd171e93a8d\\Wine.dll", gac);
636 sprintf(path, "%s\\Wine\\1.0.1.2__16a3fcd171e93a8d\\Wine.dll", gac);
638 sprintf(path, "%s\\Wine\\1.0.1.2__123456789abcdef0\\Wine.dll", gac);
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);
652 if (!init_functionpointers())
655 test_CreateAssemblyEnum();
657 test_enumerate_name();