1 /* 2 * comctl32 MRU unit tests 3 * 4 * Copyright (C) 2004 Jon Griffiths <jon_p_griffiths@yahoo.com> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 #include <stdarg.h> 21 22 #include "windef.h" 23 #include "winbase.h" 24 #include "wingdi.h" 25 #include "winuser.h" 26 #include "winnls.h" 27 #include "winreg.h" 28 #include "commctrl.h" 29 #include "shlwapi.h" 30 31 #include "wine/heap.h" 32 #include "wine/test.h" 33 34 /* Keys for testing MRU functions */ 35 #define REG_TEST_BASEKEYA "Software\\Wine" 36 #define REG_TEST_BASESUBKEYA "Test" 37 #define REG_TEST_KEYA REG_TEST_BASEKEYA "\\" REG_TEST_BASESUBKEYA 38 #define REG_TEST_SUBKEYA "MRUTest" 39 #define REG_TEST_FULLKEY REG_TEST_KEYA "\\" REG_TEST_SUBKEYA 40 41 /* Undocumented MRU functions */ 42 typedef struct tagMRUINFOA 43 { 44 DWORD cbSize; 45 UINT uMax; 46 UINT fFlags; 47 HKEY hKey; 48 LPCSTR lpszSubKey; 49 int (CALLBACK *lpfnCompare)(LPCSTR, LPCSTR); 50 } MRUINFOA; 51 52 typedef struct tagMRUINFOW 53 { 54 DWORD cbSize; 55 UINT uMax; 56 UINT fFlags; 57 HKEY hKey; 58 LPCWSTR lpszSubKey; 59 int (CALLBACK *lpfnCompare)(LPCWSTR, LPCWSTR); 60 } MRUINFOW; 61 62 #define MRU_STRING 0 /* this one's invented */ 63 #define MRU_BINARY 1 64 #define MRU_CACHEWRITE 2 65 66 #define LIST_SIZE 3 /* Max entries for each mru */ 67 68 static HMODULE hComctl32; 69 static HANDLE (WINAPI *pCreateMRUListA)(MRUINFOA*); 70 static void (WINAPI *pFreeMRUList)(HANDLE); 71 static INT (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR); 72 static INT (WINAPI *pEnumMRUListA)(HANDLE,INT,LPVOID,DWORD); 73 static INT (WINAPI *pEnumMRUListW)(HANDLE,INT,LPVOID,DWORD); 74 static HANDLE (WINAPI *pCreateMRUListLazyA)(MRUINFOA*, DWORD, DWORD, DWORD); 75 static HANDLE (WINAPI *pCreateMRUListLazyW)(MRUINFOW*, DWORD, DWORD, DWORD); 76 static INT (WINAPI *pFindMRUData)(HANDLE, LPCVOID, DWORD, LPINT); 77 static INT (WINAPI *pAddMRUData)(HANDLE, LPCVOID, DWORD); 78 static HANDLE (WINAPI *pCreateMRUListW)(MRUINFOW*); 79 80 static void init_functions(void) 81 { 82 hComctl32 = LoadLibraryA("comctl32.dll"); 83 84 #define X2(f, ord) p##f = (void*)GetProcAddress(hComctl32, (const char *)ord); 85 X2(CreateMRUListA, 151); 86 X2(FreeMRUList, 152); 87 X2(AddMRUStringA, 153); 88 X2(EnumMRUListA, 154); 89 X2(CreateMRUListLazyA, 157); 90 X2(AddMRUData, 167); 91 X2(FindMRUData, 169); 92 X2(CreateMRUListW, 400); 93 X2(EnumMRUListW, 403); 94 X2(CreateMRUListLazyW, 404); 95 #undef X2 96 } 97 98 /* Based on RegDeleteTreeW from dlls/advapi32/registry.c */ 99 static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey) 100 { 101 LONG ret; 102 DWORD dwMaxSubkeyLen, dwMaxValueLen; 103 DWORD dwMaxLen, dwSize; 104 CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; 105 HKEY hSubKey = hKey; 106 107 if(lpszSubKey) 108 { 109 ret = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); 110 if (ret) return ret; 111 } 112 113 /* Get highest length for keys, values */ 114 ret = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL, 115 &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL); 116 if (ret) goto cleanup; 117 118 dwMaxSubkeyLen++; 119 dwMaxValueLen++; 120 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen); 121 if (dwMaxLen > sizeof(szNameBuf)/sizeof(CHAR)) 122 { 123 /* Name too big: alloc a buffer for it */ 124 if (!(lpszName = heap_alloc(dwMaxLen * sizeof(CHAR)))) 125 { 126 ret = ERROR_NOT_ENOUGH_MEMORY; 127 goto cleanup; 128 } 129 } 130 131 132 /* Recursively delete all the subkeys */ 133 while (TRUE) 134 { 135 dwSize = dwMaxLen; 136 if (RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL, 137 NULL, NULL, NULL)) break; 138 139 ret = mru_RegDeleteTreeA(hSubKey, lpszName); 140 if (ret) goto cleanup; 141 } 142 143 if (lpszSubKey) 144 ret = RegDeleteKeyA(hKey, lpszSubKey); 145 else 146 while (TRUE) 147 { 148 dwSize = dwMaxLen; 149 if (RegEnumValueA(hKey, 0, lpszName, &dwSize, 150 NULL, NULL, NULL, NULL)) break; 151 152 ret = RegDeleteValueA(hKey, lpszName); 153 if (ret) goto cleanup; 154 } 155 156 cleanup: 157 /* Free buffer if allocated */ 158 if (lpszName != szNameBuf) 159 heap_free(lpszName); 160 if(lpszSubKey) 161 RegCloseKey(hSubKey); 162 return ret; 163 } 164 165 static BOOL create_reg_entries(void) 166 { 167 HKEY hKey = NULL; 168 169 ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey), 170 "Couldn't create test key \"%s\"\n", REG_TEST_KEYA); 171 if (!hKey) return FALSE; 172 RegCloseKey(hKey); 173 return TRUE; 174 } 175 176 static void delete_reg_entries(void) 177 { 178 HKEY hKey; 179 180 if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_BASEKEYA, 0, KEY_ALL_ACCESS, 181 &hKey)) 182 return; 183 mru_RegDeleteTreeA(hKey, REG_TEST_BASESUBKEYA); 184 RegCloseKey(hKey); 185 } 186 187 static void check_reg_entries(const char *mrulist, const char**items) 188 { 189 char buff[128]; 190 HKEY hKey = NULL; 191 DWORD type, size, ret; 192 unsigned int i; 193 194 ok(!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey), 195 "Couldn't open test key \"%s\"\n", REG_TEST_FULLKEY); 196 if (!hKey) return; 197 198 type = REG_SZ; 199 size = sizeof(buff); 200 buff[0] = '\0'; 201 ret = RegQueryValueExA(hKey, "MRUList", NULL, &type, (LPBYTE)buff, &size); 202 203 ok(!ret && buff[0], "Checking MRU: got %d from RegQueryValueExW\n", ret); 204 if(ret || !buff[0]) return; 205 206 ok(strcmp(buff, mrulist) == 0, "Checking MRU: Expected list %s, got %s\n", 207 mrulist, buff); 208 if(strcmp(buff, mrulist)) return; 209 210 for (i = 0; i < strlen(mrulist); i++) 211 { 212 char name[2]; 213 name[0] = mrulist[i]; 214 name[1] = '\0'; 215 type = REG_SZ; 216 size = sizeof(buff); 217 buff[0] = '\0'; 218 ret = RegQueryValueExA(hKey, name, NULL, &type, (LPBYTE)buff, &size); 219 ok(!ret && buff[0], 220 "Checking MRU item %d ('%c'): got %d from RegQueryValueExW\n", 221 i, mrulist[i], ret); 222 if(ret || !buff[0]) return; 223 ok(!strcmp(buff, items[mrulist[i]-'a']), 224 "Checking MRU item %d ('%c'): expected \"%s\", got \"%s\"\n", 225 i, mrulist[i], buff, items[mrulist[i] - 'a']); 226 } 227 } 228 229 static int CALLBACK cmp_mru_strA(LPCSTR data1, LPCSTR data2) 230 { 231 return lstrcmpiA(data1, data2); 232 } 233 234 static void test_MRUListA(void) 235 { 236 const char *checks[LIST_SIZE+1]; 237 MRUINFOA infoA; 238 HANDLE hMRU; 239 HKEY hKey; 240 INT iRet; 241 242 if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA || !pEnumMRUListA) 243 { 244 win_skip("MRU entry points not found\n"); 245 return; 246 } 247 248 if (0) 249 { 250 /* Create (NULL) - crashes native */ 251 hMRU = pCreateMRUListA(NULL); 252 } 253 254 /* size too small */ 255 infoA.cbSize = sizeof(infoA) - 2; 256 infoA.uMax = LIST_SIZE; 257 infoA.fFlags = MRU_STRING; 258 infoA.hKey = NULL; 259 infoA.lpszSubKey = REG_TEST_SUBKEYA; 260 infoA.lpfnCompare = cmp_mru_strA; 261 262 SetLastError(0); 263 hMRU = pCreateMRUListA(&infoA); 264 ok (!hMRU && !GetLastError(), 265 "CreateMRUListA(too small) expected NULL,0 got %p,%d\n", 266 hMRU, GetLastError()); 267 268 /* size too big */ 269 infoA.cbSize = sizeof(infoA) + 2; 270 infoA.uMax = LIST_SIZE; 271 infoA.fFlags = MRU_STRING; 272 infoA.hKey = NULL; 273 infoA.lpszSubKey = REG_TEST_SUBKEYA; 274 infoA.lpfnCompare = cmp_mru_strA; 275 276 SetLastError(0); 277 hMRU = pCreateMRUListA(&infoA); 278 ok (!hMRU && !GetLastError(), 279 "CreateMRUListA(too big) expected NULL,0 got %p,%d\n", 280 hMRU, GetLastError()); 281 282 /* NULL hKey */ 283 infoA.cbSize = sizeof(infoA); 284 infoA.uMax = LIST_SIZE; 285 infoA.fFlags = MRU_STRING; 286 infoA.hKey = NULL; 287 infoA.lpszSubKey = REG_TEST_SUBKEYA; 288 infoA.lpfnCompare = cmp_mru_strA; 289 290 SetLastError(0); 291 hMRU = pCreateMRUListA(&infoA); 292 ok (!hMRU && !GetLastError(), 293 "CreateMRUListA(NULL key) expected NULL,0 got %p,%d\n", 294 hMRU, GetLastError()); 295 296 /* NULL subkey name */ 297 infoA.cbSize = sizeof(infoA); 298 infoA.uMax = LIST_SIZE; 299 infoA.fFlags = MRU_STRING; 300 infoA.hKey = NULL; 301 infoA.lpszSubKey = NULL; 302 infoA.lpfnCompare = cmp_mru_strA; 303 304 SetLastError(0); 305 hMRU = pCreateMRUListA(&infoA); 306 ok (!hMRU && !GetLastError(), 307 "CreateMRUListA(NULL name) expected NULL,0 got %p,%d\n", 308 hMRU, GetLastError()); 309 310 /* Create a string MRU */ 311 ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey), 312 "Couldn't create test key \"%s\"\n", REG_TEST_KEYA); 313 if (!hKey) return; 314 315 infoA.cbSize = sizeof(infoA); 316 infoA.uMax = LIST_SIZE; 317 infoA.fFlags = MRU_STRING; 318 infoA.hKey = hKey; 319 infoA.lpszSubKey = REG_TEST_SUBKEYA; 320 infoA.lpfnCompare = cmp_mru_strA; 321 322 hMRU = pCreateMRUListA(&infoA); 323 ok(hMRU && !GetLastError(), 324 "CreateMRUListA(string) expected non-NULL,0 got %p,%d\n", 325 hMRU, GetLastError()); 326 327 if (hMRU) 328 { 329 char buffer[255]; 330 checks[0] = "Test 1"; 331 checks[1] = "Test 2"; 332 checks[2] = "Test 3"; 333 checks[3] = "Test 4"; 334 335 /* Add (NULL list) */ 336 SetLastError(0); 337 iRet = pAddMRUStringA(NULL, checks[0]); 338 ok(iRet == -1 && !GetLastError(), 339 "AddMRUStringA(NULL list) expected -1,0 got %d,%d\n", 340 iRet, GetLastError()); 341 342 /* Add (NULL string) */ 343 if (0) 344 { 345 /* Some native versions crash when passed NULL or fail to SetLastError() */ 346 SetLastError(0); 347 iRet = pAddMRUStringA(hMRU, NULL); 348 ok(iRet == 0 && GetLastError() == ERROR_INVALID_PARAMETER, 349 "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%d\n", 350 iRet, GetLastError()); 351 } 352 353 /* Add 3 strings. Check the registry is correct after each add */ 354 SetLastError(0); 355 iRet = pAddMRUStringA(hMRU, checks[0]); 356 ok(iRet == 0 && !GetLastError(), 357 "AddMRUStringA(1) expected 0,0 got %d,%d\n", 358 iRet, GetLastError()); 359 check_reg_entries("a", checks); 360 361 SetLastError(0); 362 iRet = pAddMRUStringA(hMRU, checks[1]); 363 ok(iRet == 1 && !GetLastError(), 364 "AddMRUStringA(2) expected 1,0 got %d,%d\n", 365 iRet, GetLastError()); 366 check_reg_entries("ba", checks); 367 368 SetLastError(0); 369 iRet = pAddMRUStringA(hMRU, checks[2]); 370 ok(iRet == 2 && !GetLastError(), 371 "AddMRUStringA(2) expected 2,0 got %d,%d\n", 372 iRet, GetLastError()); 373 check_reg_entries("cba", checks); 374 375 /* Add a duplicate of the 2nd string - it should move to the front, 376 * but keep the same index in the registry. 377 */ 378 SetLastError(0); 379 iRet = pAddMRUStringA(hMRU, checks[1]); 380 ok(iRet == 1 && !GetLastError(), 381 "AddMRUStringA(re-add 1) expected 1,0 got %d,%d\n", 382 iRet, GetLastError()); 383 check_reg_entries("bca", checks); 384 385 /* Add a new string - replaces the oldest string + moves to the front */ 386 SetLastError(0); 387 iRet = pAddMRUStringA(hMRU, checks[3]); 388 ok(iRet == 0 && !GetLastError(), 389 "AddMRUStringA(add new) expected 0,0 got %d,%d\n", 390 iRet, GetLastError()); 391 checks[0] = checks[3]; 392 check_reg_entries("abc", checks); 393 394 /* NULL buffer = get list size */ 395 iRet = pEnumMRUListA(hMRU, 0, NULL, 0); 396 ok(iRet == 3 || iRet == -1 /* Vista */, "EnumMRUList expected %d or -1, got %d\n", LIST_SIZE, iRet); 397 398 /* negative item pos = get list size */ 399 iRet = pEnumMRUListA(hMRU, -1, NULL, 0); 400 ok(iRet == 3 || iRet == -1 /* Vista */, "EnumMRUList expected %d or -1, got %d\n", LIST_SIZE, iRet); 401 402 /* negative item pos = get list size */ 403 iRet = pEnumMRUListA(hMRU, -5, NULL, 0); 404 ok(iRet == 3 || iRet == -1 /* Vista */, "EnumMRUList expected %d or -1, got %d\n", LIST_SIZE, iRet); 405 406 /* negative item pos = get list size */ 407 iRet = pEnumMRUListA(hMRU, -1, buffer, 255); 408 ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet); 409 410 /* negative item pos = get list size */ 411 iRet = pEnumMRUListA(hMRU, -5, buffer, 255); 412 ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet); 413 414 /* check entry 0 */ 415 buffer[0] = 0; 416 iRet = pEnumMRUListA(hMRU, 0, buffer, 255); 417 ok(iRet == lstrlenA(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlenA(checks[3]), iRet); 418 ok(strcmp(buffer, checks[3]) == 0, "EnumMRUList expected %s, got %s\n", checks[3], buffer); 419 420 /* check entry 0 with a too small buffer */ 421 buffer[0] = 0; /* overwritten with 'T' */ 422 buffer[1] = 'A'; /* overwritten with 0 */ 423 buffer[2] = 'A'; /* unchanged */ 424 buffer[3] = 0; /* unchanged */ 425 iRet = pEnumMRUListA(hMRU, 0, buffer, 2); 426 ok(iRet == lstrlenA(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlenA(checks[3]), iRet); 427 ok(strcmp(buffer, "T") == 0, "EnumMRUList expected %s, got %s\n", "T", buffer); 428 /* make sure space after buffer has old values */ 429 ok(buffer[2] == 'A', "EnumMRUList expected %02x, got %02x\n", 'A', buffer[2]); 430 431 /* check entry 1 */ 432 buffer[0] = 0; 433 iRet = pEnumMRUListA(hMRU, 1, buffer, 255); 434 ok(iRet == lstrlenA(checks[1]), "EnumMRUList expected %d, got %d\n", lstrlenA(checks[1]), iRet); 435 ok(strcmp(buffer, checks[1]) == 0, "EnumMRUList expected %s, got %s\n", checks[1], buffer); 436 437 /* check entry 2 */ 438 buffer[0] = 0; 439 iRet = pEnumMRUListA(hMRU, 2, buffer, 255); 440 ok(iRet == lstrlenA(checks[2]), "EnumMRUList expected %d, got %d\n", lstrlenA(checks[2]), iRet); 441 ok(strcmp(buffer, checks[2]) == 0, "EnumMRUList expected %s, got %s\n", checks[2], buffer); 442 443 /* check out of bounds entry 3 */ 444 strcpy(buffer, "dummy"); 445 iRet = pEnumMRUListA(hMRU, 3, buffer, 255); 446 ok(iRet == -1, "EnumMRUList expected %d, got %d\n", -1, iRet); 447 ok(strcmp(buffer, "dummy") == 0, "EnumMRUList expected unchanged buffer %s, got %s\n", "dummy", buffer); 448 449 /* Finished with this MRU */ 450 pFreeMRUList(hMRU); 451 } 452 453 /* FreeMRUList(NULL) crashes on Win98 OSR0 */ 454 } 455 456 typedef struct { 457 MRUINFOA mruA; 458 BOOL ret; 459 } create_lazya_t; 460 461 static const create_lazya_t create_lazyA[] = { 462 {{ sizeof(MRUINFOA) + 1, 0, 0, HKEY_CURRENT_USER, NULL, NULL }, FALSE }, 463 {{ sizeof(MRUINFOA) - 1, 0, 0, HKEY_CURRENT_USER, NULL, NULL }, FALSE }, 464 {{ sizeof(MRUINFOA) + 1, 0, 0, HKEY_CURRENT_USER, "WineTest", NULL }, TRUE }, 465 {{ sizeof(MRUINFOA) - 1, 0, 0, HKEY_CURRENT_USER, "WineTest", NULL }, TRUE }, 466 {{ sizeof(MRUINFOA), 0, 0, HKEY_CURRENT_USER, "WineTest", NULL }, TRUE }, 467 {{ sizeof(MRUINFOA), 0, 0, HKEY_CURRENT_USER, NULL, NULL }, FALSE }, 468 {{ sizeof(MRUINFOA), 0, 0, NULL, "WineTest", NULL }, FALSE }, 469 {{ 0, 0, 0, NULL, "WineTest", NULL }, FALSE }, 470 {{ 0, 0, 0, HKEY_CURRENT_USER, "WineTest", NULL }, TRUE } 471 }; 472 473 static void test_CreateMRUListLazyA(void) 474 { 475 int i; 476 477 if (!pCreateMRUListLazyA || !pFreeMRUList) 478 { 479 win_skip("CreateMRUListLazyA or FreeMRUList entry points not found\n"); 480 return; 481 } 482 483 for (i = 0; i < sizeof(create_lazyA)/sizeof(create_lazya_t); i++) 484 { 485 const create_lazya_t *ptr = &create_lazyA[i]; 486 HANDLE hMRU; 487 488 hMRU = pCreateMRUListLazyA((MRUINFOA*)&ptr->mruA, 0, 0, 0); 489 if (ptr->ret) 490 { 491 ok(hMRU != NULL, "%d: got %p\n", i, hMRU); 492 pFreeMRUList(hMRU); 493 } 494 else 495 ok(hMRU == NULL, "%d: got %p\n", i, hMRU); 496 } 497 } 498 499 static void test_EnumMRUList(void) 500 { 501 if (!pEnumMRUListA || !pEnumMRUListW) 502 { 503 win_skip("EnumMRUListA/EnumMRUListW entry point not found\n"); 504 return; 505 } 506 507 /* NULL handle */ 508 if (0) 509 { 510 /* crashes on NT4, passed on Win2k, XP, 2k3, Vista, 2k8 */ 511 pEnumMRUListA(NULL, 0, NULL, 0); 512 pEnumMRUListW(NULL, 0, NULL, 0); 513 } 514 } 515 516 static void test_FindMRUData(void) 517 { 518 INT iRet; 519 520 if (!pFindMRUData) 521 { 522 win_skip("FindMRUData entry point not found\n"); 523 return; 524 } 525 526 /* NULL handle */ 527 iRet = pFindMRUData(NULL, NULL, 0, NULL); 528 ok(iRet == -1, "FindMRUData expected -1, got %d\n", iRet); 529 } 530 531 static void test_AddMRUData(void) 532 { 533 INT iRet; 534 535 if (!pAddMRUData) 536 { 537 win_skip("AddMRUData entry point not found\n"); 538 return; 539 } 540 541 /* NULL handle */ 542 iRet = pFindMRUData(NULL, NULL, 0, NULL); 543 ok(iRet == -1, "AddMRUData expected -1, got %d\n", iRet); 544 } 545 546 static void test_CreateMRUListW(void) 547 { 548 static const WCHAR mrutestW[] = {'M','R','U','T','e','s','t',0}; 549 MRUINFOW infoW; 550 void *named; 551 HKEY hKey; 552 HANDLE hMru; 553 554 if (!pCreateMRUListW) 555 { 556 win_skip("CreateMRUListW entry point not found\n"); 557 return; 558 } 559 560 /* exported by name too on recent versions */ 561 named = GetProcAddress(hComctl32, "CreateMRUListW"); 562 if (named) 563 ok(named == pCreateMRUListW, "got %p, expected %p\n", named, pCreateMRUListW); 564 565 ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey), 566 "Couldn't create test key \"%s\"\n", REG_TEST_KEYA); 567 568 infoW.cbSize = sizeof(infoW); 569 infoW.uMax = 1; 570 infoW.fFlags = 0; 571 infoW.lpszSubKey = mrutestW; 572 infoW.hKey = hKey; 573 infoW.lpfnCompare = NULL; 574 575 hMru = pCreateMRUListW(&infoW); 576 ok(hMru != NULL, "got %p\n", hMru); 577 pFreeMRUList(hMru); 578 579 /* smaller size */ 580 infoW.cbSize = sizeof(infoW) - 1; 581 infoW.uMax = 1; 582 infoW.fFlags = 0; 583 infoW.lpszSubKey = mrutestW; 584 infoW.hKey = hKey; 585 infoW.lpfnCompare = NULL; 586 587 hMru = pCreateMRUListW(&infoW); 588 ok(hMru != NULL, "got %p\n", hMru); 589 pFreeMRUList(hMru); 590 591 /* increased size */ 592 infoW.cbSize = sizeof(infoW) + 1; 593 infoW.uMax = 1; 594 infoW.fFlags = 0; 595 infoW.lpszSubKey = mrutestW; 596 infoW.hKey = hKey; 597 infoW.lpfnCompare = NULL; 598 599 hMru = pCreateMRUListW(&infoW); 600 ok(hMru != NULL, "got %p\n", hMru); 601 pFreeMRUList(hMru); 602 603 /* zero size */ 604 infoW.cbSize = 0; 605 infoW.uMax = 1; 606 infoW.fFlags = 0; 607 infoW.lpszSubKey = mrutestW; 608 infoW.hKey = hKey; 609 infoW.lpfnCompare = NULL; 610 611 hMru = pCreateMRUListW(&infoW); 612 ok(hMru != NULL, "got %p\n", hMru); 613 pFreeMRUList(hMru); 614 615 /* NULL hKey */ 616 infoW.cbSize = sizeof(infoW); 617 infoW.uMax = 1; 618 infoW.fFlags = 0; 619 infoW.lpszSubKey = mrutestW; 620 infoW.hKey = NULL; 621 infoW.lpfnCompare = NULL; 622 623 hMru = pCreateMRUListW(&infoW); 624 ok(hMru == NULL, "got %p\n", hMru); 625 626 RegCloseKey(hKey); 627 } 628 629 static void test_CreateMRUListLazyW(void) 630 { 631 static const WCHAR mrutestW[] = {'M','R','U','T','e','s','t',0}; 632 MRUINFOW infoW; 633 void *named; 634 HKEY hKey; 635 HANDLE hMru; 636 637 if (!pCreateMRUListLazyW) 638 { 639 win_skip("CreateMRUListLazyW entry point not found\n"); 640 return; 641 } 642 643 /* check that it's not exported by name */ 644 named = GetProcAddress(hComctl32, "CreateMRUListLazyW"); 645 ok(named == NULL, "got %p\n", named); 646 647 ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey), 648 "Couldn't create test key \"%s\"\n", REG_TEST_KEYA); 649 650 infoW.cbSize = sizeof(infoW); 651 infoW.uMax = 1; 652 infoW.fFlags = 0; 653 infoW.lpszSubKey = mrutestW; 654 infoW.hKey = hKey; 655 infoW.lpfnCompare = NULL; 656 657 hMru = pCreateMRUListLazyW(&infoW, 0, 0, 0); 658 ok(hMru != NULL, "got %p\n", hMru); 659 pFreeMRUList(hMru); 660 661 /* smaller size */ 662 infoW.cbSize = sizeof(infoW) - 1; 663 infoW.uMax = 1; 664 infoW.fFlags = 0; 665 infoW.lpszSubKey = mrutestW; 666 infoW.hKey = hKey; 667 infoW.lpfnCompare = NULL; 668 669 hMru = pCreateMRUListLazyW(&infoW, 0, 0, 0); 670 ok(hMru != NULL, "got %p\n", hMru); 671 pFreeMRUList(hMru); 672 673 /* increased size */ 674 infoW.cbSize = sizeof(infoW) + 1; 675 infoW.uMax = 1; 676 infoW.fFlags = 0; 677 infoW.lpszSubKey = mrutestW; 678 infoW.hKey = hKey; 679 infoW.lpfnCompare = NULL; 680 681 hMru = pCreateMRUListLazyW(&infoW, 0, 0, 0); 682 ok(hMru != NULL, "got %p\n", hMru); 683 pFreeMRUList(hMru); 684 685 /* zero size */ 686 infoW.cbSize = 0; 687 infoW.uMax = 1; 688 infoW.fFlags = 0; 689 infoW.lpszSubKey = mrutestW; 690 infoW.hKey = hKey; 691 infoW.lpfnCompare = NULL; 692 693 hMru = pCreateMRUListLazyW(&infoW, 0, 0, 0); 694 ok(hMru != NULL, "got %p\n", hMru); 695 pFreeMRUList(hMru); 696 697 /* NULL hKey */ 698 infoW.cbSize = sizeof(infoW); 699 infoW.uMax = 1; 700 infoW.fFlags = 0; 701 infoW.lpszSubKey = mrutestW; 702 infoW.hKey = NULL; 703 infoW.lpfnCompare = NULL; 704 705 hMru = pCreateMRUListLazyW(&infoW, 0, 0, 0); 706 ok(hMru == NULL, "got %p\n", hMru); 707 708 RegCloseKey(hKey); 709 } 710 711 START_TEST(mru) 712 { 713 delete_reg_entries(); 714 if (!create_reg_entries()) 715 return; 716 717 init_functions(); 718 719 test_MRUListA(); 720 test_CreateMRUListLazyA(); 721 test_CreateMRUListLazyW(); 722 test_EnumMRUList(); 723 test_FindMRUData(); 724 test_AddMRUData(); 725 test_CreateMRUListW(); 726 727 delete_reg_entries(); 728 } 729