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 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 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 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 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 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 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 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 682 START_TEST(asmenum) 683 { 684 if (!init_functionpointers()) 685 return; 686 687 test_CreateAssemblyEnum(); 688 test_enumerate(); 689 test_enumerate_name(); 690 } 691