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