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