forked from microsoft/wil
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresource.h
7652 lines (6672 loc) · 279 KB
/
resource.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT.
//
//*********************************************************
//! @file
//! WIL Resource Wrappers (RAII): Provides a family of smart pointer patterns and resource wrappers to enable customers to
//! consistently use RAII in all code.
#include "result_macros.h"
#include "wistd_functional.h"
#include "wistd_memory.h"
#pragma warning(push)
#pragma warning(disable : 26135 26110) // Missing locking annotation, Caller failing to hold lock
#pragma warning(disable : 4714) // __forceinline not honored
#ifndef __WIL_RESOURCE
#define __WIL_RESOURCE
/// @cond
// stdint.h and intsafe.h have conflicting definitions, so it's not safe to include either to pick up our dependencies,
// so the definitions we need are copied below
#ifdef _WIN64
#define __WI_SIZE_MAX 0xffffffffffffffffui64 // UINT64_MAX
#else /* _WIN64 */
#define __WI_SIZE_MAX 0xffffffffui32 // UINT32_MAX
#endif /* _WIN64 */
/// @endcond
// Forward declaration
/// @cond
namespace Microsoft
{
namespace WRL
{
template <typename T>
class ComPtr;
}
} // namespace Microsoft
/// @endcond
namespace wil
{
//! This type copies the current value of GetLastError at construction and resets the last error
//! to that value when it is destroyed.
//!
//! This is useful in library code that runs during a value's destructor. If the library code could
//! inadvertently change the value of GetLastError (by calling a Win32 API or similar), it should
//! instantiate a value of this type before calling the library function in order to preserve the
//! GetLastError value the user would expect.
//!
//! This construct exists to hide kernel mode/user mode differences in wil library code.
//!
//! Example usage:
//!
//! if (!CreateFile(...))
//! {
//! auto lastError = wil::last_error_context();
//! WriteFile(g_hlog, logdata);
//! }
//!
class last_error_context
{
#ifndef WIL_KERNEL_MODE
bool m_dismissed = false;
DWORD m_error = 0;
public:
last_error_context() WI_NOEXCEPT : last_error_context(::GetLastError())
{
}
explicit last_error_context(DWORD error) WI_NOEXCEPT : m_error(error)
{
}
last_error_context(last_error_context&& other) WI_NOEXCEPT
{
operator=(wistd::move(other));
}
last_error_context& operator=(last_error_context&& other) WI_NOEXCEPT
{
m_dismissed = wistd::exchange(other.m_dismissed, true);
m_error = other.m_error;
return *this;
}
~last_error_context() WI_NOEXCEPT
{
if (!m_dismissed)
{
::SetLastError(m_error);
}
}
//! last_error_context doesn't own a concrete resource, so therefore
//! it just disarms its destructor and returns void.
void release() WI_NOEXCEPT
{
WI_ASSERT(!m_dismissed);
m_dismissed = true;
}
WI_NODISCARD auto value() const WI_NOEXCEPT
{
return m_error;
}
#else
public:
void release() WI_NOEXCEPT
{
}
#endif // WIL_KERNEL_MODE
};
/// @cond
namespace details
{
typedef wistd::integral_constant<size_t, 0> pointer_access_all; // get(), release(), addressof(), and '&' are available
typedef wistd::integral_constant<size_t, 1> pointer_access_noaddress; // get() and release() are available
typedef wistd::integral_constant<size_t, 2> pointer_access_none; // the raw pointer is not available
template <bool is_fn_ptr, typename close_fn_t, close_fn_t close_fn, typename pointer_storage_t>
struct close_invoke_helper
{
__forceinline static void close(pointer_storage_t value) WI_NOEXCEPT
{
wistd::invoke(close_fn, value);
}
inline static void close_reset(pointer_storage_t value) WI_NOEXCEPT
{
auto preserveError = last_error_context();
wistd::invoke(close_fn, value);
}
};
template <typename close_fn_t, close_fn_t close_fn, typename pointer_storage_t>
struct close_invoke_helper<true, close_fn_t, close_fn, pointer_storage_t>
{
__forceinline static void close(pointer_storage_t value) WI_NOEXCEPT
{
close_fn(value);
}
inline static void close_reset(pointer_storage_t value) WI_NOEXCEPT
{
auto preserveError = last_error_context();
close_fn(value);
}
};
template <typename close_fn_t, close_fn_t close_fn, typename pointer_storage_t>
using close_invoker =
close_invoke_helper<wistd::is_pointer_v<close_fn_t> ? wistd::is_function_v<wistd::remove_pointer_t<close_fn_t>> : false, close_fn_t, close_fn, pointer_storage_t>;
template <
typename pointer_t, // The handle type
typename close_fn_t, // The handle close function type
close_fn_t close_fn, // * and function pointer
typename pointer_access_t = pointer_access_all, // all, noaddress or none to control pointer method access
typename pointer_storage_t = pointer_t, // The type used to store the handle (usually the same as the handle itself)
typename invalid_t = pointer_t, // The invalid handle value type
invalid_t invalid = invalid_t{}, // * and its value (default ZERO value)
typename pointer_invalid_t = wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
struct resource_policy : close_invoker<close_fn_t, close_fn, pointer_storage_t>
{
typedef pointer_storage_t pointer_storage;
typedef pointer_t pointer;
typedef pointer_invalid_t pointer_invalid;
typedef pointer_access_t pointer_access;
__forceinline static pointer_storage invalid_value()
{
return (pointer)invalid;
}
__forceinline static bool is_valid(pointer_storage value) WI_NOEXCEPT
{
return (static_cast<pointer>(value) != (pointer)invalid);
}
};
// This class provides the pointer storage behind the implementation of unique_any_t utilizing the given
// resource_policy. It is separate from unique_any_t to allow a type-specific specialization class to plug
// into the inheritance chain between unique_any_t and unique_storage. This allows classes like unique_event
// to be a unique_any formed class, but also expose methods like SetEvent directly.
template <typename Policy>
class unique_storage
{
protected:
typedef Policy policy;
typedef typename policy::pointer_storage pointer_storage;
typedef typename policy::pointer pointer;
typedef unique_storage<policy> base_storage;
public:
unique_storage() WI_NOEXCEPT : m_ptr(policy::invalid_value())
{
}
explicit unique_storage(pointer_storage ptr) WI_NOEXCEPT : m_ptr(ptr)
{
}
unique_storage(unique_storage&& other) WI_NOEXCEPT : m_ptr(wistd::move(other.m_ptr))
{
other.m_ptr = policy::invalid_value();
}
~unique_storage() WI_NOEXCEPT
{
if (policy::is_valid(m_ptr))
{
policy::close(m_ptr);
}
}
WI_NODISCARD bool is_valid() const WI_NOEXCEPT
{
return policy::is_valid(m_ptr);
}
void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT
{
if (policy::is_valid(m_ptr))
{
policy::close_reset(m_ptr);
}
m_ptr = ptr;
}
void reset(wistd::nullptr_t) WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename policy::pointer_invalid, wistd::nullptr_t>::value,
"reset(nullptr): valid only for handle types using nullptr as the invalid value");
reset();
}
WI_NODISCARD pointer get() const WI_NOEXCEPT
{
return static_cast<pointer>(m_ptr);
}
pointer_storage release() WI_NOEXCEPT
{
static_assert(
!wistd::is_same<typename policy::pointer_access, pointer_access_none>::value,
"release(): the raw handle value is not available for this resource class");
auto ptr = m_ptr;
m_ptr = policy::invalid_value();
return ptr;
}
pointer_storage* addressof() WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename policy::pointer_access, pointer_access_all>::value,
"addressof(): the address of the raw handle is not available for this resource class");
return &m_ptr;
}
protected:
void replace(unique_storage&& other) WI_NOEXCEPT
{
reset(other.m_ptr);
other.m_ptr = policy::invalid_value();
}
private:
pointer_storage m_ptr;
};
// Determines if it is safe to deallocate a resource without destructing the object
template <typename T>
struct needs_destruction
{
template <typename U>
static auto invoke(int) -> wistd::bool_constant<sizeof(U) >= 0>; // Always true, but SFINAE's if incomplete type
template <typename U>
static auto invoke(float) -> wistd::false_type;
// A type needs destruction if:
// 1. It is a complete type,
// 2. It can be destructed, and
// 3. It's not trivially destructible
// Note that we need the "complete type" check because some places use an undefined struct as a type-safe
// resource type (e.g. 'typedef struct tagSERIALIZEDPROPSTORAGE SERIALIZEDPROPSTORAGE')
static constexpr const bool value = wistd::conjunction_v<
decltype(invoke<wistd::remove_extent_t<T>>(0)),
wistd::is_destructible<wistd::remove_extent_t<T>>,
wistd::negation<wistd::is_trivially_destructible<wistd::remove_extent_t<T>>>>;
};
template <typename T>
constexpr bool needs_destruction_v = needs_destruction<T>::value;
// A pass-through type that statically asserts that the specified type does not need destruction. Useful when
// specifying template arguments for various unique_* types where the destructor won't run
template <typename T>
struct ensure_trivially_destructible
{
// NOTE: Temporary opt-out for existing code that uses these types incorrectly
#ifndef WIL_DISABLE_UNIQUE_PTR_DESTRUCTOR_CHECKS
// If this static_assert fires, it means you've used a type that is not trivially destructible as a template
// argument to a wil::unique* type that will not invoke that object's destructor
static_assert(!needs_destruction_v<T>, "Resource type has a non-trivial destructor, but is used in a context where its destructor will not be run");
#endif
using type = T;
};
template <typename T>
using ensure_trivially_destructible_t = typename ensure_trivially_destructible<T>::type;
} // namespace details
/// @endcond
// This class when paired with unique_storage and an optional type-specific specialization class implements
// the same interface as STL's unique_ptr<> for resource handle types. It is a non-copyable, yet movable class
// supporting attach (reset), detach (release), retrieval (get()).
template <typename storage_t>
class unique_any_t : public storage_t
{
public:
typedef typename storage_t::policy policy;
typedef typename policy::pointer_storage pointer_storage;
typedef typename policy::pointer pointer;
unique_any_t(unique_any_t const&) = delete;
unique_any_t& operator=(unique_any_t const&) = delete;
// Note that the default constructor really shouldn't be needed (taken care of by the forwarding constructor below), but
// the forwarding constructor causes an internal compiler error when the class is used in a C++ array. Defining the default
// constructor independent of the forwarding constructor removes the compiler limitation.
unique_any_t() = default;
// forwarding constructor: forwards all 'explicit' and multi-arg constructors to the base class
template <typename arg1, typename... args_t>
explicit unique_any_t(arg1&& first, args_t&&... args)
__WI_NOEXCEPT_((wistd::is_nothrow_constructible_v<storage_t, arg1, args_t...>)) :
storage_t(wistd::forward<arg1>(first), wistd::forward<args_t>(args)...)
{
static_assert(
wistd::is_same<typename policy::pointer_access, details::pointer_access_none>::value ||
wistd::is_same<typename policy::pointer_access, details::pointer_access_all>::value ||
wistd::is_same<typename policy::pointer_access, details::pointer_access_noaddress>::value,
"pointer_access policy must be a known pointer_access* integral type");
}
unique_any_t(wistd::nullptr_t) WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename policy::pointer_invalid, wistd::nullptr_t>::value,
"nullptr constructor: valid only for handle types using nullptr as the invalid value");
}
unique_any_t(unique_any_t&& other) WI_NOEXCEPT : storage_t(wistd::move(other))
{
}
unique_any_t& operator=(unique_any_t&& other) WI_NOEXCEPT
{
if (this != wistd::addressof(other))
{
// cast to base_storage to 'skip' calling the (optional) specialization class that provides handle-specific functionality
storage_t::replace(wistd::move(static_cast<typename storage_t::base_storage&>(other)));
}
return (*this);
}
unique_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename policy::pointer_invalid, wistd::nullptr_t>::value,
"nullptr assignment: valid only for handle types using nullptr as the invalid value");
storage_t::reset();
return (*this);
}
void swap(unique_any_t& other) WI_NOEXCEPT
{
unique_any_t self(wistd::move(*this));
operator=(wistd::move(other));
other = wistd::move(self);
}
WI_NODISCARD explicit operator bool() const WI_NOEXCEPT
{
return storage_t::is_valid();
}
//!
//! ~~~
//! BOOL OpenOrCreateWaffle(PCWSTR name, HWAFFLE* handle);
//! wil::unique_any<HWAFFLE, decltype(&::CloseWaffle), ::CloseWaffle> waffle;
//! RETURN_IF_WIN32_BOOL_FALSE(OpenOrCreateWaffle(L"tasty.yum", waffle.put()));
//! ~~~
pointer_storage* put() WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename policy::pointer_access, details::pointer_access_all>::value,
"operator & is not available for this handle");
storage_t::reset();
return storage_t::addressof();
}
pointer_storage* operator&() WI_NOEXCEPT
{
return put();
}
WI_NODISCARD pointer get() const WI_NOEXCEPT
{
static_assert(
!wistd::is_same<typename policy::pointer_access, details::pointer_access_none>::value,
"get(): the raw handle value is not available for this resource class");
return storage_t::get();
}
// The following functions are publicly exposed by their inclusion in the unique_storage base class
// explicit unique_any_t(pointer_storage ptr) WI_NOEXCEPT
// void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT
// void reset(wistd::nullptr_t) WI_NOEXCEPT
// pointer_storage release() WI_NOEXCEPT // not exposed for some resource types
// pointer_storage *addressof() WI_NOEXCEPT // not exposed for some resource types
};
template <typename policy>
void swap(unique_any_t<policy>& left, unique_any_t<policy>& right) WI_NOEXCEPT
{
left.swap(right);
}
template <typename policy>
bool operator==(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
{
return (left.get() == right.get());
}
template <typename policy>
bool operator==(const unique_any_t<policy>& left, wistd::nullptr_t) WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename unique_any_t<policy>::policy::pointer_invalid, wistd::nullptr_t>::value,
"the resource class does not use nullptr as an invalid value");
return !left;
}
template <typename policy>
bool operator==(wistd::nullptr_t, const unique_any_t<policy>& right) WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename unique_any_t<policy>::policy::pointer_invalid, wistd::nullptr_t>::value,
"the resource class does not use nullptr as an invalid value");
return !right;
}
template <typename policy>
bool operator!=(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
{
return (!(left.get() == right.get()));
}
template <typename policy>
bool operator!=(const unique_any_t<policy>& left, wistd::nullptr_t) WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename unique_any_t<policy>::policy::pointer_invalid, wistd::nullptr_t>::value,
"the resource class does not use nullptr as an invalid value");
return !!left;
}
template <typename policy>
bool operator!=(wistd::nullptr_t, const unique_any_t<policy>& right) WI_NOEXCEPT
{
static_assert(
wistd::is_same<typename unique_any_t<policy>::policy::pointer_invalid, wistd::nullptr_t>::value,
"the resource class does not use nullptr as an invalid value");
return !!right;
}
template <typename policy>
bool operator<(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
{
return (left.get() < right.get());
}
template <typename policy>
bool operator>=(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
{
return (!(left < right));
}
template <typename policy>
bool operator>(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
{
return (right < left);
}
template <typename policy>
bool operator<=(const unique_any_t<policy>& left, const unique_any_t<policy>& right) WI_NOEXCEPT
{
return (!(right < left));
}
// unique_any provides a template alias for easily building a unique_any_t from a unique_storage class with the given
// template parameters for resource_policy.
template <
typename pointer, // The handle type
typename close_fn_t, // The handle close function type
close_fn_t close_fn, // * and function pointer
typename pointer_access = details::pointer_access_all, // all, noaddress or none to control pointer method access
typename pointer_storage = pointer, // The type used to store the handle (usually the same as the handle itself)
typename invalid_t = pointer, // The invalid handle value type
invalid_t invalid = invalid_t{}, // * and its value (default ZERO value)
typename pointer_invalid = wistd::nullptr_t> // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer
using unique_any =
unique_any_t<details::unique_storage<details::resource_policy<pointer, close_fn_t, close_fn, pointer_access, pointer_storage, invalid_t, invalid, pointer_invalid>>>;
/// @cond
namespace details
{
template <typename TLambda>
class lambda_call
{
public:
lambda_call(const lambda_call&) = delete;
lambda_call& operator=(const lambda_call&) = delete;
lambda_call& operator=(lambda_call&& other) = delete;
explicit lambda_call(TLambda&& lambda) WI_NOEXCEPT : m_lambda(wistd::move(lambda))
{
static_assert(wistd::is_same<decltype(lambda()), void>::value, "scope_exit lambdas must not have a return value");
static_assert(
!wistd::is_lvalue_reference<TLambda>::value && !wistd::is_rvalue_reference<TLambda>::value,
"scope_exit should only be directly used with a lambda");
}
lambda_call(lambda_call&& other) WI_NOEXCEPT : m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call)
{
other.m_call = false;
}
~lambda_call() WI_NOEXCEPT
{
reset();
}
// Ensures the scope_exit lambda will not be called
void release() WI_NOEXCEPT
{
m_call = false;
}
// Executes the scope_exit lambda immediately if not yet run; ensures it will not run again
void reset() WI_NOEXCEPT
{
if (m_call)
{
m_call = false;
m_lambda();
}
}
// Returns true if the scope_exit lambda is still going to be executed
WI_NODISCARD explicit operator bool() const WI_NOEXCEPT
{
return m_call;
}
protected:
TLambda m_lambda;
bool m_call = true;
};
#ifdef WIL_ENABLE_EXCEPTIONS
template <typename TLambda>
class lambda_call_log
{
public:
lambda_call_log(const lambda_call_log&) = delete;
lambda_call_log& operator=(const lambda_call_log&) = delete;
lambda_call_log& operator=(lambda_call_log&& other) = delete;
explicit lambda_call_log(void* address, const DiagnosticsInfo& info, TLambda&& lambda) WI_NOEXCEPT
: m_address(address),
m_info(info),
m_lambda(wistd::move(lambda))
{
static_assert(wistd::is_same<decltype(lambda()), void>::value, "scope_exit lambdas must return 'void'");
static_assert(
!wistd::is_lvalue_reference<TLambda>::value && !wistd::is_rvalue_reference<TLambda>::value,
"scope_exit should only be directly used with a lambda");
}
lambda_call_log(lambda_call_log&& other) WI_NOEXCEPT : m_address(other.m_address),
m_info(other.m_info),
m_lambda(wistd::move(other.m_lambda)),
m_call(other.m_call)
{
other.m_call = false;
}
~lambda_call_log() WI_NOEXCEPT
{
reset();
}
// Ensures the scope_exit lambda will not be called
void release() WI_NOEXCEPT
{
m_call = false;
}
// Executes the scope_exit lambda immediately if not yet run; ensures it will not run again
void reset() WI_NOEXCEPT
{
if (m_call)
{
m_call = false;
try
{
m_lambda();
}
catch (...)
{
ReportFailure_CaughtException<FailureType::Log>(__R_DIAGNOSTICS(m_info), m_address);
}
}
}
// Returns true if the scope_exit lambda is still going to be executed
WI_NODISCARD explicit operator bool() const WI_NOEXCEPT
{
return m_call;
}
private:
void* m_address;
DiagnosticsInfo m_info;
TLambda m_lambda;
bool m_call = true;
};
#endif // WIL_ENABLE_EXCEPTIONS
} // namespace details
/// @endcond
/** Returns an object that executes the given lambda when destroyed.
Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid
execution. Exceptions thrown in the lambda will fail-fast; use scope_exit_log to avoid. */
template <typename TLambda>
WI_NODISCARD inline auto scope_exit(TLambda&& lambda) WI_NOEXCEPT
{
return details::lambda_call<TLambda>(wistd::forward<TLambda>(lambda));
}
#ifdef WIL_ENABLE_EXCEPTIONS
/** Returns an object that executes the given lambda when destroyed; logs exceptions.
Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid
execution. Exceptions thrown in the lambda will be caught and logged without being propagated. */
template <typename TLambda>
WI_NODISCARD inline __declspec(noinline) auto scope_exit_log(const DiagnosticsInfo& diagnostics, TLambda&& lambda) WI_NOEXCEPT
{
return details::lambda_call_log<TLambda>(_ReturnAddress(), diagnostics, wistd::forward<TLambda>(lambda));
}
#endif
// Forward declaration...
template <typename T, typename err_policy>
class com_ptr_t;
//! Type traits class that identifies the inner type of any smart pointer.
template <typename Ptr>
struct smart_pointer_details
{
typedef typename Ptr::pointer pointer;
};
/// @cond
template <typename T>
struct smart_pointer_details<Microsoft::WRL::ComPtr<T>>
{
typedef T* pointer;
};
/// @endcond
/** Generically detaches a raw pointer from any smart pointer.
Caller takes ownership of the returned raw pointer; calls the correct release(), detach(),
or Detach() method based on the smart pointer type */
template <typename TSmartPointer>
WI_NODISCARD typename TSmartPointer::pointer detach_from_smart_pointer(TSmartPointer& smartPtr)
{
return smartPtr.release();
}
/// @cond
// Generically detaches a raw pointer from any smart pointer
template <typename T, typename err>
WI_NODISCARD T* detach_from_smart_pointer(wil::com_ptr_t<T, err>& smartPtr)
{
return smartPtr.detach();
}
// Generically detaches a raw pointer from any smart pointer
template <typename T>
WI_NODISCARD T* detach_from_smart_pointer(Microsoft::WRL::ComPtr<T>& smartPtr)
{
return smartPtr.Detach();
}
template <typename T, typename err>
class com_ptr_t; // forward
namespace details
{
// The first two attach_to_smart_pointer() overloads are ambiguous when passed a com_ptr_t.
// To solve that use this functions return type to eliminate the reset form for com_ptr_t.
template <typename T, typename err>
wistd::false_type use_reset(wil::com_ptr_t<T, err>*)
{
return wistd::false_type();
}
template <typename T>
wistd::true_type use_reset(T*)
{
return wistd::true_type();
}
} // namespace details
/// @endcond
/** Generically attach a raw pointer to a compatible smart pointer.
Calls the correct reset(), attach(), or Attach() method based on samrt pointer type. */
template <typename TSmartPointer, typename EnableResetForm = wistd::enable_if_t<decltype(details::use_reset(static_cast<TSmartPointer*>(nullptr)))::value>>
void attach_to_smart_pointer(TSmartPointer& smartPtr, typename TSmartPointer::pointer rawPtr)
{
smartPtr.reset(rawPtr);
}
/// @cond
// Generically attach a raw pointer to a compatible smart pointer.
template <typename T, typename err>
void attach_to_smart_pointer(wil::com_ptr_t<T, err>& smartPtr, T* rawPtr)
{
smartPtr.attach(rawPtr);
}
// Generically attach a raw pointer to a compatible smart pointer.
template <typename T>
void attach_to_smart_pointer(Microsoft::WRL::ComPtr<T>& smartPtr, T* rawPtr)
{
smartPtr.Attach(rawPtr);
}
/// @endcond
//! @ingroup outparam
/** Detach a smart pointer resource to an optional output pointer parameter.
Avoids cluttering code with nullptr tests; works generically for any smart pointer */
template <typename T, typename TSmartPointer>
inline void detach_to_opt_param(_Out_opt_ T* outParam, TSmartPointer&& smartPtr)
{
if (outParam)
{
*outParam = detach_from_smart_pointer(smartPtr);
}
}
/// @cond
namespace details
{
template <typename T>
struct out_param_t
{
typedef typename wil::smart_pointer_details<T>::pointer pointer;
T& wrapper;
pointer pRaw;
bool replace = true;
out_param_t(_Inout_ T& output) : wrapper(output), pRaw(nullptr)
{
}
out_param_t(out_param_t&& other) WI_NOEXCEPT : wrapper(other.wrapper), pRaw(other.pRaw)
{
WI_ASSERT(other.replace);
other.replace = false;
}
operator pointer*()
{
WI_ASSERT(replace);
return &pRaw;
}
~out_param_t()
{
if (replace)
{
attach_to_smart_pointer(wrapper, pRaw);
}
}
out_param_t(out_param_t const& other) = delete;
out_param_t& operator=(out_param_t const& other) = delete;
};
template <typename Tcast, typename T>
struct out_param_ptr_t
{
typedef typename wil::smart_pointer_details<T>::pointer pointer;
T& wrapper;
pointer pRaw;
bool replace = true;
out_param_ptr_t(_Inout_ T& output) : wrapper(output), pRaw(nullptr)
{
}
out_param_ptr_t(out_param_ptr_t&& other) WI_NOEXCEPT : wrapper(other.wrapper), pRaw(other.pRaw)
{
WI_ASSERT(other.replace);
other.replace = false;
}
operator Tcast()
{
WI_ASSERT(replace);
return reinterpret_cast<Tcast>(&pRaw);
}
~out_param_ptr_t()
{
if (replace)
{
attach_to_smart_pointer(wrapper, pRaw);
}
}
out_param_ptr_t(out_param_ptr_t const& other) = delete;
out_param_ptr_t& operator=(out_param_ptr_t const& other) = delete;
};
} // namespace details
/// @endcond
/** Use to retrieve raw out parameter pointers into smart pointers that do not support the '&' operator.
This avoids multi-step handling of a raw resource to establish the smart pointer.
Example: `GetFoo(out_param(foo));` */
template <typename T>
details::out_param_t<T> out_param(T& p)
{
return details::out_param_t<T>(p);
}
/** Use to retrieve raw out parameter pointers (with a required cast) into smart pointers that do not support the '&' operator.
Use only when the smart pointer's &handle is not equal to the output type a function requires, necessitating a cast.
Example: `wil::out_param_ptr<PSECURITY_DESCRIPTOR*>(securityDescriptor)` */
template <typename Tcast, typename T>
details::out_param_ptr_t<Tcast, T> out_param_ptr(T& p)
{
return details::out_param_ptr_t<Tcast, T>(p);
}
/** Use unique_struct to define an RAII type for a trivial struct that references resources that must be cleaned up.
Unique_struct wraps a trivial struct using a custom clean up function and, optionally, custom initializer function. If no custom
initialier function is defined in the template then ZeroMemory is used.
Unique_struct is modeled off of std::unique_ptr. However, unique_struct inherits from the defined type instead of managing the
struct through a private member variable.
If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Submit pull
requests to [GitHub](https://github.com/microsoft/wil/). Otherwise, if the type is local to your project, declare it locally.
@tparam struct_t The struct you want to manage
@tparam close_fn_t The type of the function to clean up the struct. Takes one parameter: a pointer of struct_t. Return values are
ignored.
@tparam close_fn The function of type close_fn_t. This is called in the destructor and reset functions.
@tparam init_fn_t Optional:The type of the function to initialize the struct. Takes one parameter: a pointer of struct_t. Return
values are ignored.
@tparam init_fn Optional:The function of type init_fn_t. This is called in the constructor, reset, and release functions. The
default is ZeroMemory to initialize the struct.
Defined using the default zero memory initializer
~~~
typedef wil::unique_struct<PROPVARIANT, decltype(&::PropVariantClear), ::PropVariantClear> unique_prop_variant_default_init;
unique_prop_variant_default_init propvariant;
SomeFunction(&propvariant);
~~~
Defined using a custom initializer
~~~
typedef wil::unique_struct<PROPVARIANT, decltype(&::PropVariantClear), ::PropVariantClear, decltype(&::PropVariantInit),
::PropVariantInit> unique_prop_variant;
unique_prop_variant propvariant;
SomeFunction(&propvariant);
~~~
*/
template <typename struct_t, typename close_fn_t, close_fn_t close_fn, typename init_fn_t = wistd::nullptr_t, init_fn_t init_fn = wistd::nullptr_t()>
class unique_struct : public struct_t
{
using closer = details::close_invoker<close_fn_t, close_fn, struct_t*>;
public:
//! Initializes the managed struct using the user-provided initialization function, or ZeroMemory if no function is specified
unique_struct()
{
call_init(use_default_init_fn());
}
//! Takes ownership of the struct by doing a shallow copy. Must explicitly be type struct_t
explicit unique_struct(const struct_t& other) WI_NOEXCEPT : struct_t(other)
{
}
//! Initializes the managed struct by taking the ownership of the other managed struct
//! Then resets the other managed struct by calling the custom close function
unique_struct(unique_struct&& other) WI_NOEXCEPT : struct_t(other.release())
{
}
//! Resets this managed struct by calling the custom close function and takes ownership of the other managed struct
//! Then resets the other managed struct by calling the custom close function
unique_struct& operator=(unique_struct&& other) WI_NOEXCEPT
{
if (this != wistd::addressof(other))
{
reset(other.release());
}
return *this;
}
//! Calls the custom close function
~unique_struct() WI_NOEXCEPT
{
closer::close(this);
}
void reset(const unique_struct&) = delete;
//! Resets this managed struct by calling the custom close function and begins management of the other struct
void reset(const struct_t& other) WI_NOEXCEPT
{
closer::close_reset(this);
struct_t::operator=(other);
}
//! Resets this managed struct by calling the custom close function
//! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is
//! specified
void reset() WI_NOEXCEPT
{
closer::close(this);
call_init(use_default_init_fn());
}
void swap(struct_t&) = delete;
//! Swaps the managed structs
void swap(unique_struct& other) WI_NOEXCEPT
{
struct_t self(*this);
struct_t::operator=(other);
*(other.addressof()) = self;
}
//! Returns the managed struct
//! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is
//! specified
struct_t release() WI_NOEXCEPT
{
struct_t value(*this);
call_init(use_default_init_fn());
return value;
}
//! Returns address of the managed struct
struct_t* addressof() WI_NOEXCEPT
{
return this;
}
//! Resets this managed struct by calling the custom close function
//! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is
//! specified.
//! Returns address of the managed struct
struct_t* reset_and_addressof() WI_NOEXCEPT
{
reset();
return this;
}
unique_struct(const unique_struct&) = delete;
unique_struct& operator=(const unique_struct&) = delete;
unique_struct& operator=(const struct_t&) = delete;