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