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 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 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 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 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 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 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 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 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