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 <stdio.h> 12 #include <shlwapi_undoc.h> 13 #include <versionhelpers.h> 14 #include <strsafe.h> 15 16 #include <pseh/pseh2.h> 17 18 static LPCWSTR s_pszPropNames[4] = { NULL, NULL, NULL, NULL }; 19 static VARTYPE s_vt; 20 static INT s_cRead = 0; 21 static INT s_cWrite = 0; 22 23 static void ResetTest(VARTYPE vt, 24 LPCWSTR pszName0 = NULL, LPCWSTR pszName1 = NULL, 25 LPCWSTR pszName2 = NULL, LPCWSTR pszName3 = NULL) 26 { 27 s_vt = vt; 28 s_cRead = s_cWrite = 0; 29 s_pszPropNames[0] = pszName0; 30 s_pszPropNames[1] = pszName1; 31 s_pszPropNames[2] = pszName2; 32 s_pszPropNames[3] = pszName3; 33 } 34 35 static SAFEARRAY* CreateByteArray(LPCVOID pvSrc, DWORD cbSize) 36 { 37 SAFEARRAYBOUND Bound; 38 Bound.lLbound = 0; 39 Bound.cElements = cbSize; 40 41 SAFEARRAY* pArray = SafeArrayCreate(VT_UI1, 1, &Bound); 42 if (!pArray) 43 return NULL; 44 45 void HUGEP *pvData; 46 HRESULT hr = SafeArrayAccessData(pArray, &pvData); 47 if (FAILED(hr)) 48 { 49 SafeArrayDestroy(pArray); 50 return NULL; 51 } 52 53 CopyMemory(pvData, pvSrc, cbSize); 54 SafeArrayUnaccessData(pArray); 55 56 return pArray; 57 } 58 59 class CDummyPropertyBag : public IPropertyBag 60 { 61 public: 62 CDummyPropertyBag() 63 { 64 } 65 66 // IUnknown 67 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override 68 { 69 ok(FALSE, "Unexpected call\n"); 70 return S_OK; 71 } 72 STDMETHODIMP_(ULONG) AddRef() override 73 { 74 ok(FALSE, "Unexpected call\n"); 75 return S_OK; 76 } 77 STDMETHODIMP_(ULONG) Release() override 78 { 79 ok(FALSE, "Unexpected call\n"); 80 return S_OK; 81 } 82 83 // IPropertyBag 84 STDMETHODIMP Read(LPCWSTR pszPropName, VARIANT *pvari, IErrorLog *pErrorLog) override 85 { 86 ++s_cRead; 87 ok_int(s_vt, V_VT(pvari)); 88 for (size_t i = 0; i < _countof(s_pszPropNames); ++i) 89 { 90 if (s_pszPropNames[i]) 91 { 92 ok_wstr(pszPropName, s_pszPropNames[i]); 93 s_pszPropNames[i] = NULL; 94 95 if (lstrcmpiW(pszPropName, L"RECTL2.top") == 0) 96 return E_FAIL; 97 98 if (lstrcmpiW(pszPropName, L"GUID1") == 0) 99 { 100 V_VT(pvari) = (VT_UI1 | VT_ARRAY); 101 V_ARRAY(pvari) = CreateByteArray(&IID_IShellLinkW, sizeof(IID)); 102 return S_OK; 103 } 104 105 if (lstrcmpiW(pszPropName, L"GUID2") == 0) 106 { 107 WCHAR szText[50]; 108 StringFromGUID2(IID_IUnknown, szText, _countof(szText)); 109 110 V_VT(pvari) = VT_BSTR; 111 V_BSTR(pvari) = SysAllocString(szText); 112 return S_OK; 113 } 114 115 if (lstrcmpiW(pszPropName, L"GUID3") == 0) 116 { 117 V_VT(pvari) = VT_EMPTY; 118 V_UI4(pvari) = 0xDEADFACE; 119 return S_OK; 120 } 121 122 goto Skip1; 123 } 124 } 125 ok(FALSE, "Unexpected call\n"); 126 Skip1: 127 return S_OK; 128 } 129 130 STDMETHODIMP Write(LPCWSTR pszPropName, VARIANT *pvari) override 131 { 132 ++s_cWrite; 133 ok_int(s_vt, V_VT(pvari)); 134 for (size_t i = 0; i < _countof(s_pszPropNames); ++i) 135 { 136 if (s_pszPropNames[i]) 137 { 138 ok_wstr(pszPropName, s_pszPropNames[i]); 139 s_pszPropNames[i] = NULL; 140 if (lstrcmpiW(pszPropName, L"RECTL2.bottom") == 0) 141 { 142 s_vt = VT_EMPTY; 143 ZeroMemory(&s_pszPropNames, sizeof(s_pszPropNames)); 144 s_pszPropNames[0] = L"RECTL2.right"; 145 return E_FAIL; 146 } 147 goto Skip2; 148 } 149 } 150 ok(FALSE, "Unexpected call\n"); 151 Skip2: 152 return S_OK; 153 } 154 }; 155 156 static void SHPropertyBag_ReadTest(void) 157 { 158 HRESULT hr; 159 CDummyPropertyBag dummy; 160 BOOL bValue = 0xDEADFACE; 161 SHORT sValue = 0xDEADu; 162 LONG lValue = 0xDEADDEAD; 163 DWORD dwValue = 0xFEEDF00D; 164 BSTR bstr = NULL; 165 POINTL ptl = { 0xEEEE, 0xDDDD }; 166 POINTS pts = { 0x2222, 0x3333 }; 167 RECTL rcl = { 123, 456, 789, 101112 }; 168 GUID guid = { 0 }; 169 170 ResetTest(VT_BOOL, L"BOOL1"); 171 hr = SHPropertyBag_ReadBOOL(&dummy, s_pszPropNames[0], &bValue); 172 ok_long(hr, S_OK); 173 ok_int(s_cRead, 1); 174 ok_int(s_cWrite, 0); 175 176 ResetTest(VT_UI2, L"SHORT1"); 177 hr = SHPropertyBag_ReadSHORT(&dummy, s_pszPropNames[0], &sValue); 178 ok_long(hr, S_OK); 179 ok_int(s_cRead, 1); 180 ok_int(s_cWrite, 0); 181 182 ResetTest(VT_I4, L"LONG1"); 183 hr = SHPropertyBag_ReadLONG(&dummy, s_pszPropNames[0], &lValue); 184 ok_long(hr, S_OK); 185 ok_int(s_cRead, 1); 186 ok_int(s_cWrite, 0); 187 188 ResetTest(VT_UI4, L"DWORD1"); 189 hr = SHPropertyBag_ReadDWORD(&dummy, s_pszPropNames[0], &dwValue); 190 ok_long(hr, S_OK); 191 ok_int(s_cRead, 1); 192 ok_int(s_cWrite, 0); 193 194 ResetTest(VT_BSTR, L"Str1"); 195 hr = SHPropertyBag_ReadBSTR(&dummy, s_pszPropNames[0], &bstr); 196 ok_long(hr, S_OK); 197 ok_int(s_cRead, 1); 198 ok_int(s_cWrite, 0); 199 SysFreeString(bstr); 200 201 ResetTest(VT_I4, L"POINTL1.x", L"POINTL1.y"); 202 hr = SHPropertyBag_ReadPOINTL(&dummy, L"POINTL1", &ptl); 203 ok_long(hr, S_OK); 204 ok_int(s_cRead, 2); 205 ok_int(s_cWrite, 0); 206 207 ResetTest(VT_I4, L"POINTS1.x", L"POINTS1.y"); 208 hr = SHPropertyBag_ReadPOINTS(&dummy, L"POINTS1", &pts); 209 ok_long(hr, S_OK); 210 ok_int(s_cRead, 2); 211 ok_int(s_cWrite, 0); 212 213 ResetTest(VT_I4, L"RECTL1.left", L"RECTL1.top", L"RECTL1.right", L"RECTL1.bottom"); 214 hr = SHPropertyBag_ReadRECTL(&dummy, L"RECTL1", &rcl); 215 ok_long(hr, S_OK); 216 ok_int(s_cRead, 4); 217 ok_int(s_cWrite, 0); 218 219 ResetTest(VT_I4, L"RECTL2.left", L"RECTL2.top", L"RECTL2.right", L"RECTL2.bottom"); 220 hr = SHPropertyBag_ReadRECTL(&dummy, L"RECTL2", &rcl); 221 ok_long(hr, E_FAIL); 222 ok_int(s_cRead, 2); 223 ok_int(s_cWrite, 0); 224 225 ResetTest(VT_EMPTY, L"GUID1"); 226 hr = SHPropertyBag_ReadGUID(&dummy, L"GUID1", &guid); 227 ok_long(hr, S_OK); 228 ok_int(s_cRead, 1); 229 ok_int(s_cWrite, 0); 230 ok_int(IsEqualGUID(guid, IID_IShellLinkW), TRUE); 231 232 ResetTest(VT_EMPTY, L"GUID2"); 233 hr = SHPropertyBag_ReadGUID(&dummy, L"GUID2", &guid); 234 ok_long(hr, S_OK); 235 ok_int(s_cRead, 1); 236 ok_int(s_cWrite, 0); 237 ok_int(IsEqualGUID(guid, IID_IUnknown), TRUE); 238 239 ResetTest(VT_EMPTY, L"GUID3"); 240 guid = IID_IExtractIcon; 241 hr = SHPropertyBag_ReadGUID(&dummy, L"GUID3", &guid); 242 243 if (IsWindowsVistaOrGreater()) 244 ok_long(hr, E_INVALIDARG); 245 else 246 ok_long(hr, S_OK); 247 248 ok_int(s_cRead, 1); 249 ok_int(s_cWrite, 0); 250 ok_int(IsEqualGUID(guid, IID_IExtractIcon), TRUE); 251 } 252 253 static void SHPropertyBag_WriteTest(void) 254 { 255 HRESULT hr; 256 CDummyPropertyBag dummy; 257 258 ResetTest(VT_EMPTY, L"EMPTY1"); 259 hr = SHPropertyBag_Delete(&dummy, s_pszPropNames[0]); 260 ok_long(hr, S_OK); 261 ok_int(s_cRead, 0); 262 ok_int(s_cWrite, 1); 263 264 ResetTest(VT_BOOL, L"BOOL1"); 265 hr = SHPropertyBag_WriteBOOL(&dummy, s_pszPropNames[0], TRUE); 266 ok_long(hr, S_OK); 267 ok_int(s_cRead, 0); 268 ok_int(s_cWrite, 1); 269 270 ResetTest(VT_UI2, L"SHORT1"); 271 hr = SHPropertyBag_WriteSHORT(&dummy, s_pszPropNames[0], 1); 272 ok_long(hr, S_OK); 273 ok_int(s_cRead, 0); 274 ok_int(s_cWrite, 1); 275 276 ResetTest(VT_I4, L"LONG1"); 277 hr = SHPropertyBag_WriteLONG(&dummy, s_pszPropNames[0], 1); 278 ok_long(hr, S_OK); 279 ok_int(s_cRead, 0); 280 ok_int(s_cWrite, 1); 281 282 ResetTest(VT_UI4, L"DWORD1"); 283 hr = SHPropertyBag_WriteDWORD(&dummy, s_pszPropNames[0], 1); 284 ok_long(hr, S_OK); 285 ok_int(s_cRead, 0); 286 ok_int(s_cWrite, 1); 287 288 ResetTest(VT_BSTR, L"Str1"); 289 hr = SHPropertyBag_WriteStr(&dummy, s_pszPropNames[0], L"1"); 290 ok_long(hr, S_OK); 291 ok_int(s_cRead, 0); 292 ok_int(s_cWrite, 1); 293 294 ResetTest(VT_I4, L"POINTL1.x", L"POINTL1.y"); 295 POINTL ptl = { 0xEEEE, 0xDDDD }; 296 hr = SHPropertyBag_WritePOINTL(&dummy, L"POINTL1", &ptl); 297 ok_long(hr, S_OK); 298 ok_int(s_cRead, 0); 299 ok_int(s_cWrite, 2); 300 301 ResetTest(VT_I4, L"POINTS1.x", L"POINTS1.y"); 302 POINTS pts = { 0x2222, 0x3333 }; 303 hr = SHPropertyBag_WritePOINTS(&dummy, L"POINTS1", &pts); 304 ok_long(hr, S_OK); 305 ok_int(s_cRead, 0); 306 ok_int(s_cWrite, 2); 307 308 ResetTest(VT_I4, L"RECTL1.left", L"RECTL1.top", L"RECTL1.right", L"RECTL1.bottom"); 309 RECTL rcl = { 123, 456, 789, 101112 }; 310 hr = SHPropertyBag_WriteRECTL(&dummy, L"RECTL1", &rcl); 311 ok_long(hr, S_OK); 312 ok_int(s_cRead, 0); 313 ok_int(s_cWrite, 4); 314 315 ResetTest(VT_I4, L"RECTL2.left", L"RECTL2.top", L"RECTL2.right", L"RECTL2.bottom"); 316 hr = SHPropertyBag_WriteRECTL(&dummy, L"RECTL2", &rcl); 317 ok_long(hr, S_OK); 318 ok_int(s_cRead, 0); 319 ok_int(s_cWrite, 5); 320 321 GUID guid; 322 ZeroMemory(&guid, sizeof(guid)); 323 ResetTest(VT_BSTR, L"GUID1"); 324 hr = SHPropertyBag_WriteGUID(&dummy, L"GUID1", &guid); 325 ok_long(hr, S_OK); 326 ok_int(s_cRead, 0); 327 ok_int(s_cWrite, 1); 328 } 329 330 static void SHPropertyBag_OnMemory(void) 331 { 332 HRESULT hr; 333 VARIANT vari; 334 335 IPropertyBag *pPropBag = NULL; 336 hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_IPropertyBag, (void**)&pPropBag); 337 ok_long(hr, S_OK); 338 if (pPropBag == NULL) 339 { 340 skip("pPropBag was NULL\n"); 341 return; 342 } 343 344 VariantInit(&vari); 345 hr = pPropBag->Read(L"InvalidName", &vari, NULL); 346 ok_long(hr, E_FAIL); 347 VariantClear(&vari); 348 349 VariantInit(&vari); 350 V_VT(&vari) = VT_UI4; 351 V_UI4(&vari) = 0xDEADFACE; 352 hr = pPropBag->Write(L"Name1", &vari); 353 ok_long(hr, S_OK); 354 VariantClear(&vari); 355 356 VariantInit(&vari); 357 hr = pPropBag->Read(L"Name1", &vari, NULL); 358 ok_long(hr, S_OK); 359 ok_long(V_VT(&vari), VT_UI4); 360 ok_long(V_UI4(&vari), 0xDEADFACE); 361 VariantClear(&vari); 362 363 pPropBag->Release(); 364 pPropBag = NULL; 365 366 hr = SHCreatePropertyBagOnMemory(STGM_READ, IID_IPropertyBag, (void**)&pPropBag); 367 ok_long(hr, S_OK); 368 369 VariantInit(&vari); 370 V_VT(&vari) = VT_UI4; 371 V_UI4(&vari) = 0xDEADFACE; 372 hr = pPropBag->Write(L"Name1", &vari); 373 ok_long(hr, (IsWindowsVistaOrGreater() ? S_OK : E_ACCESSDENIED)); 374 VariantClear(&vari); 375 376 VariantInit(&vari); 377 V_VT(&vari) = VT_UI4; 378 V_UI4(&vari) = 0xFEEDF00D; 379 hr = pPropBag->Read(L"Name1", &vari, NULL); 380 if (IsWindowsVistaOrGreater()) 381 { 382 ok_long(hr, S_OK); 383 ok_int(V_VT(&vari), VT_UI4); 384 ok_long(V_UI4(&vari), 0xDEADFACE); 385 } 386 else 387 { 388 ok_long(hr, E_FAIL); 389 ok_int(V_VT(&vari), VT_EMPTY); 390 ok_long(V_UI4(&vari), 0xFEEDF00D); 391 } 392 VariantClear(&vari); 393 394 pPropBag->Release(); 395 pPropBag = NULL; 396 397 hr = SHCreatePropertyBagOnMemory(STGM_WRITE, IID_IPropertyBag, (void**)&pPropBag); 398 ok_long(hr, S_OK); 399 400 VariantInit(&vari); 401 V_VT(&vari) = VT_UI4; 402 V_UI4(&vari) = 0xDEADFACE; 403 hr = pPropBag->Write(L"Name1", &vari); 404 ok_long(hr, S_OK); 405 VariantClear(&vari); 406 407 VariantInit(&vari); 408 V_VT(&vari) = VT_UI4; 409 V_UI4(&vari) = 0xFEEDF00D; 410 hr = pPropBag->Read(L"Name1", &vari, NULL); 411 if (IsWindowsVistaOrGreater()) 412 { 413 ok_long(hr, S_OK); 414 ok_int(V_VT(&vari), VT_UI4); 415 ok_long(V_UI4(&vari), 0xDEADFACE); 416 } 417 else 418 { 419 ok_long(hr, E_ACCESSDENIED); 420 ok_int(V_VT(&vari), VT_EMPTY); 421 ok_long(V_UI4(&vari), 0xFEEDF00D); 422 } 423 VariantClear(&vari); 424 425 pPropBag->Release(); 426 427 hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_IPropertyBag2, (void**)&pPropBag); 428 if (IsWindowsVistaOrGreater()) 429 { 430 ok_long(hr, E_NOINTERFACE); 431 } 432 else 433 { 434 ok_long(hr, S_OK); 435 pPropBag->Release(); 436 } 437 438 hr = SHCreatePropertyBagOnMemory(STGM_READ, IID_IPropertyBag2, (void**)&pPropBag); 439 if (IsWindowsVistaOrGreater()) 440 { 441 ok_long(hr, E_NOINTERFACE); 442 } 443 else 444 { 445 ok_long(hr, S_OK); 446 pPropBag->Release(); 447 } 448 449 hr = SHCreatePropertyBagOnMemory(STGM_WRITE, IID_IPropertyBag2, (void**)&pPropBag); 450 if (IsWindowsVistaOrGreater()) 451 { 452 ok_long(hr, E_NOINTERFACE); 453 } 454 else 455 { 456 ok_long(hr, S_OK); 457 pPropBag->Release(); 458 } 459 } 460 461 static void SHPropertyBag_OnRegKey(void) 462 { 463 HKEY hKey, hSubKey; 464 LONG error; 465 VARIANT vari; 466 WCHAR szText[MAX_PATH]; 467 IStream *pStream; 468 GUID guid; 469 BYTE guid_and_extra[sizeof(GUID) + sizeof(GUID)]; 470 471 // Create HKCU\Software\ReactOS registry key 472 error = RegCreateKeyW(HKEY_CURRENT_USER, L"Software\\ReactOS", &hKey); 473 if (error) 474 { 475 skip("FAILED to create HKCU\\Software\\ReactOS\n"); 476 return; 477 } 478 479 IPropertyBag *pPropBag; 480 HRESULT hr; 481 482 // Try to create new registry key 483 RegDeleteKeyW(hKey, L"PropBagTest"); 484 hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", 0, 485 IID_IPropertyBag, (void **)&pPropBag); 486 ok_long(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); 487 488 // Try to create new registry key 489 RegDeleteKeyW(hKey, L"PropBagTest"); 490 hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", STGM_READWRITE, 491 IID_IPropertyBag, (void **)&pPropBag); 492 ok_long(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); 493 494 // Create new registry key 495 RegDeleteKeyW(hKey, L"PropBagTest"); 496 hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", STGM_CREATE | STGM_READWRITE, 497 IID_IPropertyBag, (void **)&pPropBag); 498 if (FAILED(hr)) 499 { 500 skip("SHCreatePropertyBagOnRegKey FAILED\n"); 501 RegCloseKey(hKey); 502 return; 503 } 504 505 // Write UI4 506 VariantInit(&vari); 507 V_VT(&vari) = VT_UI4; 508 V_UI4(&vari) = 0xDEADFACE; 509 hr = pPropBag->Write(L"Name1", &vari); 510 ok_long(hr, S_OK); 511 VariantClear(&vari); 512 513 // Read UI4 514 VariantInit(&vari); 515 hr = pPropBag->Read(L"Name1", &vari, NULL); 516 ok_long(hr, S_OK); 517 ok_long(V_VT(&vari), VT_UI4); 518 ok_long(V_UI4(&vari), 0xDEADFACE); 519 VariantClear(&vari); 520 521 // Write BSTR 522 VariantInit(&vari); 523 V_VT(&vari) = VT_BSTR; 524 V_BSTR(&vari) = SysAllocString(L"StrValue"); 525 hr = pPropBag->Write(L"Name2", &vari); 526 ok_long(hr, S_OK); 527 VariantClear(&vari); 528 529 // Read BSTR 530 VariantInit(&vari); 531 V_VT(&vari) = VT_BSTR; 532 hr = pPropBag->Read(L"Name2", &vari, NULL); 533 ok_long(hr, S_OK); 534 ok_long(V_VT(&vari), VT_BSTR); 535 ok_wstr(V_BSTR(&vari), L"StrValue"); 536 VariantClear(&vari); 537 538 // Write GUID 539 VariantInit(&vari); 540 V_VT(&vari) = VT_UNKNOWN; 541 V_UNKNOWN(&vari) = SHCreateMemStream((BYTE*)&IID_IShellLinkW, sizeof(IID_IShellLinkW)); 542 hr = pPropBag->Write(L"Name4", &vari); 543 ok_long(hr, S_OK); 544 VariantClear(&vari); 545 546 // Read GUID 547 VariantInit(&vari); 548 V_VT(&vari) = VT_EMPTY; 549 hr = pPropBag->Read(L"Name4", &vari, NULL); 550 if (IsWindowsVistaOrGreater()) 551 { 552 ok_long(hr, S_OK); 553 ok_long(V_VT(&vari), VT_UNKNOWN); 554 pStream = (IStream*)V_UNKNOWN(&vari); 555 FillMemory(&guid, sizeof(guid), 0xEE); 556 hr = pStream->Read(&guid, sizeof(guid), NULL); 557 ok_long(hr, S_OK); 558 ok_int(::IsEqualGUID(guid, IID_IShellLinkW), TRUE); 559 } 560 else // XP/2k3 Read is buggy 561 { 562 ok_long(hr, E_FAIL); 563 ok_long(V_VT(&vari), VT_EMPTY); 564 } 565 VariantClear(&vari); 566 567 pPropBag->Release(); 568 569 // Check registry 570 error = RegOpenKeyExW(hKey, L"PropBagTest", 0, KEY_READ, &hSubKey); 571 ok_long(error, ERROR_SUCCESS); 572 DWORD dwType, dwValue, cbValue = sizeof(dwValue); 573 error = RegQueryValueExW(hSubKey, L"Name1", NULL, &dwType, (BYTE*)&dwValue, &cbValue); 574 ok_long(error, ERROR_SUCCESS); 575 ok_long(dwType, REG_DWORD); 576 ok_long(dwValue, 0xDEADFACE); 577 ok_long(cbValue, sizeof(DWORD)); 578 cbValue = sizeof(szText); 579 error = RegQueryValueExW(hSubKey, L"Name2", NULL, &dwType, (BYTE*)szText, &cbValue); 580 ok_long(error, ERROR_SUCCESS); 581 ok_long(dwType, REG_SZ); 582 ok_wstr(szText, L"StrValue"); 583 cbValue = sizeof(guid_and_extra); 584 error = RegQueryValueExW(hSubKey, L"Name4", NULL, &dwType, (BYTE*)&guid_and_extra, &cbValue); 585 ok_long(error, ERROR_SUCCESS); 586 ok_long(dwType, REG_BINARY); 587 ok_int(memcmp(&guid_and_extra, &GUID_NULL, sizeof(GUID)), 0); 588 ok_int(memcmp(&guid_and_extra[sizeof(GUID)], &IID_IShellLinkW, sizeof(GUID)), 0); 589 RegCloseKey(hSubKey); 590 591 // Create as read-only 592 hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", STGM_READ, 593 IID_IPropertyBag, (void **)&pPropBag); 594 ok_long(hr, S_OK); 595 596 // Read UI4 597 VariantInit(&vari); 598 hr = pPropBag->Read(L"Name1", &vari, NULL); 599 ok_long(hr, S_OK); 600 ok_long(V_VT(&vari), VT_UI4); 601 ok_long(V_UI4(&vari), 0xDEADFACE); 602 VariantClear(&vari); 603 604 // Write UI4 605 VariantInit(&vari); 606 V_VT(&vari) = VT_UI4; 607 V_UI4(&vari) = 0xDEADFACE; 608 hr = pPropBag->Write(L"Name1", &vari); 609 ok_long(hr, E_ACCESSDENIED); 610 VariantClear(&vari); 611 612 pPropBag->Release(); 613 614 // Create as write-only IPropertyBag2 615 hr = SHCreatePropertyBagOnRegKey(hKey, L"PropBagTest", STGM_WRITE, 616 IID_IPropertyBag2, (void **)&pPropBag); 617 ok_long(hr, S_OK); 618 619 // Write UI4 620 VariantInit(&vari); 621 V_VT(&vari) = VT_UI4; 622 V_UI4(&vari) = 0xDEADFACE; 623 hr = pPropBag->Write(L"Name3", &vari); 624 ok_long(hr, E_NOTIMPL); 625 VariantClear(&vari); 626 627 // Read UI4 628 VariantInit(&vari); 629 V_UI4(&vari) = 0xFEEDF00D; 630 hr = pPropBag->Read(L"Name3", &vari, NULL); 631 ok_long(hr, E_NOTIMPL); 632 ok_int(V_VT(&vari), VT_EMPTY); 633 ok_long(V_UI4(&vari), 0xFEEDF00D); 634 VariantClear(&vari); 635 636 pPropBag->Release(); 637 638 // Clean up 639 RegDeleteKeyW(hKey, L"PropBagTest"); 640 RegCloseKey(hKey); 641 } 642 643 static void SHPropertyBag_SHSetIniStringW(void) 644 { 645 WCHAR szIniFile[MAX_PATH]; 646 WCHAR szValue[MAX_PATH]; 647 BOOL bRet; 648 DWORD dwRet; 649 650 ExpandEnvironmentStringsW(L"%TEMP%\\SHSetIniString.ini", szIniFile, _countof(szIniFile)); 651 652 DeleteFileW(szIniFile); 653 654 trace("%ls\n", szIniFile); 655 656 bRet = SHSetIniStringW(L"TestSection", L"Key", L"Value", szIniFile); 657 ok_int(bRet, TRUE); 658 659 WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); 660 661 dwRet = SHGetIniStringW(L"TestSection", L"Key", szValue, _countof(szValue), szIniFile); 662 ok_long(dwRet, 5); 663 ok_wstr(szValue, L"Value"); 664 665 bRet = SHSetIniStringW(L"TestSection", L"Key", NULL, szIniFile); 666 ok_int(bRet, TRUE); 667 668 WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); 669 670 dwRet = SHGetIniStringW(L"TestSection", L"Key", szValue, _countof(szValue), szIniFile); 671 ok_long(dwRet, 0); 672 ok_wstr(szValue, L""); 673 674 bRet = SHSetIniStringW(L"TestSection", L"Key", L"ABC\x3042\x3044\x3046\x2665", szIniFile); 675 ok_int(bRet, TRUE); 676 677 WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); 678 679 dwRet = SHGetIniStringW(L"TestSection", L"Key", szValue, _countof(szValue), szIniFile); 680 ok_long(dwRet, 7); 681 ok_wstr(szValue, L"ABC\x3042\x3044\x3046\x2665"); 682 683 szValue[0] = 0x3000; 684 szValue[1] = UNICODE_NULL; 685 dwRet = SHGetIniStringW(L"TestSection", L"NotExistentKey", szValue, _countof(szValue), szIniFile); 686 ok_long(dwRet, 0); 687 ok_wstr(szValue, L""); 688 689 DeleteFileW(szIniFile); 690 } 691 692 static void SHPropertyBag_OnIniFile(void) 693 { 694 WCHAR szIniFile[MAX_PATH], szValue[MAX_PATH]; 695 HRESULT hr; 696 IPropertyBag *pPropBag; 697 VARIANT vari; 698 DWORD dwRet; 699 700 ExpandEnvironmentStringsW(L"%TEMP%\\SHPropertyBag.ini", szIniFile, _countof(szIniFile)); 701 702 DeleteFileW(szIniFile); 703 fclose(_wfopen(szIniFile, L"w")); 704 705 trace("%ls\n", szIniFile); 706 707 // read-write 708 hr = SHCreatePropertyBagOnProfileSection( 709 szIniFile, 710 L"TestSection", 711 STGM_READWRITE, 712 IID_IPropertyBag, 713 (void**)&pPropBag); 714 ok_long(hr, S_OK); 715 ok_int(PathFileExistsW(szIniFile), TRUE); 716 717 // Write UI4 718 VariantInit(&vari); 719 V_VT(&vari) = VT_UI4; 720 V_UI4(&vari) = 0xDEADFACE; 721 hr = pPropBag->Write(L"Name1", &vari); 722 ok_long(hr, S_OK); 723 VariantClear(&vari); 724 725 // Write BSTR 726 VariantInit(&vari); 727 V_VT(&vari) = VT_BSTR; 728 V_BSTR(&vari) = SysAllocString(L"StrValue"); 729 hr = pPropBag->Write(L"Name2", &vari); 730 ok_long(hr, S_OK); 731 VariantClear(&vari); 732 733 // Write BSTR (dirty UTF-7) 734 VariantInit(&vari); 735 V_VT(&vari) = VT_BSTR; 736 V_BSTR(&vari) = SysAllocString(L"ABC\x3042\x3044\x3046\x2665"); 737 hr = pPropBag->Write(L"@Name3", &vari); 738 ok_long(hr, S_OK); 739 VariantClear(&vari); 740 741 // Write BSTR (clean UTF-7) 742 VariantInit(&vari); 743 V_VT(&vari) = VT_BSTR; 744 V_BSTR(&vari) = SysAllocString(L"1234abc"); 745 hr = pPropBag->Write(L"@Name4", &vari); 746 ok_long(hr, S_OK); 747 VariantClear(&vari); 748 749 pPropBag->Release(); 750 751 // Flush 752 WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); 753 754 // Check INI file 755 dwRet = GetPrivateProfileStringW(L"TestSection", L"Name1", L"BAD", szValue, _countof(szValue), szIniFile); 756 ok_long(dwRet, 10); 757 ok_wstr(szValue, L"3735943886"); 758 759 dwRet = GetPrivateProfileStringW(L"TestSection", L"Name2", L"BAD", szValue, _countof(szValue), szIniFile); 760 ok_long(dwRet, 8); 761 ok_wstr(szValue, L"StrValue"); 762 763 GetPrivateProfileStringW(L"TestSection", L"Name3", L"NotFound", szValue, _countof(szValue), szIniFile); 764 ok_int(memcmp(szValue, L"ABC", 3 * sizeof(WCHAR)), 0); 765 766 GetPrivateProfileStringW(L"TestSection.A", L"Name3", L"NotFound", szValue, _countof(szValue), szIniFile); 767 ok_int(memcmp(szValue, L"ABC", 3 * sizeof(WCHAR)), 0); 768 769 GetPrivateProfileStringW(L"TestSection.W", L"Name3", L"NotFound", szValue, _countof(szValue), szIniFile); 770 ok_wstr(szValue, L"ABC+MEIwRDBGJmU-"); // UTF-7 771 772 GetPrivateProfileStringW(L"TestSection", L"Name4", L"NotFound", szValue, _countof(szValue), szIniFile); 773 ok_wstr(szValue, L"1234abc"); 774 775 GetPrivateProfileStringW(L"TestSection.A", L"Name4", L"NotFound", szValue, _countof(szValue), szIniFile); 776 ok_wstr(szValue, L"NotFound"); 777 778 GetPrivateProfileStringW(L"TestSection.W", L"Name4", L"NotFound", szValue, _countof(szValue), szIniFile); 779 ok_wstr(szValue, L"NotFound"); 780 781 // read-only 782 hr = SHCreatePropertyBagOnProfileSection( 783 szIniFile, 784 NULL, 785 STGM_READ, 786 IID_IPropertyBag, 787 (void**)&pPropBag); 788 ok_long(hr, S_OK); 789 790 // Read UI4 791 VariantInit(&vari); 792 V_VT(&vari) = VT_UI4; 793 hr = pPropBag->Read(L"TestSection\\Name1", &vari, NULL); 794 ok_long(hr, S_OK); 795 ok_long(V_UI4(&vari), 0xDEADFACE); 796 VariantClear(&vari); 797 798 // Read BSTR 799 VariantInit(&vari); 800 V_VT(&vari) = VT_BSTR; 801 hr = pPropBag->Read(L"TestSection\\Name2", &vari, NULL); 802 ok_long(hr, S_OK); 803 ok_wstr(V_BSTR(&vari), L"StrValue"); 804 VariantClear(&vari); 805 806 // Read BSTR (dirty UTF-7) 807 VariantInit(&vari); 808 V_VT(&vari) = VT_BSTR; 809 hr = pPropBag->Read(L"TestSection\\@Name3", &vari, NULL); 810 ok_long(hr, S_OK); 811 ok_wstr(V_BSTR(&vari), L"ABC\x3042\x3044\x3046\x2665"); 812 VariantClear(&vari); 813 814 // Read BSTR (clean UTF-7) 815 VariantInit(&vari); 816 V_VT(&vari) = VT_BSTR; 817 hr = pPropBag->Read(L"TestSection\\@Name4", &vari, NULL); 818 ok_long(hr, S_OK); 819 ok_wstr(V_BSTR(&vari), L"1234abc"); 820 VariantClear(&vari); 821 822 pPropBag->Release(); 823 824 DeleteFileW(szIniFile); 825 } 826 827 static void SHPropertyBag_PerScreenRes(void) 828 { 829 HDC hDC = GetDC(NULL); 830 INT cxWidth = GetDeviceCaps(hDC, HORZRES); 831 INT cyHeight = GetDeviceCaps(hDC, VERTRES); 832 INT cMonitors = GetSystemMetrics(SM_CMONITORS); 833 ReleaseDC(NULL, hDC); 834 835 WCHAR szBuff1[64], szBuff2[64]; 836 StringCchPrintfW(szBuff1, _countof(szBuff1), L"%dx%d(%d)", cxWidth, cyHeight, cMonitors); 837 838 szBuff2[0] = UNICODE_NULL; 839 SHGetPerScreenResName(szBuff2, _countof(szBuff2), 0); 840 ok_wstr(szBuff1, szBuff2); 841 } 842 843 START_TEST(SHPropertyBag) 844 { 845 SHPropertyBag_ReadTest(); 846 SHPropertyBag_WriteTest(); 847 SHPropertyBag_OnMemory(); 848 SHPropertyBag_OnRegKey(); 849 SHPropertyBag_SHSetIniStringW(); 850 SHPropertyBag_OnIniFile(); 851 SHPropertyBag_PerScreenRes(); 852 } 853