[COMCTL32_WINETEST] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / modules / rostests / winetests / comctl32 / mru.c
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 > ARRAY_SIZE(szNameBuf))
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 < ARRAY_SIZE(create_lazyA); 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 }