2 * comctl32 MRU unit tests
4 * Copyright (C) 2004 Jon Griffiths <jon_p_griffiths@yahoo.com>
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.
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.
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
31 #include "wine/test.h"
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
40 /* Undocumented MRU structures & functions */
41 typedef struct tagCREATEMRULISTA
49 } CREATEMRULISTA, *LPCREATEMRULISTA;
51 #define MRUF_STRING_LIST 0
52 #define MRUF_BINARY_LIST 1
53 #define MRUF_DELAYED_SAVE 2
55 #define LIST_SIZE 3 /* Max entries for each mru */
57 static CREATEMRULISTA mruA =
59 sizeof(CREATEMRULISTA),
67 static HMODULE hComctl32;
68 static HANDLE (WINAPI *pCreateMRUListA)(LPCREATEMRULISTA);
69 static void (WINAPI *pFreeMRUList)(HANDLE);
70 static INT (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR);
71 static INT (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
73 static INT (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT);
77 static BOOL create_reg_entries(void)
81 ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
82 "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
83 if (!hKey) return FALSE;
88 static void delete_reg_entries(void)
92 if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_BASEKEYA, 0, KEY_ALL_ACCESS,
95 SHDeleteKeyA(hKey, REG_TEST_BASESUBKEYA);
99 static void check_reg_entries(const char *mrulist, const char**items)
103 DWORD type, size, ret;
106 ok(!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
107 "Couldn't open test key \"%s\"\n", REG_TEST_FULLKEY);
113 ret = RegQueryValueExA(hKey, "MRUList", NULL, &type, (LPBYTE)buff, &size);
115 ok(!ret && buff[0], "Checking MRU: got %d from RegQueryValueExW\n", ret);
116 if(ret || !buff[0]) return;
118 ok(strcmp(buff, mrulist) == 0, "Checking MRU: Expected list %s, got %s\n",
120 if(strcmp(buff, mrulist)) return;
122 for (i = 0; i < strlen(mrulist); i++)
125 name[0] = mrulist[i];
130 ret = RegQueryValueExA(hKey, name, NULL, &type, (LPBYTE)buff, &size);
132 "Checking MRU item %d ('%c'): got %d from RegQueryValueExW\n",
134 if(ret || !buff[0]) return;
135 ok(!strcmp(buff, items[mrulist[i]-'a']),
136 "Checking MRU item %d ('%c'): expected \"%s\", got \"%s\"\n",
137 i, mrulist[i], buff, items[mrulist[i] - 'a']);
141 static INT CALLBACK cmp_mru_strA(LPCVOID data1, LPCVOID data2)
143 return lstrcmpiA(data1, data2);
146 static HANDLE create_mruA(HKEY hKey, DWORD flags, PROC cmp)
148 mruA.dwFlags = flags;
149 mruA.lpfnCompare = cmp;
153 return pCreateMRUListA(&mruA);
156 static void test_MRUListA(void)
158 const char *checks[LIST_SIZE+1];
163 pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151);
164 pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152);
165 pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153);
166 pEnumMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)154);
168 if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA || !pEnumMRUList)
170 skip("MRU entry points not found\n");
176 /* Create (NULL) - crashes native */
177 hMRU = pCreateMRUListA(NULL);
180 /* Create (size too small) */
181 mruA.cbSize = sizeof(mruA) - 2;
182 hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
183 ok (!hMRU && !GetLastError(),
184 "CreateMRUListA(too small) expected NULL,0 got %p,%d\n",
185 hMRU, GetLastError());
186 mruA.cbSize = sizeof(mruA);
188 /* Create (size too big) */
189 mruA.cbSize = sizeof(mruA) + 2;
190 hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
191 ok (!hMRU && !GetLastError(),
192 "CreateMRUListA(too big) expected NULL,0 got %p,%d\n",
193 hMRU, GetLastError());
194 mruA.cbSize = sizeof(mruA);
196 /* Create (NULL hKey) */
197 hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
198 ok (!hMRU && !GetLastError(),
199 "CreateMRUListA(NULL key) expected NULL,0 got %p,%d\n",
200 hMRU, GetLastError());
202 /* Create (NULL name) */
203 mruA.lpszSubKey = NULL;
204 hMRU = create_mruA(NULL, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
205 ok (!hMRU && !GetLastError(),
206 "CreateMRUListA(NULL name) expected NULL,0 got %p,%d\n",
207 hMRU, GetLastError());
208 mruA.lpszSubKey = REG_TEST_SUBKEYA;
210 /* Create a string MRU */
211 ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey),
212 "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
215 hMRU = create_mruA(hKey, MRUF_STRING_LIST, (PROC)cmp_mru_strA);
216 ok(hMRU && !GetLastError(),
217 "CreateMRUListA(string) expected non-NULL,0 got %p,%d\n",
218 hMRU, GetLastError());
223 checks[0] = "Test 1";
224 checks[1] = "Test 2";
225 checks[2] = "Test 3";
226 checks[3] = "Test 4";
228 /* Add (NULL list) */
230 iRet = pAddMRUStringA(NULL, checks[0]);
231 ok(iRet == -1 && !GetLastError(),
232 "AddMRUStringA(NULL list) expected -1,0 got %d,%d\n",
233 iRet, GetLastError());
235 /* Add (NULL string) */
238 /* Some native versions crash when passed NULL or fail to SetLastError() */
240 iRet = pAddMRUStringA(hMRU, NULL);
241 ok(iRet == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
242 "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%d\n",
243 iRet, GetLastError());
246 /* Add 3 strings. Check the registry is correct after each add */
248 iRet = pAddMRUStringA(hMRU, checks[0]);
249 ok(iRet == 0 && !GetLastError(),
250 "AddMRUStringA(1) expected 0,0 got %d,%d\n",
251 iRet, GetLastError());
252 check_reg_entries("a", checks);
255 iRet = pAddMRUStringA(hMRU, checks[1]);
256 ok(iRet == 1 && !GetLastError(),
257 "AddMRUStringA(2) expected 1,0 got %d,%d\n",
258 iRet, GetLastError());
259 check_reg_entries("ba", checks);
262 iRet = pAddMRUStringA(hMRU, checks[2]);
263 ok(iRet == 2 && !GetLastError(),
264 "AddMRUStringA(2) expected 2,0 got %d,%d\n",
265 iRet, GetLastError());
266 check_reg_entries("cba", checks);
268 /* Add a duplicate of the 2nd string - it should move to the front,
269 * but keep the same index in the registry.
272 iRet = pAddMRUStringA(hMRU, checks[1]);
273 ok(iRet == 1 && !GetLastError(),
274 "AddMRUStringA(re-add 1) expected 1,0 got %d,%d\n",
275 iRet, GetLastError());
276 check_reg_entries("bca", checks);
278 /* Add a new string - replaces the oldest string + moves to the front */
280 iRet = pAddMRUStringA(hMRU, checks[3]);
281 ok(iRet == 0 && !GetLastError(),
282 "AddMRUStringA(add new) expected 0,0 got %d,%d\n",
283 iRet, GetLastError());
284 checks[0] = checks[3];
285 check_reg_entries("abc", checks);
287 /* NULL buffer = get list size */
288 iRet = pEnumMRUList(hMRU, 0, NULL, 0);
289 ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
291 /* negative item pos = get list size */
292 iRet = pEnumMRUList(hMRU, -1, NULL, 0);
293 ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
295 /* negative item pos = get list size */
296 iRet = pEnumMRUList(hMRU, -5, NULL, 0);
297 ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
299 /* negative item pos = get list size */
300 iRet = pEnumMRUList(hMRU, -1, buffer, 255);
301 ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
303 /* negative item pos = get list size */
304 iRet = pEnumMRUList(hMRU, -5, buffer, 255);
305 ok(iRet == 3, "EnumMRUList expected %d, got %d\n", LIST_SIZE, iRet);
309 iRet = pEnumMRUList(hMRU, 0, buffer, 255);
310 todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
311 ok(strcmp(buffer, checks[3]) == 0, "EnumMRUList expected %s, got %s\n", checks[3], buffer);
313 /* check entry 0 with a too small buffer */
314 buffer[0] = 0; /* overwritten with 'T' */
315 buffer[1] = 'A'; /* overwritten with 0 */
316 buffer[2] = 'A'; /* unchanged */
317 buffer[3] = 0; /* unchanged */
318 iRet = pEnumMRUList(hMRU, 0, buffer, 2);
319 todo_wine ok(iRet == lstrlen(checks[3]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[3]), iRet);
320 todo_wine ok(strcmp(buffer, "T") == 0, "EnumMRUList expected %s, got %s\n", "T", buffer);
321 /* make sure space after buffer has old values */
322 ok(buffer[2] == 'A', "EnumMRUList expected %02x, got %02x\n", 'A', buffer[2]);
326 iRet = pEnumMRUList(hMRU, 1, buffer, 255);
327 todo_wine ok(iRet == lstrlen(checks[1]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[1]), iRet);
328 ok(strcmp(buffer, checks[1]) == 0, "EnumMRUList expected %s, got %s\n", checks[1], buffer);
332 iRet = pEnumMRUList(hMRU, 2, buffer, 255);
333 todo_wine ok(iRet == lstrlen(checks[2]), "EnumMRUList expected %d, got %d\n", lstrlen(checks[2]), iRet);
334 ok(strcmp(buffer, checks[2]) == 0, "EnumMRUList expected %s, got %s\n", checks[2], buffer);
336 /* check out of bounds entry 3 */
337 strcpy(buffer, "dummy");
338 iRet = pEnumMRUList(hMRU, 3, buffer, 255);
339 ok(iRet == -1, "EnumMRUList expected %d, got %d\n", -1, iRet);
340 ok(strcmp(buffer, "dummy") == 0, "EnumMRUList expected unchanged buffer %s, got %s\n", "dummy", buffer);
342 /* Finished with this MRU */
346 /* Free (NULL list) - Doesn't crash */
352 hComctl32 = GetModuleHandleA("comctl32.dll");
354 delete_reg_entries();
355 if (!create_reg_entries())
360 delete_reg_entries();