1 2 // Included first and then again later to ensure that we're able to "light up" new functionality based off new includes 3 #include <wil/resource.h> 4 5 #include <wil/com.h> 6 #include <wil/stl.h> 7 8 // Headers to "light up" functionality in resource.h 9 #include <memory> 10 #include <roapi.h> 11 #include <winstring.h> 12 13 #include <wil/resource.h> 14 #include <wrl/implements.h> 15 16 #include "common.h" 17 18 TEST_CASE("ResourceTests::TestLastErrorContext", "[resource][last_error_context]") 19 { 20 // Destructing the last_error_context restores the error. 21 { 22 SetLastError(42); 23 auto error42 = wil::last_error_context(); 24 SetLastError(0); 25 } 26 REQUIRE(GetLastError() == 42); 27 28 // The context can be moved. 29 { 30 SetLastError(42); 31 auto error42 = wil::last_error_context(); 32 SetLastError(0); 33 { 34 auto another_error42 = wil::last_error_context(std::move(error42)); 35 SetLastError(1); 36 } 37 REQUIRE(GetLastError() == 42); 38 SetLastError(0); 39 // error42 has been moved-from and should not do anything at destruction. 40 } 41 REQUIRE(GetLastError() == 0); 42 43 // The context can be self-assigned, which has no effect. 44 { 45 SetLastError(42); 46 auto error42 = wil::last_error_context(); 47 SetLastError(0); 48 error42 = std::move(error42); 49 SetLastError(1); 50 } 51 REQUIRE(GetLastError() == 42); 52 53 // The context can be dismissed, which cause it to do nothing at destruction. 54 { 55 SetLastError(42); 56 auto error42 = wil::last_error_context(); 57 SetLastError(0); 58 error42.release(); 59 SetLastError(1); 60 } 61 REQUIRE(GetLastError() == 1); 62 } 63 64 TEST_CASE("ResourceTests::TestScopeExit", "[resource][scope_exit]") 65 { 66 int count = 0; __anon7bb6e1070802(int expected) 67 auto validate = [&](int expected) { REQUIRE(count == expected); count = 0; }; 68 69 { __anon7bb6e1070902null70 auto foo = wil::scope_exit([&] { count++; }); 71 } 72 validate(1); 73 74 { __anon7bb6e1070a02null75 auto foo = wil::scope_exit([&] { count++; }); 76 foo.release(); 77 foo.reset(); 78 } 79 validate(0); 80 81 { __anon7bb6e1070b02null82 auto foo = wil::scope_exit([&] { count++; }); 83 foo.reset(); 84 foo.reset(); 85 validate(1); 86 } 87 validate(0); 88 89 #ifdef WIL_ENABLE_EXCEPTIONS 90 { __anon7bb6e1070c02null91 auto foo = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] { count++; THROW_HR(E_FAIL); }); 92 } 93 validate(1); 94 95 { __anon7bb6e1070d02null96 auto foo = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] { count++; THROW_HR(E_FAIL); }); 97 foo.release(); 98 foo.reset(); 99 } 100 validate(0); 101 102 { __anon7bb6e1070e02null103 auto foo = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] { count++; THROW_HR(E_FAIL); }); 104 foo.reset(); 105 foo.reset(); 106 validate(1); 107 } 108 validate(0); 109 #endif // WIL_ENABLE_EXCEPTIONS 110 } 111 112 interface __declspec(uuid("ececcc6a-5193-4d14-b38e-ed1460c20b00")) 113 ITest : public IUnknown 114 { 115 STDMETHOD_(void, Test)() = 0; 116 }; 117 118 class PointerTestObject : witest::AllocatedObject, 119 public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>, ITest> 120 { 121 public: 122 STDMETHOD_(void, Test)() {}; 123 }; 124 125 TEST_CASE("ResourceTests::TestOperationsOnGenericSmartPointerClasses", "[resource]") 126 { 127 #ifdef WIL_ENABLE_EXCEPTIONS 128 { 129 // wil::unique_any_t example 130 wil::unique_event ptr2(wil::EventOptions::ManualReset); 131 // wil::com_ptr 132 wil::com_ptr<PointerTestObject> ptr3 = Microsoft::WRL::Make<PointerTestObject>(); 133 // wil::shared_any_t example 134 wil::shared_event ptr4(wil::EventOptions::ManualReset); 135 // wistd::unique_ptr example 136 auto ptr5 = wil::make_unique_failfast<POINT>(); 137 138 static_assert(wistd::is_same<typename wil::smart_pointer_details<decltype(ptr2)>::pointer, HANDLE>::value, "type-mismatch"); 139 static_assert(wistd::is_same<typename wil::smart_pointer_details<decltype(ptr3)>::pointer, PointerTestObject*>::value, "type-mismatch"); 140 141 auto p2 = wil::detach_from_smart_pointer(ptr2); 142 auto p3 = wil::detach_from_smart_pointer(ptr3); 143 // auto p4 = wil::detach_from_smart_pointer(ptr4); // wil::shared_any_t and std::shared_ptr do not support release(). 144 HANDLE p4{}; 145 auto p5 = wil::detach_from_smart_pointer(ptr5); 146 147 REQUIRE((!ptr2 && !ptr3)); 148 REQUIRE((p2 && p3)); 149 150 wil::attach_to_smart_pointer(ptr2, p2); 151 wil::attach_to_smart_pointer(ptr3, p3); 152 wil::attach_to_smart_pointer(ptr4, p4); 153 wil::attach_to_smart_pointer(ptr5, p5); 154 155 p2 = nullptr; 156 p3 = nullptr; 157 p4 = nullptr; 158 p5 = nullptr; 159 160 wil::detach_to_opt_param(&p2, ptr2); 161 wil::detach_to_opt_param(&p3, ptr3); 162 163 REQUIRE((!ptr2 && !ptr3)); 164 REQUIRE((p2 && p3)); 165 166 wil::attach_to_smart_pointer(ptr2, p2); 167 wil::attach_to_smart_pointer(ptr3, p3); 168 p2 = nullptr; 169 p3 = nullptr; 170 171 wil::detach_to_opt_param(&p2, ptr2); 172 wil::detach_to_opt_param(&p3, ptr3); 173 REQUIRE((!ptr2 && !ptr3)); 174 REQUIRE((p2 && p3)); 175 176 [&](decltype(p2)* ptr) { *ptr = p2; } (wil::out_param(ptr2)); 177 [&](decltype(p3)* ptr) { *ptr = p3; } (wil::out_param(ptr3)); 178 [&](decltype(p4)* ptr) { *ptr = p4; } (wil::out_param(ptr4)); 179 [&](decltype(p5)* ptr) { *ptr = p5; } (wil::out_param(ptr5)); 180 181 REQUIRE((ptr2 && ptr3)); 182 183 // Validate R-Value compilation 184 wil::detach_to_opt_param(&p2, decltype(ptr2){}); 185 wil::detach_to_opt_param(&p3, decltype(ptr3){}); 186 } 187 #endif 188 189 std::unique_ptr<int> ptr1(new int(1)); 190 Microsoft::WRL::ComPtr<PointerTestObject> ptr4 = Microsoft::WRL::Make<PointerTestObject>(); 191 192 static_assert(wistd::is_same<typename wil::smart_pointer_details<decltype(ptr1)>::pointer, int*>::value, "type-mismatch"); 193 static_assert(wistd::is_same<typename wil::smart_pointer_details<decltype(ptr4)>::pointer, PointerTestObject*>::value, "type-mismatch"); 194 195 auto p1 = wil::detach_from_smart_pointer(ptr1); 196 auto p4 = wil::detach_from_smart_pointer(ptr4); 197 198 REQUIRE((!ptr1 && !ptr4)); 199 REQUIRE((p1 && p4)); 200 201 wil::attach_to_smart_pointer(ptr1, p1); 202 wil::attach_to_smart_pointer(ptr4, p4); 203 204 REQUIRE((ptr1 && ptr4)); 205 206 p1 = nullptr; 207 p4 = nullptr; 208 209 int** pNull = nullptr; 210 wil::detach_to_opt_param(pNull, ptr1); 211 REQUIRE(ptr1); 212 213 wil::detach_to_opt_param(&p1, ptr1); 214 wil::detach_to_opt_param(&p4, ptr4); 215 216 REQUIRE((!ptr1 && !ptr4)); 217 REQUIRE((p1 && p4)); 218 219 [&](decltype(p1)* ptr) { *ptr = p1; } (wil::out_param(ptr1)); 220 [&](decltype(p4)* ptr) { *ptr = p4; } (wil::out_param(ptr4)); 221 222 REQUIRE((ptr1 && ptr4)); 223 224 p1 = wil::detach_from_smart_pointer(ptr1); 225 [&](int** ptr) { *ptr = p1; } (wil::out_param_ptr<int **>(ptr1)); 226 REQUIRE(ptr1); 227 } 228 229 // Compilation only test... 230 void StlAdlTest() 231 { 232 // This test has exposed some Argument Dependent Lookup issues in wistd / stl. Primarily we're 233 // just looking for clean compilation. 234 235 std::vector<wistd::unique_ptr<int>> v; 236 v.emplace_back(new int{ 1 }); 237 v.emplace_back(new int{ 2 }); 238 v.emplace_back(new int{ 3 }); 239 std::rotate(begin(v), begin(v) + 1, end(v)); 240 241 REQUIRE(*v[0] == 1); 242 REQUIRE(*v[1] == 3); 243 REQUIRE(*v[2] == 2); 244 245 decltype(v) v2; 246 v2 = std::move(v); 247 REQUIRE(*v2[0] == 1); 248 REQUIRE(*v2[1] == 3); 249 REQUIRE(*v2[2] == 2); 250 251 decltype(v) v3; 252 std::swap(v2, v3); 253 REQUIRE(*v3[0] == 1); 254 REQUIRE(*v3[1] == 3); 255 REQUIRE(*v3[2] == 2); 256 } 257 258 // Compilation only test... 259 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 260 void UniqueProcessInfo() 261 { 262 wil::unique_process_information process; 263 CreateProcessW(nullptr, nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr, nullptr, &process); 264 ResumeThread(process.hThread); 265 WaitForSingleObject(process.hProcess, INFINITE); 266 wil::unique_process_information other(wistd::move(process)); 267 } 268 #endif 269 270 struct FakeComInterface 271 { 272 void AddRef() 273 { 274 refs++; 275 } 276 void Release() 277 { 278 refs--; 279 } 280 281 HRESULT __stdcall Close() 282 { 283 closes++; 284 return S_OK; 285 } 286 287 size_t refs = 0; 288 size_t closes = 0; 289 290 bool called() 291 { 292 auto old = closes; 293 closes = 0; 294 return (old > 0); 295 } 296 297 bool has_ref() 298 { 299 return (refs > 0); 300 } 301 }; 302 303 static void __stdcall CloseFakeComInterface(FakeComInterface* fake) 304 { 305 fake->Close(); 306 } 307 308 using unique_fakeclose_call = wil::unique_com_call<FakeComInterface, decltype(&CloseFakeComInterface), CloseFakeComInterface>; 309 310 TEST_CASE("ResourceTests::VerifyUniqueComCall", "[resource][unique_com_call]") 311 { 312 unique_fakeclose_call call1; 313 unique_fakeclose_call call2; 314 315 // intentional compilation errors 316 // unique_fakeclose_call call3 = call1; 317 // call2 = call1; 318 319 FakeComInterface fake1; 320 unique_fakeclose_call call4(&fake1); 321 REQUIRE(fake1.has_ref()); 322 323 unique_fakeclose_call call5(wistd::move(call4)); 324 REQUIRE(!call4); 325 REQUIRE(call5); 326 REQUIRE(fake1.has_ref()); 327 328 call4 = wistd::move(call5); 329 REQUIRE(call4); 330 REQUIRE(!call5); 331 REQUIRE(fake1.has_ref()); 332 REQUIRE(!fake1.called()); 333 334 FakeComInterface fake2; 335 { 336 unique_fakeclose_call scoped(&fake2); 337 } 338 REQUIRE(!fake2.has_ref()); 339 REQUIRE(fake2.called()); 340 341 call4.reset(&fake2); 342 REQUIRE(fake1.called()); 343 REQUIRE(!fake1.has_ref()); 344 call4.reset(); 345 REQUIRE(!fake2.has_ref()); 346 REQUIRE(fake2.called()); 347 348 call1.reset(&fake1); 349 call2.swap(call1); 350 REQUIRE((call2 && !call1)); 351 352 call2.release(); 353 REQUIRE(!fake1.called()); 354 REQUIRE(!fake1.has_ref()); 355 REQUIRE(!call2); 356 357 REQUIRE(*call1.addressof() == nullptr); 358 359 call1.reset(&fake1); 360 fake2.closes = 0; 361 fake2.refs = 1; 362 *(&call1) = &fake2; 363 REQUIRE(!fake1.has_ref()); 364 REQUIRE(fake1.called()); 365 REQUIRE(fake2.has_ref()); 366 367 call1.reset(&fake1); 368 fake2.closes = 0; 369 fake2.refs = 1; 370 *call1.put() = &fake2; 371 REQUIRE(!fake1.has_ref()); 372 REQUIRE(fake1.called()); 373 REQUIRE(fake2.has_ref()); 374 375 call1.reset(); 376 REQUIRE(!fake2.has_ref()); 377 REQUIRE(fake2.called()); 378 } 379 380 static bool g_called = false; 381 static bool called() 382 { 383 auto call = g_called; 384 g_called = false; 385 return (call); 386 } 387 388 static void __stdcall FakeCall() 389 { 390 g_called = true; 391 } 392 393 using unique_fake_call = wil::unique_call<decltype(&FakeCall), FakeCall>; 394 395 TEST_CASE("ResourceTests::VerifyUniqueCall", "[resource][unique_call]") 396 { 397 unique_fake_call call1; 398 unique_fake_call call2; 399 400 // intentional compilation errors 401 // unique_fake_call call3 = call1; 402 // call2 = call1; 403 404 unique_fake_call call4; 405 REQUIRE(!called()); 406 407 unique_fake_call call5(wistd::move(call4)); 408 REQUIRE(!call4); 409 REQUIRE(call5); 410 411 call4 = wistd::move(call5); 412 REQUIRE(call4); 413 REQUIRE(!call5); 414 REQUIRE(!called()); 415 416 { 417 unique_fake_call scoped; 418 } 419 REQUIRE(called()); 420 421 call4.reset(); 422 REQUIRE(called()); 423 call4.reset(); 424 REQUIRE(!called()); 425 426 call1.release(); 427 REQUIRE((!call1 && call2)); 428 call2.swap(call1); 429 REQUIRE((call1 && !call2)); 430 431 call2.release(); 432 REQUIRE(!called()); 433 REQUIRE(!call2); 434 435 #ifdef __WIL__ROAPI_H_APPEXCEPTIONAL 436 { 437 auto call = wil::RoInitialize(); 438 } 439 #endif 440 #ifdef __WIL__ROAPI_H_APP 441 { 442 wil::unique_rouninitialize_call uninit; 443 uninit.release(); 444 445 auto call = wil::RoInitialize_failfast(); 446 } 447 #endif 448 #ifdef __WIL__COMBASEAPI_H_APPEXCEPTIONAL 449 { 450 auto call = wil::CoInitializeEx(); 451 } 452 #endif 453 #ifdef __WIL__COMBASEAPI_H_APP 454 { 455 wil::unique_couninitialize_call uninit; 456 uninit.release(); 457 458 auto call = wil::CoInitializeEx_failfast(); 459 } 460 #endif 461 } 462 463 void UniqueCallCompilationTest() 464 { 465 #ifdef __WIL__COMBASEAPI_H_EXCEPTIONAL 466 { 467 auto call = wil::CoImpersonateClient(); 468 } 469 #endif 470 #ifdef __WIL__COMBASEAPI_H_ 471 { 472 wil::unique_coreverttoself_call uninit; 473 uninit.release(); 474 475 auto call = wil::CoImpersonateClient_failfast(); 476 } 477 #endif 478 } 479 480 template<typename StringType, typename VerifyContents> 481 static void TestStringMaker(VerifyContents&& verifyContents) 482 { 483 PCWSTR values[] = 484 { 485 L"", 486 L"value", 487 // 300 chars 488 L"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" 489 L"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" 490 L"0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" 491 }; 492 493 for (const auto& value : values) 494 { 495 auto const valueLength = wcslen(value); 496 497 // Direct construction case. 498 wil::details::string_maker<StringType> maker; 499 THROW_IF_FAILED(maker.make(value, valueLength)); 500 auto result = maker.release(); 501 verifyContents(value, valueLength, result); 502 503 // Two phase construction case. 504 THROW_IF_FAILED(maker.make(nullptr, valueLength)); 505 REQUIRE(maker.buffer() != nullptr); 506 // In the case of the wil::unique_hstring and the empty string the buffer is in a read only 507 // section and can't be written to, so StringCchCopy(maker.buffer(), valueLength + 1, value) will fault adding the nul terminator. 508 // Use memcpy_s specifying exact size that will be zero in this case instead. 509 memcpy_s(maker.buffer(), valueLength * sizeof(*value), value, valueLength * sizeof(*value)); 510 result = maker.release(); 511 verifyContents(value, valueLength, result); 512 513 { 514 // no promote, ensure no leaks (not tested here, inspect in the debugger) 515 wil::details::string_maker<StringType> maker2; 516 THROW_IF_FAILED(maker2.make(value, valueLength)); 517 } 518 } 519 } 520 521 #ifdef WIL_ENABLE_EXCEPTIONS 522 template <typename StringType> 523 static void VerifyMakeUniqueString(bool nullValueSupported = true) 524 { 525 if (nullValueSupported) 526 { 527 auto value0 = wil::make_unique_string<StringType>(nullptr, 5); 528 } 529 530 struct 531 { 532 PCWSTR expectedValue; 533 PCWSTR testValue; 534 // this is an optional parameter 535 size_t testLength = static_cast<size_t>(-1); 536 } 537 const testCaseEntries[] = 538 { 539 { L"value", L"value", 5 }, 540 { L"value", L"value" }, 541 { L"va", L"va\0ue", 5 }, 542 { L"v", L"value", 1 }, 543 { L"\0", L"", 5 }, 544 { L"\0", nullptr, 5 }, 545 }; 546 547 using maker = wil::details::string_maker<StringType>; 548 for (auto const &entry : testCaseEntries) 549 { 550 bool shouldSkipNullString = ((wcscmp(entry.expectedValue, L"\0") == 0) && !nullValueSupported); 551 if (!shouldSkipNullString) 552 { 553 auto desiredValue = wil::make_unique_string<StringType>(entry.expectedValue); 554 auto stringValue = wil::make_unique_string<StringType>(entry.testValue, entry.testLength); 555 auto stringValueNoThrow = wil::make_unique_string_nothrow<StringType>(entry.testValue, entry.testLength); 556 auto stringValueFailFast = wil::make_unique_string_failfast<StringType>(entry.testValue, entry.testLength); 557 REQUIRE(wcscmp(maker::get(desiredValue), maker::get(stringValue)) == 0); 558 REQUIRE(wcscmp(maker::get(desiredValue), maker::get(stringValueNoThrow)) == 0); 559 REQUIRE(wcscmp(maker::get(desiredValue), maker::get(stringValueFailFast)) == 0); 560 } 561 } 562 } 563 564 TEST_CASE("UniqueStringAndStringMakerTests::VerifyStringMakerCoTaskMem", "[resource][string_maker]") 565 { 566 VerifyMakeUniqueString<wil::unique_cotaskmem_string>(); 567 TestStringMaker<wil::unique_cotaskmem_string>( 568 [](PCWSTR value, size_t /*valueLength*/, const wil::unique_cotaskmem_string& result) 569 { 570 REQUIRE(wcscmp(value, result.get()) == 0); 571 }); 572 } 573 574 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 575 TEST_CASE("UniqueStringAndStringMakerTests::VerifyStringMakerLocalAlloc", "[resource][string_maker]") 576 { 577 VerifyMakeUniqueString<wil::unique_hlocal_string>(); 578 TestStringMaker<wil::unique_hlocal_string>( 579 [](PCWSTR value, size_t /*valueLength*/, const wil::unique_hlocal_string& result) 580 { 581 REQUIRE(wcscmp(value, result.get()) == 0); 582 }); 583 } 584 585 TEST_CASE("UniqueStringAndStringMakerTests::VerifyStringMakerGlobalAlloc", "[resource][string_maker]") 586 { 587 VerifyMakeUniqueString<wil::unique_hglobal_string>(); 588 TestStringMaker<wil::unique_hglobal_string>( 589 [](PCWSTR value, size_t /*valueLength*/, const wil::unique_hglobal_string& result) 590 { 591 REQUIRE(wcscmp(value, result.get()) == 0); 592 }); 593 } 594 595 TEST_CASE("UniqueStringAndStringMakerTests::VerifyStringMakerProcessHeap", "[resource][string_maker]") 596 { 597 VerifyMakeUniqueString<wil::unique_process_heap_string>(); 598 TestStringMaker<wil::unique_process_heap_string>( 599 [](PCWSTR value, size_t /*valueLength*/, const wil::unique_process_heap_string& result) 600 { 601 REQUIRE(wcscmp(value, result.get()) == 0); 602 }); 603 } 604 #endif 605 606 TEST_CASE("UniqueStringAndStringMakerTests::VerifyStringMakerMidl", "[resource][string_maker]") 607 { 608 VerifyMakeUniqueString<wil::unique_midl_string>(); 609 TestStringMaker<wil::unique_midl_string>( 610 [](PCWSTR value, size_t /*valueLength*/, const wil::unique_midl_string& result) 611 { 612 REQUIRE(wcscmp(value, result.get()) == 0); 613 }); 614 } 615 616 TEST_CASE("UniqueStringAndStringMakerTests::VerifyStringMakerHString", "[resource][string_maker]") 617 { 618 wil::unique_hstring value; 619 value.reset(static_cast<HSTRING>(nullptr)); 620 621 VerifyMakeUniqueString<wil::unique_hstring>(false); 622 623 TestStringMaker<wil::unique_hstring>( 624 [](PCWSTR value, size_t valueLength, const wil::unique_hstring& result) 625 { 626 UINT32 length; 627 REQUIRE(wcscmp(value, WindowsGetStringRawBuffer(result.get(), &length)) == 0); 628 REQUIRE(valueLength == length); 629 }); 630 } 631 632 #ifdef WIL_ENABLE_EXCEPTIONS 633 TEST_CASE("UniqueStringAndStringMakerTests::VerifyStringMakerStdWString", "[resource][string_maker]") 634 { 635 std::string s; 636 wil::details::string_maker<std::wstring> maker; 637 638 TestStringMaker<std::wstring>( 639 [](PCWSTR value, size_t valueLength, const std::wstring& result) 640 { 641 REQUIRE(wcscmp(value, result.c_str()) == 0); 642 REQUIRE(result == value); 643 REQUIRE(result.size() == valueLength); 644 }); 645 } 646 #endif 647 648 TEST_CASE("UniqueStringAndStringMakerTests::VerifyLegacySTringMakers", "[resource][string_maker]") 649 { 650 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 651 auto l = wil::make_hlocal_string(L"value"); 652 l = wil::make_hlocal_string_nothrow(L"value"); 653 l = wil::make_hlocal_string_failfast(L"value"); 654 655 auto p = wil::make_process_heap_string(L"value"); 656 p = wil::make_process_heap_string_nothrow(L"value"); 657 p = wil::make_process_heap_string_failfast(L"value"); 658 #endif 659 auto c = wil::make_cotaskmem_string(L"value"); 660 c = wil::make_cotaskmem_string_nothrow(L"value"); 661 c = wil::make_cotaskmem_string_failfast(L"value"); 662 } 663 #endif 664 665 _Use_decl_annotations_ void* __RPC_USER MIDL_user_allocate(size_t size) 666 { 667 return ::HeapAlloc(GetProcessHeap(), 0, size); 668 } 669 670 _Use_decl_annotations_ void __RPC_USER MIDL_user_free(void* p) 671 { 672 ::HeapFree(GetProcessHeap(), 0, p); 673 } 674 675 TEST_CASE("UniqueMidlStringTests", "[resource][rpc]") 676 { 677 wil::unique_midl_ptr<int[]> intArray{ reinterpret_cast<int*>(::MIDL_user_allocate(sizeof(int) * 10)) }; 678 intArray[2] = 1; 679 680 wil::unique_midl_ptr<int> intSingle{ reinterpret_cast<int*>(::MIDL_user_allocate(sizeof(int) * 1)) }; 681 } 682 683 TEST_CASE("UniqueEnvironmentStrings", "[resource][win32]") 684 { 685 wil::unique_environstrings_ptr env{ ::GetEnvironmentStringsW() }; 686 const wchar_t* nextVar = env.get(); 687 while (nextVar &&* nextVar) 688 { 689 // consume 'nextVar' 690 nextVar += wcslen(nextVar) + 1; 691 } 692 693 wil::unique_environansistrings_ptr envAnsi{ ::GetEnvironmentStringsA() }; 694 const char* nextVarAnsi = envAnsi.get(); 695 while (nextVarAnsi && *nextVarAnsi) 696 { 697 // consume 'nextVar' 698 nextVarAnsi += strlen(nextVarAnsi) + 1; 699 } 700 } 701 702 TEST_CASE("UniqueVariant", "[resource][com]") 703 { 704 wil::unique_variant var; 705 var.vt = VT_BSTR; 706 var.bstrVal = ::SysAllocString(L"25"); 707 REQUIRE(var.bstrVal != nullptr); 708 709 auto call = [](const VARIANT&) {}; 710 call(var); 711 712 VARIANT weakVar = var; 713 (void)weakVar; 714 715 wil::unique_variant var2; 716 REQUIRE_SUCCEEDED(VariantChangeType(&var2, &var, 0, VT_UI4)); 717 REQUIRE(var2.vt == VT_UI4); 718 REQUIRE(var2.uiVal == 25); 719 } 720 721 TEST_CASE("DefaultTemplateParamCompiles", "[resource]") 722 { 723 wil::unique_process_heap_ptr<> a; 724 wil::unique_virtualalloc_ptr<> b; 725 726 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 727 wil::unique_hlocal_ptr<> c; 728 wil::unique_hlocal_secure_ptr<> d; 729 wil::unique_hglobal_ptr<> e; 730 wil::unique_cotaskmem_secure_ptr<> f; 731 #endif 732 733 wil::unique_midl_ptr<> g; 734 wil::unique_cotaskmem_ptr<> h; 735 } 736