1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Tests for MRU List
5 * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8 #include <apitest.h>
9 #include <winreg.h>
10 #include <shlwapi.h>
11 #include <shlobj.h>
12 #include <shlobj_undoc.h>
13 #include <shlguid_undoc.h>
14 #include <stdio.h>
15 #include <shlwapi_undoc.h>
16 #include <versionhelpers.h>
17 #include <strsafe.h>
18 #include <wine/test.h>
19 #include <pseh/pseh2.h>
20
21 #define SUBKEY0 L"Software\\MRUListTest"
22 #define SUBSUBKEY0 L"Software\\MRUListTest\\0"
23 #define TEXT0 L"This is a test."
24 #define TEXT1 L"ReactOS rocks!"
25
MRUList_DataList_0(void)26 static void MRUList_DataList_0(void)
27 {
28 HRESULT hr;
29 IMruDataList *pList = NULL;
30 UINT iSlot1, iSlot2, iSlot3;
31 DWORD cbText;
32 WCHAR szText[MAX_PATH];
33
34 hr = CoCreateInstance(CLSID_MruLongList, NULL, CLSCTX_INPROC_SERVER,
35 IID_IMruDataList, (LPVOID*)&pList);
36 ok_hex(hr, S_OK);
37 if (pList == NULL)
38 {
39 skip("pList was NULL\n");
40 return;
41 }
42
43 hr = pList->InitData(26, 0, HKEY_CURRENT_USER, SUBKEY0, NULL);
44 ok_hex(hr, S_OK);
45
46 cbText = (wcslen(TEXT0) + 1) * sizeof(WCHAR);
47 hr = pList->AddData((BYTE*)TEXT0, cbText, &iSlot1);
48 ok_hex(hr, S_OK);
49 ok_int(iSlot1, 0);
50
51 hr = pList->FindData((BYTE*)TEXT0, cbText, &iSlot2);
52 ok_hex(hr, S_OK);
53 ok_int(iSlot1, iSlot2);
54
55 cbText = sizeof(szText);
56 hr = pList->GetData(iSlot1, (BYTE*)szText, cbText);
57 ok_hex(hr, S_OK);
58 ok_wstr(szText, TEXT0);
59
60 cbText = (wcslen(TEXT1) + 1) * sizeof(WCHAR);
61 hr = pList->AddData((BYTE*)TEXT1, cbText, &iSlot3);
62 ok_hex(hr, S_OK);
63 ok_int(iSlot3, 1);
64
65 pList->Release();
66 }
67
MRUList_Check(LPCWSTR pszSubKey,LPCWSTR pszValueName,LPCVOID pvData,DWORD cbData)68 static INT MRUList_Check(LPCWSTR pszSubKey, LPCWSTR pszValueName, LPCVOID pvData, DWORD cbData)
69 {
70 BYTE abData[512];
71 LONG error;
72 DWORD dwSize = cbData;
73
74 error = SHGetValueW(HKEY_CURRENT_USER, pszSubKey, pszValueName, NULL, abData, &dwSize);
75 if (error != ERROR_SUCCESS)
76 return -999;
77
78 #if 0
79 printf("dwSize: %ld\n", dwSize);
80 for (DWORD i = 0; i < dwSize; ++i)
81 {
82 printf("%02X ", abData[i]);
83 }
84 printf("\n");
85 #endif
86
87 if (dwSize != cbData)
88 return +999;
89
90 if (!pvData)
91 return TRUE;
92
93 return memcmp(abData, pvData, cbData) == 0;
94 }
95
MRUList_DataList_1(void)96 static void MRUList_DataList_1(void)
97 {
98 HRESULT hr;
99 IMruDataList *pList = NULL;
100 UINT iSlot;
101
102 hr = CoCreateInstance(CLSID_MruLongList, NULL, CLSCTX_INPROC_SERVER,
103 IID_IMruDataList, (LPVOID*)&pList);
104 ok_hex(hr, S_OK);
105 if (pList == NULL)
106 {
107 skip("pList was NULL\n");
108 return;
109 }
110
111 hr = pList->InitData(26, 0, HKEY_CURRENT_USER, SUBKEY0, NULL);
112 ok_hex(hr, S_OK);
113
114 DWORD cbText = (wcslen(TEXT0) + 1) * sizeof(WCHAR);
115 hr = pList->FindData((BYTE*)TEXT0, cbText, &iSlot);
116 ok_hex(hr, S_OK);
117 ok_int(iSlot, 1);
118
119 hr = pList->Delete(iSlot);
120 ok_hex(hr, S_OK);
121
122 iSlot = 0xCAFE;
123 cbText = (wcslen(TEXT0) + 1) * sizeof(WCHAR);
124 hr = pList->FindData((BYTE*)TEXT0, cbText, &iSlot);
125 ok_hex(hr, E_FAIL);
126 ok_int(iSlot, 0xCAFE);
127
128 pList->Release();
129 }
130
MRUList_DataList_2(void)131 static void MRUList_DataList_2(void)
132 {
133 HRESULT hr;
134 IMruDataList *pList = NULL;
135
136 hr = CoCreateInstance(CLSID_MruLongList, NULL, CLSCTX_INPROC_SERVER,
137 IID_IMruDataList, (LPVOID*)&pList);
138 ok_hex(hr, S_OK);
139 if (pList == NULL)
140 {
141 skip("pList was NULL\n");
142 return;
143 }
144
145 hr = pList->InitData(26, 0, HKEY_CURRENT_USER, SUBKEY0, NULL);
146 ok_hex(hr, S_OK);
147
148 WCHAR szText[MAX_PATH];
149 DWORD cbText = sizeof(szText);
150 StringCchCopyW(szText, _countof(szText), L"====");
151 hr = pList->GetData(0, (BYTE*)szText, cbText);
152 ok_hex(hr, S_OK);
153 ok_wstr(szText, L"ABC");
154
155 StringCchCopyW(szText, _countof(szText), L"====");
156 cbText = sizeof(szText);
157 hr = pList->GetData(1, (BYTE*)szText, cbText);
158 ok_hex(hr, S_OK);
159 ok_wstr(szText, L"XYZ");
160
161 pList->Release();
162 }
163
MRUList_DataList(void)164 static void MRUList_DataList(void)
165 {
166 if (IsWindowsVistaOrGreater())
167 {
168 skip("Vista+ doesn't support CLSID_MruLongList\n");
169 return;
170 }
171
172 SHDeleteKeyW(HKEY_CURRENT_USER, SUBKEY0);
173
174 LONG error;
175 error = SHSetValueW(HKEY_CURRENT_USER, SUBKEY0, NULL, REG_SZ, L"", sizeof(UNICODE_NULL));
176 ok_long(error, ERROR_SUCCESS);
177
178 error = SHGetValueW(HKEY_CURRENT_USER, SUBKEY0, NULL, NULL, NULL, NULL);
179 ok_long(error, ERROR_SUCCESS);
180
181 MRUList_DataList_0();
182 ok_int(MRUList_Check(SUBKEY0, L"MRUListEx", "\x01\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 12), TRUE);
183
184 MRUList_DataList_1();
185 ok_int(MRUList_Check(SUBKEY0, L"MRUListEx", "\x01\x00\x00\x00\xFF\xFF\xFF\xFF", 8), TRUE);
186
187 error = SHDeleteValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUList");
188 ok_long(error, ERROR_FILE_NOT_FOUND);
189 error = SHDeleteValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUListEx");
190 ok_long(error, ERROR_SUCCESS);
191
192 error = SHSetValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUList", REG_SZ, L"ab", 3 * sizeof(WCHAR));
193 ok_long(error, ERROR_SUCCESS);
194 error = SHSetValueW(HKEY_CURRENT_USER, SUBKEY0, L"a", REG_BINARY, L"ABC", 4 * sizeof(WCHAR));
195 ok_long(error, ERROR_SUCCESS);
196 error = SHSetValueW(HKEY_CURRENT_USER, SUBKEY0, L"b", REG_BINARY, L"XYZ", 4 * sizeof(WCHAR));
197 ok_long(error, ERROR_SUCCESS);
198
199 MRUList_DataList_2();
200 ok_int(MRUList_Check(SUBKEY0, L"MRUListEx", "\x00\x00\x00\x00\x01\x00\x00\x00\xFF\xFF\xFF\xFF", 12), TRUE);
201
202 error = SHDeleteValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUList");
203 ok_long(error, ERROR_FILE_NOT_FOUND);
204 error = SHDeleteValueW(HKEY_CURRENT_USER, SUBKEY0, L"MRUListEx");
205 ok_long(error, ERROR_SUCCESS);
206
207 SHDeleteKeyW(HKEY_CURRENT_USER, SUBKEY0);
208 }
209
MRUList_PidlList_0(void)210 static void MRUList_PidlList_0(void)
211 {
212 HRESULT hr;
213 IMruPidlList *pList = NULL;
214
215 hr = CoCreateInstance(CLSID_MruPidlList, NULL, CLSCTX_INPROC_SERVER,
216 IID_IMruPidlList, (LPVOID*)&pList);
217 ok_hex(hr, S_OK);
218 if (pList == NULL)
219 {
220 skip("pList was NULL\n");
221 return;
222 }
223
224 LONG error;
225
226 error = SHGetValueW(HKEY_CURRENT_USER, SUBKEY0, NULL, NULL, NULL, NULL);
227 ok_long(error, ERROR_FILE_NOT_FOUND);
228
229 hr = pList->InitList(32, HKEY_CURRENT_USER, SUBKEY0);
230 ok_hex(hr, S_OK);
231
232 error = SHGetValueW(HKEY_CURRENT_USER, SUBKEY0, NULL, NULL, NULL, NULL);
233 ok_long(error, ERROR_FILE_NOT_FOUND);
234
235 LPITEMIDLIST pidl1, pidl2;
236 SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl1);
237 SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl2);
238
239 UINT uNodeSlot1 = 0xDEADFACE;
240 hr = pList->UsePidl(pidl1, &uNodeSlot1);
241 ok_hex(uNodeSlot1, 1);
242
243 // "NodeSlot" value
244 ok_int(MRUList_Check(SUBKEY0, L"NodeSlot", "\x01\x00\x00\x00", 4), TRUE);
245
246 // "NodeSlots" value (Not "NodeSlot")
247 ok_int(MRUList_Check(SUBKEY0, L"NodeSlots", "\x02", 1), TRUE);
248
249 UINT uNodeSlot2 = 0xDEADFACE;
250 hr = pList->UsePidl(pidl2, &uNodeSlot2);
251 ok_hex(uNodeSlot2, 2);
252
253 // "0" value
254 ok_int(MRUList_Check(SUBKEY0, L"0", NULL, 22), TRUE);
255
256 // "MRUListEx" value
257 ok_int(MRUList_Check(SUBKEY0, L"MRUListEx", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 8), TRUE);
258
259 // "NodeSlot" value
260 ok_int(MRUList_Check(SUBKEY0, L"NodeSlot", "\x01\x00\x00\x00", 4), TRUE);
261
262 // "NodeSlots" value
263 ok_int(MRUList_Check(SUBKEY0, L"NodeSlots", "\x02\x02", 2), TRUE);
264
265 // SUBSUBKEY0: "MRUListEx" value
266 ok_int(MRUList_Check(SUBSUBKEY0, L"MRUListEx", "\xFF\xFF\xFF\xFF", 4), TRUE);
267
268 // SUBSUBKEY0: "NodeSlot" value
269 ok_int(MRUList_Check(SUBSUBKEY0, L"NodeSlot", "\x02\x00\x00\x00", 4), TRUE);
270
271 // QueryPidl
272 UINT anNodeSlot[2], cNodeSlots;
273 FillMemory(anNodeSlot, sizeof(anNodeSlot), 0xCC);
274 cNodeSlots = 0xDEAD;
275 hr = pList->QueryPidl(pidl1, _countof(anNodeSlot), anNodeSlot, &cNodeSlots);
276 ok_long(hr, S_OK);
277 ok_int(anNodeSlot[0], 1);
278 ok_int(anNodeSlot[1], 0xCCCCCCCC);
279 ok_int(cNodeSlots, 1);
280
281 hr = pList->PruneKids(pidl1);
282
283 // "MRUListEx" value
284 ok_int(MRUList_Check(SUBKEY0, L"MRUListEx", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF", 8), TRUE);
285
286 // "NodeSlot" value
287 ok_int(MRUList_Check(SUBKEY0, L"NodeSlot", "\x01\x00\x00\x00", 4), TRUE);
288
289 // "NodeSlots" value
290 ok_int(MRUList_Check(SUBKEY0, L"NodeSlots", "\x02\x00", 2), TRUE);
291
292 FillMemory(anNodeSlot, sizeof(anNodeSlot), 0xCC);
293 cNodeSlots = 0xBEEF;
294 hr = pList->QueryPidl(pidl1, 0, anNodeSlot, &cNodeSlots);
295 ok_long(hr, E_FAIL);
296 ok_int(anNodeSlot[0], 0xCCCCCCCC);
297 ok_int(anNodeSlot[1], 0xCCCCCCCC);
298 ok_int(cNodeSlots, 0);
299
300 FillMemory(anNodeSlot, sizeof(anNodeSlot), 0xCC);
301 cNodeSlots = 0xDEAD;
302 hr = pList->QueryPidl(pidl1, _countof(anNodeSlot), anNodeSlot, &cNodeSlots);
303 ok_long(hr, S_OK);
304 ok_int(anNodeSlot[0], 1);
305 ok_int(anNodeSlot[1], 0xCCCCCCCC);
306 ok_int(cNodeSlots, 1);
307
308 FillMemory(anNodeSlot, sizeof(anNodeSlot), 0xCC);
309 cNodeSlots = 0xDEAD;
310 hr = pList->QueryPidl(pidl2, _countof(anNodeSlot), anNodeSlot, &cNodeSlots);
311 ok_long(hr, S_FALSE);
312 ok_int(anNodeSlot[0], 1);
313 ok_int(anNodeSlot[1], 0xCCCCCCCC);
314 ok_int(cNodeSlots, 1);
315
316 pList->Release();
317 ILFree(pidl1);
318 ILFree(pidl2);
319 }
320
MRUList_PidlList(void)321 static void MRUList_PidlList(void)
322 {
323 if (IsWindowsVistaOrGreater())
324 {
325 skip("Vista+ doesn't support CLSID_MruPidlList\n");
326 return;
327 }
328
329 SHDeleteKeyW(HKEY_CURRENT_USER, SUBKEY0);
330
331 MRUList_PidlList_0();
332
333 SHDeleteKeyW(HKEY_CURRENT_USER, SUBKEY0);
334 }
335
START_TEST(MRUList)336 START_TEST(MRUList)
337 {
338 HRESULT hr = CoInitialize(NULL);
339 ok_hex(hr, S_OK);
340
341 MRUList_DataList();
342 MRUList_PidlList();
343
344 if (SUCCEEDED(hr))
345 CoUninitialize();
346 }
347