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 SHPropertyBag Read/Write 5 * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8 #include <apitest.h> 9 #include <shlwapi.h> 10 #include <shlobj.h> 11 #include <shlwapi_undoc.h> 12 #include <versionhelpers.h> 13 14 #include <pseh/pseh2.h> 15 16 static LPCWSTR s_pszPropNames[4] = { NULL, NULL, NULL, NULL }; 17 static VARTYPE s_vt; 18 static INT s_cRead = 0; 19 static INT s_cWrite = 0; 20 21 static void ResetTest(VARTYPE vt, 22 LPCWSTR pszName0 = NULL, LPCWSTR pszName1 = NULL, 23 LPCWSTR pszName2 = NULL, LPCWSTR pszName3 = NULL) 24 { 25 s_vt = vt; 26 s_cRead = s_cWrite = 0; 27 s_pszPropNames[0] = pszName0; 28 s_pszPropNames[1] = pszName1; 29 s_pszPropNames[2] = pszName2; 30 s_pszPropNames[3] = pszName3; 31 } 32 33 static SAFEARRAY* CreateByteArray(LPCVOID pvSrc, DWORD cbSize) 34 { 35 SAFEARRAYBOUND Bound; 36 Bound.lLbound = 0; 37 Bound.cElements = cbSize; 38 39 SAFEARRAY* pArray = SafeArrayCreate(VT_UI1, 1, &Bound); 40 if (!pArray) 41 return NULL; 42 43 void HUGEP *pvData; 44 HRESULT hr = SafeArrayAccessData(pArray, &pvData); 45 if (FAILED(hr)) 46 { 47 SafeArrayDestroy(pArray); 48 return NULL; 49 } 50 51 CopyMemory(pvData, pvSrc, cbSize); 52 SafeArrayUnaccessData(pArray); 53 54 return pArray; 55 } 56 57 class CDummyPropertyBag : public IPropertyBag 58 { 59 public: 60 CDummyPropertyBag() 61 { 62 } 63 64 // IUnknown 65 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override 66 { 67 ok(FALSE, "Unexpected call\n"); 68 return S_OK; 69 } 70 STDMETHODIMP_(ULONG) AddRef() override 71 { 72 ok(FALSE, "Unexpected call\n"); 73 return S_OK; 74 } 75 STDMETHODIMP_(ULONG) Release() override 76 { 77 ok(FALSE, "Unexpected call\n"); 78 return S_OK; 79 } 80 81 // IPropertyBag 82 STDMETHODIMP Read(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog) override 83 { 84 ++s_cRead; 85 ok_int(s_vt, V_VT(pvari)); 86 for (size_t i = 0; i < _countof(s_pszPropNames); ++i) 87 { 88 if (s_pszPropNames[i]) 89 { 90 ok_wstr(pszPropName, s_pszPropNames[i]); 91 s_pszPropNames[i] = NULL; 92 93 if (lstrcmpiW(pszPropName, L"RECTL2.top") == 0) 94 return E_FAIL; 95 96 if (lstrcmpiW(pszPropName, L"GUID1") == 0) 97 { 98 V_VT(pvari) = (VT_UI1 | VT_ARRAY); 99 V_ARRAY(pvari) = CreateByteArray(&IID_IShellLink, sizeof(IID)); 100 return S_OK; 101 } 102 103 if (lstrcmpiW(pszPropName, L"GUID2") == 0) 104 { 105 WCHAR szText[50]; 106 StringFromGUID2(IID_IUnknown, szText, _countof(szText)); 107 108 V_VT(pvari) = VT_BSTR; 109 V_BSTR(pvari) = SysAllocString(szText); 110 return S_OK; 111 } 112 113 if (lstrcmpiW(pszPropName, L"GUID3") == 0) 114 { 115 V_VT(pvari) = VT_EMPTY; 116 V_UI4(pvari) = 0xDEADFACE; 117 return S_OK; 118 } 119 120 goto Skip1; 121 } 122 } 123 ok(FALSE, "Unexpected call\n"); 124 Skip1: 125 return S_OK; 126 } 127 128 STDMETHODIMP Write(LPCWSTR pszPropName, VARIANT *pvari) override 129 { 130 ++s_cWrite; 131 ok_int(s_vt, V_VT(pvari)); 132 for (size_t i = 0; i < _countof(s_pszPropNames); ++i) 133 { 134 if (s_pszPropNames[i]) 135 { 136 ok_wstr(pszPropName, s_pszPropNames[i]); 137 s_pszPropNames[i] = NULL; 138 if (lstrcmpiW(pszPropName, L"RECTL2.bottom") == 0) 139 { 140 s_vt = VT_EMPTY; 141 ZeroMemory(&s_pszPropNames, sizeof(s_pszPropNames)); 142 s_pszPropNames[0] = L"RECTL2.right"; 143 return E_FAIL; 144 } 145 goto Skip2; 146 } 147 } 148 ok(FALSE, "Unexpected call\n"); 149 Skip2: 150 return S_OK; 151 } 152 }; 153 154 static void SHPropertyBag_ReadTest(void) 155 { 156 HRESULT hr; 157 CDummyPropertyBag dummy; 158 BOOL bValue = 0xDEADFACE; 159 SHORT sValue = 0xDEAD; 160 LONG lValue = 0xDEADDEAD; 161 DWORD dwValue = 0xFEEDF00D; 162 BSTR bstr = NULL; 163 POINTL ptl = { 0xEEEE, 0xDDDD }; 164 POINTS pts = { 0x2222, 0x3333 }; 165 RECTL rcl = { 123, 456, 789, 101112 }; 166 GUID guid = { 0 }; 167 168 ResetTest(VT_BOOL, L"BOOL1"); 169 hr = SHPropertyBag_ReadBOOL(&dummy, s_pszPropNames[0], &bValue); 170 ok_long(hr, S_OK); 171 ok_int(s_cRead, 1); 172 ok_int(s_cWrite, 0); 173 174 ResetTest(VT_UI2, L"SHORT1"); 175 hr = SHPropertyBag_ReadSHORT(&dummy, s_pszPropNames[0], &sValue); 176 ok_long(hr, S_OK); 177 ok_int(s_cRead, 1); 178 ok_int(s_cWrite, 0); 179 180 ResetTest(VT_I4, L"LONG1"); 181 hr = SHPropertyBag_ReadLONG(&dummy, s_pszPropNames[0], &lValue); 182 ok_long(hr, S_OK); 183 ok_int(s_cRead, 1); 184 ok_int(s_cWrite, 0); 185 186 ResetTest(VT_UI4, L"DWORD1"); 187 hr = SHPropertyBag_ReadDWORD(&dummy, s_pszPropNames[0], &dwValue); 188 ok_long(hr, S_OK); 189 ok_int(s_cRead, 1); 190 ok_int(s_cWrite, 0); 191 192 ResetTest(VT_BSTR, L"Str1"); 193 hr = SHPropertyBag_ReadBSTR(&dummy, s_pszPropNames[0], &bstr); 194 ok_long(hr, S_OK); 195 ok_int(s_cRead, 1); 196 ok_int(s_cWrite, 0); 197 SysFreeString(bstr); 198 199 ResetTest(VT_I4, L"POINTL1.x", L"POINTL1.y"); 200 hr = SHPropertyBag_ReadPOINTL(&dummy, L"POINTL1", &ptl); 201 ok_long(hr, S_OK); 202 ok_int(s_cRead, 2); 203 ok_int(s_cWrite, 0); 204 205 ResetTest(VT_I4, L"POINTS1.x", L"POINTS1.y"); 206 hr = SHPropertyBag_ReadPOINTS(&dummy, L"POINTS1", &pts); 207 ok_long(hr, S_OK); 208 ok_int(s_cRead, 2); 209 ok_int(s_cWrite, 0); 210 211 ResetTest(VT_I4, L"RECTL1.left", L"RECTL1.top", L"RECTL1.right", L"RECTL1.bottom"); 212 hr = SHPropertyBag_ReadRECTL(&dummy, L"RECTL1", &rcl); 213 ok_long(hr, S_OK); 214 ok_int(s_cRead, 4); 215 ok_int(s_cWrite, 0); 216 217 ResetTest(VT_I4, L"RECTL2.left", L"RECTL2.top", L"RECTL2.right", L"RECTL2.bottom"); 218 hr = SHPropertyBag_ReadRECTL(&dummy, L"RECTL2", &rcl); 219 ok_long(hr, E_FAIL); 220 ok_int(s_cRead, 2); 221 ok_int(s_cWrite, 0); 222 223 ResetTest(VT_EMPTY, L"GUID1"); 224 hr = SHPropertyBag_ReadGUID(&dummy, L"GUID1", &guid); 225 ok_long(hr, S_OK); 226 ok_int(s_cRead, 1); 227 ok_int(s_cWrite, 0); 228 ok_int(IsEqualGUID(guid, IID_IShellLink), TRUE); 229 230 ResetTest(VT_EMPTY, L"GUID2"); 231 hr = SHPropertyBag_ReadGUID(&dummy, L"GUID2", &guid); 232 ok_long(hr, S_OK); 233 ok_int(s_cRead, 1); 234 ok_int(s_cWrite, 0); 235 ok_int(IsEqualGUID(guid, IID_IUnknown), TRUE); 236 237 ResetTest(VT_EMPTY, L"GUID3"); 238 guid = IID_IExtractIcon; 239 hr = SHPropertyBag_ReadGUID(&dummy, L"GUID3", &guid); 240 241 if (IsWindowsVistaOrGreater()) 242 ok_long(hr, E_INVALIDARG); 243 else 244 ok_long(hr, S_OK); 245 246 ok_int(s_cRead, 1); 247 ok_int(s_cWrite, 0); 248 ok_int(IsEqualGUID(guid, IID_IExtractIcon), TRUE); 249 } 250 251 static void SHPropertyBag_WriteTest(void) 252 { 253 HRESULT hr; 254 CDummyPropertyBag dummy; 255 256 ResetTest(VT_EMPTY, L"EMPTY1"); 257 hr = SHPropertyBag_Delete(&dummy, s_pszPropNames[0]); 258 ok_long(hr, S_OK); 259 ok_int(s_cRead, 0); 260 ok_int(s_cWrite, 1); 261 262 ResetTest(VT_BOOL, L"BOOL1"); 263 hr = SHPropertyBag_WriteBOOL(&dummy, s_pszPropNames[0], TRUE); 264 ok_long(hr, S_OK); 265 ok_int(s_cRead, 0); 266 ok_int(s_cWrite, 1); 267 268 ResetTest(VT_UI2, L"SHORT1"); 269 hr = SHPropertyBag_WriteSHORT(&dummy, s_pszPropNames[0], 1); 270 ok_long(hr, S_OK); 271 ok_int(s_cRead, 0); 272 ok_int(s_cWrite, 1); 273 274 ResetTest(VT_I4, L"LONG1"); 275 hr = SHPropertyBag_WriteLONG(&dummy, s_pszPropNames[0], 1); 276 ok_long(hr, S_OK); 277 ok_int(s_cRead, 0); 278 ok_int(s_cWrite, 1); 279 280 ResetTest(VT_UI4, L"DWORD1"); 281 hr = SHPropertyBag_WriteDWORD(&dummy, s_pszPropNames[0], 1); 282 ok_long(hr, S_OK); 283 ok_int(s_cRead, 0); 284 ok_int(s_cWrite, 1); 285 286 ResetTest(VT_BSTR, L"Str1"); 287 hr = SHPropertyBag_WriteStr(&dummy, s_pszPropNames[0], L"1"); 288 ok_long(hr, S_OK); 289 ok_int(s_cRead, 0); 290 ok_int(s_cWrite, 1); 291 292 ResetTest(VT_I4, L"POINTL1.x", L"POINTL1.y"); 293 POINTL ptl = { 0xEEEE, 0xDDDD }; 294 hr = SHPropertyBag_WritePOINTL(&dummy, L"POINTL1", &ptl); 295 ok_long(hr, S_OK); 296 ok_int(s_cRead, 0); 297 ok_int(s_cWrite, 2); 298 299 ResetTest(VT_I4, L"POINTS1.x", L"POINTS1.y"); 300 POINTS pts = { 0x2222, 0x3333 }; 301 hr = SHPropertyBag_WritePOINTS(&dummy, L"POINTS1", &pts); 302 ok_long(hr, S_OK); 303 ok_int(s_cRead, 0); 304 ok_int(s_cWrite, 2); 305 306 ResetTest(VT_I4, L"RECTL1.left", L"RECTL1.top", L"RECTL1.right", L"RECTL1.bottom"); 307 RECTL rcl = { 123, 456, 789, 101112 }; 308 hr = SHPropertyBag_WriteRECTL(&dummy, L"RECTL1", &rcl); 309 ok_long(hr, S_OK); 310 ok_int(s_cRead, 0); 311 ok_int(s_cWrite, 4); 312 313 ResetTest(VT_I4, L"RECTL2.left", L"RECTL2.top", L"RECTL2.right", L"RECTL2.bottom"); 314 hr = SHPropertyBag_WriteRECTL(&dummy, L"RECTL2", &rcl); 315 ok_long(hr, S_OK); 316 ok_int(s_cRead, 0); 317 ok_int(s_cWrite, 5); 318 319 GUID guid; 320 ZeroMemory(&guid, sizeof(guid)); 321 ResetTest(VT_BSTR, L"GUID1"); 322 hr = SHPropertyBag_WriteGUID(&dummy, L"GUID1", &guid); 323 ok_long(hr, S_OK); 324 ok_int(s_cRead, 0); 325 ok_int(s_cWrite, 1); 326 } 327 328 START_TEST(SHPropertyBag) 329 { 330 SHPropertyBag_ReadTest(); 331 SHPropertyBag_WriteTest(); 332 } 333