1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | |
6 | #ifndef __HOLDER_H_ |
7 | #define __HOLDER_H_ |
8 | |
9 | #include <wincrypt.h> |
10 | #include "cor.h" |
11 | #include "genericstackprobe.h" |
12 | #include "staticcontract.h" |
13 | #include "volatile.h" |
14 | #include "palclr.h" |
15 | |
16 | #ifdef PAL_STDCPP_COMPAT |
17 | #include <utility> |
18 | #include <type_traits> |
19 | #else |
20 | #include "clr_std/utility" |
21 | #include "clr_std/type_traits" |
22 | #endif |
23 | |
24 | #if defined(FEATURE_COMINTEROP) && !defined(STRIKE) |
25 | #include <Activation.h> |
26 | #include <Inspectable.h> |
27 | #endif |
28 | |
29 | // Note: you can't use CONTRACT's in this file. You can't use dynamic contracts because the impl of dynamic |
30 | // contracts depends on holders. You can't use static contracts because they include the function name as a string, |
31 | // and the template names in this file are just too long, so you get a compiler error. |
32 | // |
33 | // All the functions in this file are pretty basic, so the lack of CONTRACT's isn't a big loss. |
34 | |
35 | #ifdef _MSC_VER |
36 | // Make sure we can recurse deep enough for FORCEINLINE |
37 | #pragma inline_recursion(on) |
38 | #pragma inline_depth(16) |
39 | #pragma warning(disable:4714) |
40 | #endif // _MSC_VER |
41 | |
42 | //------------------------------------------------------------------------------------------------ |
43 | // Declare but do not define methods that would normally be automatically generated by the |
44 | // compiler. This will produce a link-time error if they are used. This is involved in object |
45 | // initialization and operator eliding; see |
46 | // http://groups.google.com/group/comp.lang.c++/msg/3cd673ab749bed83?dmode=source |
47 | // for the intricate details. |
48 | |
49 | #ifdef __GNUC__ |
50 | // GCC checks accessibility of the copy ctor before performing elision optimization, so |
51 | // it must be declared as public. VC does not, so we can declare it private to give an |
52 | // earlier error message. |
53 | #define HIDE_GENERATED_METHODS(_NAME) \ |
54 | public: \ |
55 | _NAME(_NAME const &); \ |
56 | private: \ |
57 | _NAME & operator=(_NAME const &); |
58 | #else |
59 | #define HIDE_GENERATED_METHODS(_NAME) \ |
60 | private: \ |
61 | _NAME(_NAME const &); \ |
62 | _NAME & operator=(_NAME const &); |
63 | #endif |
64 | |
65 | |
66 | #ifdef _DEBUG |
67 | |
68 | |
69 | //------------------------------------------------------------------------------------------------ |
70 | // This is used to make Visual Studio autoexp.dat work sensibly with holders again. |
71 | // The problem is that certain codebases (particulary Fusion) implement key data structures |
72 | // using a class but refer to it using a holder to an interface type. This combination prevents |
73 | // autoexp rules from working as desired. |
74 | // |
75 | // Example: Take this useful autoexp rule for CAssemblyName. |
76 | // |
77 | // CAssemblyName=<_rProp._rProp[3].asStr> |
78 | // |
79 | // To get the same rule to fire when your assemblyname is wrapped in a ReleaseHolder, |
80 | // add these companion rules. |
81 | // |
82 | // HolderBase<CAssemblyName *>=<m_value->_rProp._rProp[3].asStr> |
83 | // HolderBase<IAssemblyName *>=<m_pAutoExpVisibleValue->_asCAssemblyName->_rProp._rProp[3].asStr> |
84 | // |
85 | //------------------------------------------------------------------------------------------------ |
86 | struct AutoExpVisibleValue |
87 | { |
88 | private: |
89 | union |
90 | { |
91 | // Only include a class name here if it is customarily referred to through an abstract interface. |
92 | |
93 | #if defined(FEATURE_APPX) |
94 | const class AppXBindResultImpl *_asAppXBindResultImpl; |
95 | #endif |
96 | |
97 | const void *_pPreventEmptyUnion; |
98 | }; |
99 | }; |
100 | #endif //_DEBUG |
101 | |
102 | //----------------------------------------------------------------------------- |
103 | // Holder is the base class of all holder objects. Any backout object should derive from it. |
104 | // (Eventually some additional bookeeping and exception handling code will be placed in this |
105 | // base class.) |
106 | // |
107 | // There are several ways to use this class: |
108 | // 1. Derive from HolderBase, and instantiate a Holder or Wrapper around your base. This is necessary |
109 | // if you need to add more state to your holder. |
110 | // 2. Instantiate the Holder template with your type and functions. |
111 | // 3. Instantiate the Wrapper template with your type and functions. The Wrapper adds some additional |
112 | // operator overloads to provide "smart pointer" like behavior |
113 | // 4. Use a prebaked Holder. This is ALWAYS the preferable strategy. It is expected that |
114 | // the general design patter is that Holders will be provided as part of a typical data abstraction. |
115 | // (See Crst for an example of this.) |
116 | //----------------------------------------------------------------------------- |
117 | |
118 | |
119 | |
120 | //----------------------------------------------------------------------------- |
121 | // HolderBase defines the base holder functionality. You can subtype and plug in |
122 | // a different base if you need to add more members for access during |
123 | // acquire & release |
124 | //----------------------------------------------------------------------------- |
125 | template <typename TYPE> |
126 | class HolderBase |
127 | { |
128 | protected: |
129 | TYPE m_value; |
130 | |
131 | HolderBase(TYPE value) |
132 | : m_value(value) |
133 | { |
134 | // TODO: Find a way to enable this check. |
135 | // We can have a holder in SO tolerant, then probe, then acquire a value. This works |
136 | // because the dtor is guaranteed to run with enough stack. |
137 | // EnsureSOIntolerantOK(__FUNCTION__, __FILE__, __LINE__); |
138 | |
139 | #ifdef _DEBUG |
140 | m_pAutoExpVisibleValue = (const AutoExpVisibleValue *)(&m_value); |
141 | #endif //_DEBUG |
142 | } |
143 | |
144 | void DoAcquire() |
145 | { |
146 | // Insert any global or thread bookeeping here |
147 | } |
148 | |
149 | void DoRelease() |
150 | { |
151 | // Insert any global or thread bookeeping here |
152 | } |
153 | |
154 | #ifdef _DEBUG |
155 | private: |
156 | // NOT DEAD CODE: This field is not referenced in the source code but it is not a dead field. See comments above "class AutoExpVisibleValue" for why this field exists. |
157 | // Note: What we really want is for m_value and m_pAutoExpVisibleValue to be members of a union. But the compiler won't let you build that |
158 | // since it can't prove that "TYPE" doesn't have a non-trivial constructor. |
159 | const AutoExpVisibleValue *m_pAutoExpVisibleValue; // This field is to be referenced from individual autoexp.dat files, NOT from the CLR source code. |
160 | #endif //_DEBUG |
161 | |
162 | }; // class HolderBase<> |
163 | |
164 | #ifndef _PREFAST_ // Work around an ICE error in EspX.dll |
165 | |
166 | template <typename TYPE> |
167 | BOOL CompareDefault(TYPE value, TYPE defaultValue) |
168 | { |
169 | STATIC_CONTRACT_SUPPORTS_DAC; |
170 | return value == defaultValue; |
171 | } |
172 | |
173 | #else |
174 | |
175 | template <typename TYPE> |
176 | BOOL CompareDefault(TYPE value, TYPE defaultValue) |
177 | { |
178 | return FALSE; |
179 | } |
180 | |
181 | #endif |
182 | |
183 | |
184 | template <typename TYPE> |
185 | BOOL NoNull(TYPE value, TYPE defaultValue) |
186 | { |
187 | return FALSE; |
188 | } |
189 | |
190 | // Used e.g. for retail version of code:SyncAccessHolder |
191 | template <typename TYPE> |
192 | class NoOpBaseHolder |
193 | { |
194 | public: |
195 | FORCEINLINE NoOpBaseHolder() |
196 | { |
197 | } |
198 | FORCEINLINE NoOpBaseHolder(TYPE value, BOOL take = TRUE) |
199 | { |
200 | } |
201 | FORCEINLINE ~NoOpBaseHolder() |
202 | { |
203 | } |
204 | FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE) |
205 | { |
206 | } |
207 | FORCEINLINE void Acquire() |
208 | { |
209 | } |
210 | FORCEINLINE void Release() |
211 | { |
212 | } |
213 | FORCEINLINE void Clear() |
214 | { |
215 | } |
216 | FORCEINLINE void SuppressRelease() |
217 | { |
218 | } |
219 | FORCEINLINE TYPE () |
220 | { |
221 | } |
222 | FORCEINLINE TYPE GetValue() |
223 | { |
224 | } |
225 | FORCEINLINE BOOL IsNull() const |
226 | { |
227 | return FALSE; |
228 | } |
229 | |
230 | private: |
231 | NoOpBaseHolder& operator=(NoOpBaseHolder const &); |
232 | NoOpBaseHolder(NoOpBaseHolder const &); |
233 | }; // NoOpBaseHolder<> |
234 | |
235 | |
236 | template |
237 | < |
238 | typename TYPE, |
239 | typename BASE, |
240 | UINT_PTR DEFAULTVALUE = 0, |
241 | BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, |
242 | HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq |
243 | > |
244 | class BaseHolder : protected BASE |
245 | { |
246 | protected: |
247 | BOOL m_acquired; // Have we acquired the resource? |
248 | |
249 | static_assert(!std::is_pointer<TYPE>::value || DEFAULTVALUE == 0 || DEFAULTVALUE == UINT_PTR(-1 /*INVALID_HANDLE_VALUE*/), |
250 | "DEFAULTVALUE must be NULL for pointer holders and wrappers." ); |
251 | |
252 | public: |
253 | FORCEINLINE BaseHolder() |
254 | : BASE(TYPE(DEFAULTVALUE)), |
255 | m_acquired(FALSE) |
256 | { |
257 | } |
258 | FORCEINLINE BaseHolder(TYPE value) |
259 | : BASE(value), |
260 | m_acquired(FALSE) |
261 | { |
262 | if (!IsNull()) |
263 | Acquire(); |
264 | } |
265 | FORCEINLINE BaseHolder(TYPE value, BOOL takeOwnership) |
266 | : BASE(value), |
267 | m_acquired(FALSE) |
268 | { |
269 | if (takeOwnership) |
270 | Acquire(); |
271 | } |
272 | FORCEINLINE ~BaseHolder() |
273 | { |
274 | Release(); |
275 | } |
276 | // Sets the value to 'value'. Doesn't call Acquire if value is DEFAULTVALUE. |
277 | FORCEINLINE void Assign(TYPE value) |
278 | { |
279 | Assign(value, !IS_NULL(value, TYPE(DEFAULTVALUE))); |
280 | } |
281 | // Sets the value to 'value'. Doesn't call Acquire if fTake is FALSE. |
282 | FORCEINLINE void Assign(TYPE value, BOOL takeOwnership) |
283 | { |
284 | Release(); |
285 | this->m_value = value; |
286 | if (takeOwnership) |
287 | Acquire(); |
288 | } |
289 | FORCEINLINE void Acquire() |
290 | { |
291 | STATIC_CONTRACT_WRAPPER; |
292 | _ASSERTE(!m_acquired); |
293 | |
294 | if (!IsNull()) |
295 | { |
296 | this->DoAcquire(); |
297 | m_acquired = TRUE; |
298 | } |
299 | } |
300 | FORCEINLINE void Release() |
301 | { |
302 | STATIC_CONTRACT_WRAPPER; |
303 | if (m_acquired) |
304 | { |
305 | _ASSERTE(!IsNull()); |
306 | |
307 | if (VALIDATION_TYPE != HSV_NoValidation) |
308 | { |
309 | VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE); |
310 | this->DoRelease(); |
311 | } |
312 | else |
313 | { |
314 | this->DoRelease(); |
315 | } |
316 | m_acquired = FALSE; |
317 | } |
318 | } |
319 | |
320 | FORCEINLINE void Clear() |
321 | { |
322 | STATIC_CONTRACT_WRAPPER; |
323 | Assign(TYPE(DEFAULTVALUE), FALSE); |
324 | } |
325 | FORCEINLINE void SuppressRelease() |
326 | { |
327 | STATIC_CONTRACT_LEAF; |
328 | m_acquired = FALSE; |
329 | } |
330 | FORCEINLINE TYPE () |
331 | { |
332 | STATIC_CONTRACT_WRAPPER; |
333 | SuppressRelease(); |
334 | return GetValue(); |
335 | } |
336 | FORCEINLINE TYPE GetValue() |
337 | { |
338 | STATIC_CONTRACT_LEAF; |
339 | return this->m_value; |
340 | } |
341 | FORCEINLINE BOOL IsNull() const |
342 | { |
343 | STATIC_CONTRACT_WRAPPER; |
344 | return IS_NULL(this->m_value, TYPE(DEFAULTVALUE)); |
345 | } |
346 | |
347 | HIDE_GENERATED_METHODS(BaseHolder) |
348 | }; // BaseHolder<> |
349 | |
350 | template <void (*ACQUIRE)(), void (*RELEASEF)(), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq> |
351 | class StateHolder |
352 | { |
353 | private: |
354 | BOOL m_acquired; // Have we acquired the state? |
355 | |
356 | public: |
357 | FORCEINLINE StateHolder(BOOL take = TRUE) |
358 | : m_acquired(FALSE) |
359 | { |
360 | STATIC_CONTRACT_WRAPPER; |
361 | if (take) |
362 | Acquire(); |
363 | } |
364 | FORCEINLINE ~StateHolder() |
365 | { |
366 | STATIC_CONTRACT_WRAPPER; |
367 | Release(); |
368 | } |
369 | FORCEINLINE void Acquire() |
370 | { |
371 | STATIC_CONTRACT_WRAPPER; |
372 | // Insert any global or thread bookeeping here |
373 | |
374 | _ASSERTE(!m_acquired); |
375 | |
376 | ACQUIRE(); |
377 | m_acquired = TRUE; |
378 | } |
379 | FORCEINLINE void Release() |
380 | { |
381 | STATIC_CONTRACT_WRAPPER; |
382 | // Insert any global or thread bookeeping here |
383 | |
384 | if (m_acquired) |
385 | { |
386 | if (VALIDATION_TYPE != HSV_NoValidation) |
387 | { |
388 | VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE); |
389 | RELEASEF(); |
390 | } |
391 | else |
392 | { |
393 | RELEASEF(); |
394 | } |
395 | m_acquired = FALSE; |
396 | } |
397 | } |
398 | FORCEINLINE void Clear() |
399 | { |
400 | STATIC_CONTRACT_WRAPPER; |
401 | if (m_acquired) |
402 | { |
403 | RELEASEF(); |
404 | } |
405 | |
406 | m_acquired = FALSE; |
407 | } |
408 | FORCEINLINE void SuppressRelease() |
409 | { |
410 | STATIC_CONTRACT_LEAF; |
411 | m_acquired = FALSE; |
412 | } |
413 | |
414 | HIDE_GENERATED_METHODS(StateHolder) |
415 | }; // class StateHolder<> |
416 | |
417 | // Holder for the case where the acquire function can fail. |
418 | template <typename VALUE, BOOL (*ACQUIRE)(VALUE value), void (*RELEASEF)(VALUE value), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq> |
419 | class ConditionalStateHolder |
420 | { |
421 | private: |
422 | VALUE m_value; |
423 | BOOL m_acquired; // Have we acquired the state? |
424 | |
425 | public: |
426 | FORCEINLINE ConditionalStateHolder(VALUE value, BOOL take = TRUE) |
427 | : m_value(value), m_acquired(FALSE) |
428 | { |
429 | STATIC_CONTRACT_WRAPPER; |
430 | if (take) |
431 | Acquire(); |
432 | } |
433 | FORCEINLINE ~ConditionalStateHolder() |
434 | { |
435 | STATIC_CONTRACT_WRAPPER; |
436 | Release(); |
437 | } |
438 | FORCEINLINE BOOL Acquire() |
439 | { |
440 | STATIC_CONTRACT_WRAPPER; |
441 | // Insert any global or thread bookeeping here |
442 | |
443 | _ASSERTE(!m_acquired); |
444 | |
445 | m_acquired = ACQUIRE(m_value); |
446 | |
447 | return m_acquired; |
448 | } |
449 | FORCEINLINE void Release() |
450 | { |
451 | STATIC_CONTRACT_WRAPPER; |
452 | // Insert any global or thread bookeeping here |
453 | |
454 | if (m_acquired) |
455 | { |
456 | if (VALIDATION_TYPE != HSV_NoValidation) |
457 | { |
458 | VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE); |
459 | RELEASEF(m_value); |
460 | } |
461 | else |
462 | { |
463 | RELEASEF(m_value); |
464 | } |
465 | m_acquired = FALSE; |
466 | } |
467 | } |
468 | FORCEINLINE void Clear() |
469 | { |
470 | STATIC_CONTRACT_WRAPPER; |
471 | if (m_acquired) |
472 | { |
473 | RELEASEF(m_value); |
474 | } |
475 | |
476 | m_acquired = FALSE; |
477 | } |
478 | FORCEINLINE void SuppressRelease() |
479 | { |
480 | STATIC_CONTRACT_LEAF; |
481 | m_acquired = FALSE; |
482 | } |
483 | FORCEINLINE BOOL Acquired() |
484 | { |
485 | STATIC_CONTRACT_LEAF; |
486 | |
487 | return m_acquired; |
488 | } |
489 | |
490 | HIDE_GENERATED_METHODS(ConditionalStateHolder) |
491 | }; // class ConditionalStateHolder<> |
492 | |
493 | |
494 | // Making the copy constructor private produces a warning about "can't generate copy |
495 | // constructor" on all holders (duh, that's the point.) |
496 | #ifdef _MSC_VER |
497 | #pragma warning(disable:4511) |
498 | #endif // _MSC_VER |
499 | |
500 | //----------------------------------------------------------------------------- |
501 | // BaseWrapper is just Base like a Holder, but it "transparently" proxies the type it contains, |
502 | // using operator overloads. Use this when you want a holder to expose the functionality of |
503 | // the value it contains. |
504 | //----------------------------------------------------------------------------- |
505 | template <typename TYPE, typename BASE, |
506 | UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq> |
507 | class BaseWrapper : public BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> |
508 | { |
509 | typedef BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT; |
510 | |
511 | |
512 | #ifdef __GNUC__ |
513 | //#pragma GCC visibility push(hidden) |
514 | #endif // __GNUC__ |
515 | // This temporary object takes care of the case where we are initializing |
516 | // a holder's contents by passing it as an out parameter. The object is |
517 | // guaranteed to live longer than the call it is passed to, hence we should |
518 | // properly acquire the object on return |
519 | friend class AddressInitHolder; |
520 | class AddressInitHolder |
521 | { |
522 | protected: |
523 | BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &m_holder; |
524 | |
525 | public: |
526 | FORCEINLINE AddressInitHolder(BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &holder) |
527 | : m_holder(holder) |
528 | { |
529 | // |
530 | // We must clear the value, to avoid the following scenario: |
531 | // |
532 | // ReleaseHolder<MyType> pMyType; |
533 | // hr = MyFunction(&pMyType, ...); |
534 | // <do something with pMyType> |
535 | // hr = MyFunction(&pMyType, ...); <- calls Release before call and Acquire on return. |
536 | // |
537 | // If the second call to MyFunction were to fail and return without updating the |
538 | // out parameter, then ~AddressInitHolder will all Acquire, which is a no-op on |
539 | // the underlying pointer but sets m_acquired to TRUE. Thus, when pMyType goes |
540 | // out of scope, ReleaseHolder will cause a double-release of pMyType. |
541 | // |
542 | // By calling Clear, then the call to Acquire in the dtor will not set m_acquired |
543 | // to true since IsNull(m_holder.m_value) will return true. |
544 | // |
545 | m_holder.Clear(); |
546 | } |
547 | FORCEINLINE ~AddressInitHolder() |
548 | { |
549 | m_holder.Acquire(); |
550 | } |
551 | |
552 | // It's not optimal to have to declare these casting operators. But if we don't, |
553 | // people cannot cast the result of &holder to these values. (The C++ compiler won't |
554 | // automatically use the TYPE * cast as an intermediate value.) So we put them here, |
555 | // rather than forcing callers to double cast in these common cases. |
556 | |
557 | FORCEINLINE operator IUnknown **() |
558 | { |
559 | IUnknown *unknown; |
560 | // Typesafe check. This will fail at compile time if |
561 | // m_holder.m_value can't be converted to an IUnknown *. |
562 | unknown = static_cast<IUnknown*>(m_holder.m_value); |
563 | // do the cast with an unsafe cast |
564 | return (IUnknown **)(&m_holder.m_value); |
565 | } |
566 | |
567 | #if defined(FEATURE_COMINTEROP) && !defined(STRIKE) |
568 | FORCEINLINE operator IInspectable **() |
569 | { |
570 | IInspectable *inspectable; |
571 | // Typesafe check. This will fail at compile time if |
572 | // m_holder.m_value can't be converted to an IInspectable *. |
573 | inspectable = static_cast<IInspectable *>(m_holder.m_value); |
574 | return (IInspectable **)(&m_holder.m_value); |
575 | |
576 | } |
577 | #endif // FEATURE_COMINTEROP |
578 | |
579 | FORCEINLINE operator void **() |
580 | { |
581 | return (void **)(&m_holder.m_value); |
582 | } |
583 | FORCEINLINE operator void *() |
584 | { |
585 | return (void *)(&m_holder.m_value); |
586 | } |
587 | }; |
588 | |
589 | // Separate out method with TYPE * cast operator, since it may clash with IUnknown ** or |
590 | // void ** cast operator. |
591 | friend class TypedAddressInitHolder; |
592 | class TypedAddressInitHolder : public AddressInitHolder |
593 | { |
594 | public: |
595 | FORCEINLINE TypedAddressInitHolder(BaseWrapper & holder) |
596 | : AddressInitHolder(holder) |
597 | { |
598 | } |
599 | |
600 | FORCEINLINE operator TYPE *() |
601 | { |
602 | return static_cast<TYPE *>(&this->m_holder.m_value); |
603 | } |
604 | }; |
605 | #ifdef __GNUC__ |
606 | //#pragma GCC visibility pop |
607 | #endif // __GNUC__ |
608 | |
609 | public: |
610 | FORCEINLINE BaseWrapper() |
611 | : BaseT(TYPE(DEFAULTVALUE), FALSE) |
612 | { |
613 | } |
614 | FORCEINLINE BaseWrapper(TYPE value) |
615 | : BaseT(value) |
616 | { |
617 | } |
618 | FORCEINLINE BaseWrapper(TYPE value, BOOL take) |
619 | : BaseT(value, take) |
620 | { |
621 | } |
622 | FORCEINLINE BaseWrapper& operator=(TYPE value) |
623 | { |
624 | BaseT::Assign(value); |
625 | return *this; |
626 | } |
627 | FORCEINLINE operator TYPE() const |
628 | { |
629 | return this->m_value; |
630 | } |
631 | FORCEINLINE TypedAddressInitHolder operator&() |
632 | { |
633 | return TypedAddressInitHolder(*this); |
634 | } |
635 | template <typename T> |
636 | FORCEINLINE bool operator==(T const & value) const |
637 | { |
638 | return !!(this->m_value == TYPE(value)); |
639 | } |
640 | template <typename T> |
641 | FORCEINLINE bool operator!=(T const & value) const |
642 | { |
643 | return !!(this->m_value != TYPE(value)); |
644 | } |
645 | #ifdef __llvm__ |
646 | // This handles the NULL value that is an int and clang |
647 | // doesn't want to convert int to a pointer |
648 | FORCEINLINE bool operator==(int value) const |
649 | { |
650 | return !!(this->m_value == TYPE((void*)(SIZE_T)value)); |
651 | } |
652 | FORCEINLINE bool operator!=(int value) const |
653 | { |
654 | return !!(this->m_value != TYPE((void*)(SIZE_T)value)); |
655 | } |
656 | #endif // __llvm__ |
657 | FORCEINLINE const TYPE &operator->() const |
658 | { |
659 | return this->m_value; |
660 | } |
661 | FORCEINLINE int operator!() const |
662 | { |
663 | return this->IsNull(); |
664 | } |
665 | |
666 | private: |
667 | HIDE_GENERATED_METHODS(BaseWrapper) |
668 | }; // class BaseWrapper<> |
669 | |
670 | //----------------------------------------------------------------------------- |
671 | // Generic templates to use to wrap up acquire/release functionality for Holder |
672 | //----------------------------------------------------------------------------- |
673 | |
674 | template <typename TYPE> |
675 | FORCEINLINE void DoNothing(TYPE value) |
676 | { |
677 | // @TODO: Due to prefast template problems, implementations of the DoNothing macro have been changed |
678 | // Search by prefast, and remove them when prefast is ready |
679 | } |
680 | |
681 | FORCEINLINE void DoNothing() |
682 | { |
683 | } |
684 | |
685 | // Prefast stuff.We should have DoNothing<type*> in the holder declaration, but currently |
686 | // prefast doesnt support, it, so im stuffing all these here so if we need to change the template you can change |
687 | // everything here. When prefast works, remove the following functions |
688 | struct ConnectionCookie; |
689 | FORCEINLINE void ConnectionCookieDoNothing(ConnectionCookie* p) |
690 | { |
691 | } |
692 | |
693 | class ComCallWrapper; |
694 | FORCEINLINE void CCWHolderDoNothing(ComCallWrapper* p) |
695 | { |
696 | } |
697 | |
698 | |
699 | FORCEINLINE void DispParamHolderDoNothing(VARIANT* p) |
700 | { |
701 | } |
702 | |
703 | FORCEINLINE void VariantPtrDoNothing(VARIANT* p) |
704 | { |
705 | } |
706 | |
707 | FORCEINLINE void VariantDoNothing(VARIANT) |
708 | { |
709 | } |
710 | |
711 | FORCEINLINE void ZeroDoNothing(VOID* p) |
712 | { |
713 | } |
714 | |
715 | class CtxEntry; |
716 | FORCEINLINE void CtxEntryDoNothing(CtxEntry* p) |
717 | { |
718 | } |
719 | |
720 | struct RCW; |
721 | FORCEINLINE void NewRCWHolderDoNothing(RCW*) |
722 | { |
723 | } |
724 | |
725 | // Prefast stuff.We should have DoNothing<SafeArray*> in the holder declaration |
726 | FORCEINLINE void SafeArrayDoNothing(SAFEARRAY* p) |
727 | { |
728 | } |
729 | |
730 | |
731 | |
732 | |
733 | //----------------------------------------------------------------------------- |
734 | // Holder/Wrapper are the simplest way to define holders - they synthesizes a base class out of |
735 | // function pointers |
736 | //----------------------------------------------------------------------------- |
737 | |
738 | template <typename TYPE, void (*ACQUIREF)(TYPE), void (*RELEASEF)(TYPE), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq> |
739 | class FunctionBase : protected HolderBase<TYPE> |
740 | { |
741 | protected: |
742 | |
743 | FORCEINLINE FunctionBase(TYPE value) |
744 | : HolderBase<TYPE>(value) |
745 | { |
746 | } |
747 | |
748 | FORCEINLINE void DoAcquire() |
749 | { |
750 | ACQUIREF(this->m_value); |
751 | } |
752 | |
753 | void DoRelease() |
754 | { |
755 | // <TODO> Consider removing this stack validation since it is redundant with the |
756 | // one that is already being done in BaseHolder & BaseWrapper. </TODO> |
757 | if (VALIDATION_TYPE != HSV_NoValidation) |
758 | { |
759 | VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE); |
760 | RELEASEF(this->m_value); |
761 | } |
762 | else |
763 | { |
764 | RELEASEF(this->m_value); |
765 | } |
766 | } |
767 | }; // class Function<> |
768 | |
769 | template |
770 | < |
771 | typename TYPE, |
772 | void (*ACQUIREF)(TYPE), |
773 | void (*RELEASEF)(TYPE), |
774 | UINT_PTR DEFAULTVALUE = 0, |
775 | BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, |
776 | HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq, |
777 | // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor |
778 | // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and |
779 | // operates on static or global value instead. |
780 | bool DEFAULT_CTOR_ACQUIRE = true |
781 | > |
782 | class Holder : public BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>, |
783 | DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> |
784 | { |
785 | typedef BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>, |
786 | DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT; |
787 | |
788 | public: |
789 | FORCEINLINE Holder() |
790 | : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE) |
791 | { |
792 | STATIC_CONTRACT_WRAPPER; |
793 | } |
794 | |
795 | FORCEINLINE Holder(TYPE value) |
796 | : BaseT(value) |
797 | { |
798 | STATIC_CONTRACT_WRAPPER; |
799 | } |
800 | |
801 | FORCEINLINE Holder(TYPE value, BOOL takeOwnership) |
802 | : BaseT(value, takeOwnership) |
803 | { |
804 | STATIC_CONTRACT_WRAPPER; |
805 | } |
806 | |
807 | FORCEINLINE Holder& operator=(TYPE p) |
808 | { |
809 | STATIC_CONTRACT_WRAPPER; |
810 | BaseT::operator=(p); |
811 | return *this; |
812 | } |
813 | |
814 | HIDE_GENERATED_METHODS(Holder) |
815 | }; |
816 | |
817 | //--------------------------------------------------------------------------------------- |
818 | // |
819 | template |
820 | < |
821 | typename TYPE, |
822 | void (*ACQUIREF)(TYPE), |
823 | void (*RELEASEF)(TYPE), |
824 | UINT_PTR DEFAULTVALUE = 0, |
825 | BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, |
826 | HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq, |
827 | // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor |
828 | // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and |
829 | // operates on static or global value instead. |
830 | bool DEFAULT_CTOR_ACQUIRE = true |
831 | > |
832 | class Wrapper : public BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>, |
833 | DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> |
834 | { |
835 | typedef BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>, |
836 | DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT; |
837 | |
838 | public: |
839 | FORCEINLINE Wrapper() |
840 | : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE) |
841 | { |
842 | STATIC_CONTRACT_WRAPPER; |
843 | } |
844 | |
845 | FORCEINLINE Wrapper(TYPE value) |
846 | : BaseT(value) |
847 | { |
848 | STATIC_CONTRACT_WRAPPER; |
849 | } |
850 | |
851 | FORCEINLINE Wrapper(TYPE value, BOOL takeOwnership) |
852 | : BaseT(value, takeOwnership) |
853 | { |
854 | STATIC_CONTRACT_WRAPPER; |
855 | } |
856 | |
857 | FORCEINLINE Wrapper& operator=(TYPE const & value) |
858 | { |
859 | STATIC_CONTRACT_WRAPPER; |
860 | BaseT::operator=(value); |
861 | return *this; |
862 | } |
863 | |
864 | HIDE_GENERATED_METHODS(Wrapper) |
865 | }; // Wrapper<> |
866 | |
867 | //--------------------------------------------------------------------------------------- |
868 | // - Cannot use the standard INDEBUG macro: holder.h is used in places where INDEBUG is defined in the nonstandard way |
869 | #if defined(_DEBUG) |
870 | #define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x) x |
871 | #else |
872 | #define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x) |
873 | #endif |
874 | |
875 | //--------------------------------------------------------------------------------------- |
876 | // |
877 | // New template wrapper type macros. These save some effort when specializing |
878 | // existing holder templates. (We would rather use a construct like: |
879 | // |
880 | // template <P1> |
881 | // typedef Holder<...> NewHolder; |
882 | // |
883 | // But this construct doesn't exist in C++. These macros ease some of the cruft necessary |
884 | // to get similar functionality out of class templates. |
885 | //----------------------------------------------------------------------------- |
886 | |
887 | // Dev10 VC++ has some of the new C++0x language extensions. Of particular interest here: |
888 | // rvalue references, which enables differentiation between named (lvalue) and |
889 | // temporary (rvalue) object references, enabling move semantics and perfect forwarding. |
890 | // See http://msdn.microsoft.com/en-us/library/dd293668.aspx for more information. |
891 | |
892 | // Enable copy construction and assignment from temporary objects. This permits Wrapper objects |
893 | // to be returned from methods, and for move assignment. |
894 | #define NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME) \ |
895 | public: \ |
896 | FORCEINLINE _NAME(_NAME && other) \ |
897 | : BaseT(NULL, FALSE) \ |
898 | { \ |
899 | STATIC_CONTRACT_WRAPPER; \ |
900 | INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \ |
901 | *this = std::move(other); \ |
902 | } \ |
903 | FORCEINLINE _NAME& operator=(_NAME && other) \ |
904 | { \ |
905 | std::swap(BaseT::m_value, other.BaseT::m_value); \ |
906 | std::swap(BaseT::m_acquired, other.BaseT::m_acquired); \ |
907 | return *this; \ |
908 | } |
909 | |
910 | #define NEW_WRAPPER_TEMPLATE1(_NAME, _RELEASEF) \ |
911 | template <typename _TYPE> \ |
912 | class _NAME : public Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> \ |
913 | { \ |
914 | typedef Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> BaseT; \ |
915 | public: \ |
916 | FORCEINLINE _NAME() : BaseT(NULL, FALSE) \ |
917 | { \ |
918 | STATIC_CONTRACT_WRAPPER; \ |
919 | INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \ |
920 | } \ |
921 | FORCEINLINE _NAME(_TYPE* value) : BaseT(value) \ |
922 | { \ |
923 | STATIC_CONTRACT_WRAPPER; \ |
924 | INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \ |
925 | } \ |
926 | FORCEINLINE _NAME(_TYPE* value, BOOL takeOwnership) : BaseT(value, takeOwnership) \ |
927 | { \ |
928 | STATIC_CONTRACT_WRAPPER; \ |
929 | INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \ |
930 | } \ |
931 | FORCEINLINE ~_NAME() \ |
932 | { \ |
933 | } \ |
934 | FORCEINLINE _NAME& operator=(_TYPE * value) \ |
935 | { \ |
936 | STATIC_CONTRACT_WRAPPER; \ |
937 | BaseT::operator=(value); \ |
938 | return *this; \ |
939 | } \ |
940 | /* Since operator& is overloaded we need a way to get a type safe this pointer. */ \ |
941 | FORCEINLINE _NAME* GetAddr() \ |
942 | { \ |
943 | STATIC_CONTRACT_LEAF; \ |
944 | return this; \ |
945 | } \ |
946 | NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME) \ |
947 | HIDE_GENERATED_METHODS(_NAME) \ |
948 | private: \ |
949 | /* m_ppValue: Do not use from source code: Only for convenient use from debugger */ \ |
950 | /* watch windows - saves five mouseclicks when inspecting holders. */ \ |
951 | INDEBUG_AND_WINDOWS_FOR_HOLDERS(_TYPE ** m_pvalue;) \ |
952 | }; |
953 | |
954 | //----------------------------------------------------------------------------- |
955 | // NOTE: THIS IS UNSAFE TO USE IN THE VM for interop COM objects!! |
956 | // WE DO NOT CORRECTLY CHANGE TO PREEMPTIVE MODE BEFORE CALLING RELEASE!! |
957 | // USE SafeComHolder |
958 | // |
959 | // ReleaseHolder : COM Interface holder for use outside the VM (or on well known instances |
960 | // which do not need preemptive Relesae) |
961 | // |
962 | // Usage example: |
963 | // |
964 | // { |
965 | // ReleaseHolder<IFoo> foo; |
966 | // hr = FunctionToGetRefOfFoo(&foo); |
967 | // // Note ComHolder doesn't call AddRef - it assumes you already have a ref (if non-0). |
968 | // } // foo->Release() on out of scope (WITHOUT RESPECT FOR GC MODE!!) |
969 | // |
970 | //----------------------------------------------------------------------------- |
971 | |
972 | template <typename TYPE> |
973 | FORCEINLINE void DoTheRelease(TYPE *value) |
974 | { |
975 | if (value) |
976 | { |
977 | VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(HSV_ValidateNormalStackReq); |
978 | value->Release(); |
979 | } |
980 | } |
981 | |
982 | NEW_WRAPPER_TEMPLATE1(DoNothingHolder, DoNothing<_TYPE*>); |
983 | |
984 | NEW_WRAPPER_TEMPLATE1(ReleaseHolder, DoTheRelease<_TYPE>); |
985 | |
986 | NEW_WRAPPER_TEMPLATE1(NonVMComHolder, DoTheRelease<_TYPE>); |
987 | |
988 | |
989 | //----------------------------------------------------------------------------- |
990 | // StubHolder : holder for stubs |
991 | // |
992 | // Usage example: |
993 | // |
994 | // { |
995 | // StubHolder<Stub> foo; |
996 | // foo = new Stub(); |
997 | // foo->AddRef(); |
998 | // // Note StubHolder doesn't call AddRef for you. |
999 | // } // foo->DecRef() on out of scope |
1000 | // |
1001 | //----------------------------------------------------------------------------- |
1002 | template <typename TYPE> |
1003 | FORCEINLINE void StubRelease(TYPE* value) |
1004 | { |
1005 | if (value) |
1006 | value->DecRef(); |
1007 | } |
1008 | |
1009 | NEW_WRAPPER_TEMPLATE1(StubHolder, StubRelease<_TYPE>); |
1010 | |
1011 | //----------------------------------------------------------------------------- |
1012 | // CoTaskMemHolder : CoTaskMemAlloc allocated memory holder |
1013 | // |
1014 | // { |
1015 | // CoTaskMemHolder<Foo> foo = (Foo*) CoTaskMemAlloc(sizeof(Foo)); |
1016 | // } // delete foo on out of scope |
1017 | //----------------------------------------------------------------------------- |
1018 | |
1019 | template <typename TYPE> |
1020 | FORCEINLINE void DeleteCoTaskMem(TYPE *value) |
1021 | { |
1022 | if (value) |
1023 | CoTaskMemFree(value); |
1024 | } |
1025 | |
1026 | NEW_WRAPPER_TEMPLATE1(CoTaskMemHolder, DeleteCoTaskMem<_TYPE>); |
1027 | |
1028 | //----------------------------------------------------------------------------- |
1029 | // NewHolder : New'ed memory holder |
1030 | // |
1031 | // { |
1032 | // NewHolder<Foo> foo = new Foo (); |
1033 | // } // delete foo on out of scope |
1034 | //----------------------------------------------------------------------------- |
1035 | |
1036 | template <typename TYPE> |
1037 | FORCEINLINE void Delete(TYPE *value) |
1038 | { |
1039 | STATIC_CONTRACT_LEAF; |
1040 | |
1041 | static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, WCHAR>::value, |
1042 | "Must use NewArrayHolder (not NewHolder) for strings." ); |
1043 | static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, CHAR>::value, |
1044 | "Must use NewArrayHolder (not NewHolder) for strings." ); |
1045 | |
1046 | delete value; |
1047 | } |
1048 | |
1049 | NEW_WRAPPER_TEMPLATE1(NewHolder, Delete<_TYPE>); |
1050 | |
1051 | //----------------------------------------------------------------------------- |
1052 | // NewExecutableHolder : New'ed memory holder for executable memory. |
1053 | // |
1054 | // { |
1055 | // NewExecutableHolder<Foo> foo = (Foo*) new (executable) Byte[num]; |
1056 | // } // delete foo on out of scope |
1057 | //----------------------------------------------------------------------------- |
1058 | // IJW |
1059 | template<class T> void DeleteExecutable(T *p); |
1060 | |
1061 | NEW_WRAPPER_TEMPLATE1(NewExecutableHolder, DeleteExecutable<_TYPE>); |
1062 | |
1063 | //----------------------------------------------------------------------------- |
1064 | // NewArrayHolder : New []'ed pointer holder |
1065 | // { |
1066 | // NewArrayHolder<Foo> foo = new Foo [30]; |
1067 | // } // delete [] foo on out of scope |
1068 | //----------------------------------------------------------------------------- |
1069 | |
1070 | template <typename TYPE> |
1071 | FORCEINLINE void DeleteArray(TYPE *value) |
1072 | { |
1073 | STATIC_CONTRACT_WRAPPER; |
1074 | delete [] value; |
1075 | value = NULL; |
1076 | } |
1077 | |
1078 | NEW_WRAPPER_TEMPLATE1(NewArrayHolder, DeleteArray<_TYPE>); |
1079 | typedef NewArrayHolder<CHAR> AStringHolder; |
1080 | typedef NewArrayHolder<WCHAR> WStringHolder; |
1081 | |
1082 | //----------------------------------------------------------------------------- |
1083 | // A special array holder that expects its contents are interface pointers, |
1084 | // and will call Release() on them. |
1085 | // |
1086 | // NOTE: You may ONLY use this if you've determined that it is SAFE to call |
1087 | // Release() on the contained interface pointers (e.g., as opposed to SafeRelease) |
1088 | // |
1089 | template <typename INTERFACE> |
1090 | class NewInterfaceArrayHolder : public NewArrayHolder<INTERFACE *> |
1091 | { |
1092 | public: |
1093 | NewInterfaceArrayHolder() : |
1094 | NewArrayHolder<INTERFACE *>(), |
1095 | m_cElements(0) |
1096 | { |
1097 | STATIC_CONTRACT_WRAPPER; |
1098 | } |
1099 | |
1100 | NewInterfaceArrayHolder& operator=(INTERFACE ** value) |
1101 | { |
1102 | STATIC_CONTRACT_WRAPPER; |
1103 | NewArrayHolder<INTERFACE *>::operator=(value); |
1104 | return *this; |
1105 | } |
1106 | |
1107 | void SetElementCount(ULONG32 cElements) |
1108 | { |
1109 | STATIC_CONTRACT_LEAF; |
1110 | m_cElements = cElements; |
1111 | } |
1112 | |
1113 | ~NewInterfaceArrayHolder() |
1114 | { |
1115 | STATIC_CONTRACT_LEAF; |
1116 | for (ULONG32 i=0; i < m_cElements; i++) |
1117 | { |
1118 | if (this->m_value[i] != NULL) |
1119 | this->m_value[i]->Release(); |
1120 | } |
1121 | } |
1122 | |
1123 | protected: |
1124 | ULONG32 m_cElements; |
1125 | }; |
1126 | |
1127 | |
1128 | //----------------------------------------------------------------------------- |
1129 | // ResetPointerHolder : pointer which needs to be set to NULL |
1130 | // { |
1131 | // ResetPointerHolder<Foo> holder = &pFoo; |
1132 | // } // "*pFoo=NULL" on out of scope |
1133 | //----------------------------------------------------------------------------- |
1134 | #ifdef __GNUC__ |
1135 | // With -fvisibility-inlines-hidden, the Invoke methods below |
1136 | // get hidden, which causes warnings when visible classes expose them. |
1137 | #define VISIBLE __attribute__ ((visibility("default"))) |
1138 | #else |
1139 | #define VISIBLE |
1140 | #endif // __GNUC__ |
1141 | |
1142 | namespace detail |
1143 | { |
1144 | template <typename T> |
1145 | struct ZeroMem |
1146 | { |
1147 | static VISIBLE void Invoke(T * pVal) |
1148 | { |
1149 | ZeroMemory(pVal, sizeof(T)); |
1150 | } |
1151 | }; |
1152 | |
1153 | template <typename T> |
1154 | struct ZeroMem<T*> |
1155 | { |
1156 | static VISIBLE void Invoke(T ** pVal) |
1157 | { |
1158 | *pVal = NULL; |
1159 | } |
1160 | }; |
1161 | |
1162 | } |
1163 | #undef VISIBLE |
1164 | |
1165 | NEW_WRAPPER_TEMPLATE1(ResetPointerHolder, detail::ZeroMem<_TYPE>::Invoke); |
1166 | NEW_WRAPPER_TEMPLATE1(FieldNuller, detail::ZeroMem<_TYPE>::Invoke); |
1167 | |
1168 | //----------------------------------------------------------------------------- |
1169 | // Wrap win32 functions using HANDLE |
1170 | //----------------------------------------------------------------------------- |
1171 | |
1172 | FORCEINLINE void VoidCloseHandle(HANDLE h) { if (h != NULL) CloseHandle(h); } |
1173 | // (UINT_PTR) -1 is INVALID_HANDLE_VALUE |
1174 | FORCEINLINE void VoidCloseFileHandle(HANDLE h) { if (h != ((HANDLE)((LONG_PTR) -1))) CloseHandle(h); } |
1175 | FORCEINLINE void VoidFindClose(HANDLE h) { FindClose(h); } |
1176 | FORCEINLINE void VoidUnmapViewOfFile(void *ptr) { UnmapViewOfFile(ptr); } |
1177 | |
1178 | template <typename TYPE> |
1179 | FORCEINLINE void TypeUnmapViewOfFile(TYPE *ptr) { UnmapViewOfFile(ptr); } |
1180 | |
1181 | // (UINT_PTR) -1 is INVALID_HANDLE_VALUE |
1182 | //@TODO: Dangerous default value. Some Win32 functions return INVALID_HANDLE_VALUE, some return NULL (such as CreatEvent). |
1183 | typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseHandle, (UINT_PTR) -1> HandleHolder; |
1184 | typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseFileHandle, (UINT_PTR) -1> FileHandleHolder; |
1185 | typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidFindClose, (UINT_PTR) -1> FindHandleHolder; |
1186 | |
1187 | typedef Wrapper<void *, DoNothing, VoidUnmapViewOfFile> MapViewHolder; |
1188 | |
1189 | #ifdef WszDeleteFile |
1190 | // Deletes a file with the specified path. Do not use if you care about failures |
1191 | // deleting the file, as failures are ignored by VoidDeleteFile. |
1192 | FORCEINLINE void VoidDeleteFile(LPCWSTR wszFilePath) { WszDeleteFile(wszFilePath); } |
1193 | typedef Wrapper<LPCWSTR, DoNothing<LPCWSTR>, VoidDeleteFile, NULL> DeleteFileHolder; |
1194 | #endif // WszDeleteFile |
1195 | |
1196 | |
1197 | //----------------------------------------------------------------------------- |
1198 | // Misc holders |
1199 | //----------------------------------------------------------------------------- |
1200 | |
1201 | // A holder for HMODULE. |
1202 | FORCEINLINE void HolderFreeLibrary(HMODULE h) { FreeLibrary(h); } |
1203 | |
1204 | typedef Wrapper<HMODULE, DoNothing<HMODULE>, HolderFreeLibrary, NULL> HModuleHolder; |
1205 | |
1206 | template <typename T> FORCEINLINE |
1207 | void DoLocalFree(T* pMem) { (LocalFree)((HLOCAL)pMem); } |
1208 | |
1209 | NEW_WRAPPER_TEMPLATE1(LocalAllocHolder, DoLocalFree<_TYPE>); |
1210 | |
1211 | inline void BoolSet( _Out_ bool * val ) { *val = true; } |
1212 | inline void BoolUnset( _Out_ bool * val ) { *val = false; } |
1213 | |
1214 | typedef Wrapper< bool *, BoolSet, BoolUnset > BoolFlagStateHolder; |
1215 | |
1216 | // |
1217 | // We need the following methods to have volatile arguments, so that they can accept |
1218 | // raw pointers in addition to the results of the & operator on Volatile<T>. |
1219 | // |
1220 | |
1221 | FORCEINLINE void CounterIncrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedIncrement(p);}; |
1222 | FORCEINLINE void CounterDecrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedDecrement(p);}; |
1223 | |
1224 | typedef Wrapper<RAW_KEYWORD(volatile) LONG*, CounterIncrease, CounterDecrease, (UINT_PTR)0, CompareDefault<RAW_KEYWORD(volatile) LONG*>, HSV_NoValidation> CounterHolder; |
1225 | |
1226 | |
1227 | #ifndef FEATURE_PAL |
1228 | FORCEINLINE void RegKeyRelease(HKEY k) {RegCloseKey(k);}; |
1229 | typedef Wrapper<HKEY,DoNothing,RegKeyRelease> RegKeyHolder; |
1230 | #endif // !FEATURE_PAL |
1231 | |
1232 | class ErrorModeHolder |
1233 | { |
1234 | UINT m_oldMode; |
1235 | public: |
1236 | ErrorModeHolder(UINT newMode){m_oldMode=SetErrorMode(newMode);}; |
1237 | ~ErrorModeHolder(){SetErrorMode(m_oldMode);}; |
1238 | UINT OldMode() {return m_oldMode;}; |
1239 | }; |
1240 | |
1241 | #ifndef FEATURE_PAL |
1242 | //----------------------------------------------------------------------------- |
1243 | // HKEYHolder : HKEY holder, Calls RegCloseKey on scope exit. |
1244 | // |
1245 | // { |
1246 | // HKEYHolder hFoo = NULL; |
1247 | // WszRegOpenKeyEx(HKEY_CLASSES_ROOT, L"Interface",0, KEY_READ, hFoo); |
1248 | // |
1249 | // } // close key on out of scope via RegCloseKey. |
1250 | //----------------------------------------------------------------------------- |
1251 | |
1252 | class HKEYHolder |
1253 | { |
1254 | public: |
1255 | HKEYHolder() |
1256 | { |
1257 | STATIC_CONTRACT_LEAF; |
1258 | m_value = 0; |
1259 | } |
1260 | |
1261 | ~HKEYHolder() |
1262 | { |
1263 | STATIC_CONTRACT_WRAPPER; |
1264 | if (m_value != NULL) |
1265 | ::RegCloseKey(m_value); |
1266 | } |
1267 | |
1268 | FORCEINLINE void operator=(HKEY p) |
1269 | { |
1270 | STATIC_CONTRACT_LEAF; |
1271 | if (p != 0) |
1272 | m_value = p; |
1273 | } |
1274 | |
1275 | FORCEINLINE operator HKEY() |
1276 | { |
1277 | STATIC_CONTRACT_LEAF; |
1278 | return m_value; |
1279 | } |
1280 | |
1281 | FORCEINLINE operator HKEY*() |
1282 | { |
1283 | STATIC_CONTRACT_LEAF; |
1284 | return &m_value; |
1285 | } |
1286 | |
1287 | FORCEINLINE HKEY* operator&() |
1288 | { |
1289 | STATIC_CONTRACT_LEAF; |
1290 | return &m_value; |
1291 | } |
1292 | |
1293 | private: |
1294 | HKEY m_value; |
1295 | }; |
1296 | #endif // !FEATURE_PAL |
1297 | |
1298 | //---------------------------------------------------------------------------- |
1299 | // |
1300 | // External data access does not want certain holder implementations |
1301 | // to be active as locks should not be taken and so on. Provide |
1302 | // a no-op in that case. |
1303 | // |
1304 | //---------------------------------------------------------------------------- |
1305 | |
1306 | #ifndef DACCESS_COMPILE |
1307 | |
1308 | #define DacHolder Holder |
1309 | |
1310 | #else |
1311 | |
1312 | template <typename TYPE, void (*ACQUIRE)(TYPE), void (*RELEASEF)(TYPE), UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, BOOL VALIDATE_BACKOUT_STACK = TRUE> |
1313 | class DacHolder |
1314 | { |
1315 | protected: |
1316 | TYPE m_value; |
1317 | |
1318 | private: |
1319 | BOOL m_acquired; // Have we acquired the resource? |
1320 | |
1321 | public: |
1322 | FORCEINLINE DacHolder() |
1323 | : m_value(TYPE(DEFAULTVALUE)), |
1324 | m_acquired(FALSE) |
1325 | { |
1326 | STATIC_CONTRACT_SUPPORTS_DAC; |
1327 | } |
1328 | |
1329 | // construct a new instance of DacHolder |
1330 | // Arguments: |
1331 | // input: value - the resource held |
1332 | // take - indicates whether the lock should be taken--the default is true. See Notes: |
1333 | // Note: In DAC builds, the Acquire function does not actually take the lock, instead |
1334 | // it determines whether the lock is held (by the LS). If it is, the locked data |
1335 | // is assumed to be inconsistent and the Acquire function will throw. |
1336 | FORCEINLINE DacHolder(TYPE value, BOOL take = TRUE) |
1337 | : m_value(value), |
1338 | m_acquired(FALSE) |
1339 | { |
1340 | STATIC_CONTRACT_SUPPORTS_DAC; |
1341 | if (take) |
1342 | Acquire(); |
1343 | |
1344 | } |
1345 | FORCEINLINE ~DacHolder() |
1346 | { |
1347 | STATIC_CONTRACT_SUPPORTS_DAC; |
1348 | } |
1349 | // Sets the value to 'value'. Doesn't call Acquire/Release if fTake is FALSE. |
1350 | FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE) |
1351 | { |
1352 | m_value = value; |
1353 | } |
1354 | FORCEINLINE void Acquire() |
1355 | { |
1356 | STATIC_CONTRACT_SUPPORTS_DAC; |
1357 | |
1358 | if (!IsNull()) |
1359 | { |
1360 | m_acquired = TRUE; |
1361 | // because ACQUIRE is a template argument, if the line m_acquired = TRUE is placed after the call |
1362 | // where it logically belongs, the compiler flags it as "unreachable code." |
1363 | ACQUIRE(this->m_value); |
1364 | } |
1365 | } |
1366 | FORCEINLINE void Release() |
1367 | { |
1368 | // Insert any global or thread bookeeping here |
1369 | |
1370 | if (m_acquired) |
1371 | { |
1372 | m_acquired = FALSE; |
1373 | } |
1374 | } |
1375 | FORCEINLINE void Clear() |
1376 | { |
1377 | m_value = TYPE(DEFAULTVALUE); |
1378 | m_acquired = FALSE; |
1379 | } |
1380 | FORCEINLINE void SuppressRelease() |
1381 | { |
1382 | m_acquired = FALSE; |
1383 | } |
1384 | FORCEINLINE TYPE GetValue() |
1385 | { |
1386 | return m_value; |
1387 | } |
1388 | FORCEINLINE BOOL IsNull() const |
1389 | { |
1390 | return IS_NULL(m_value, TYPE(DEFAULTVALUE)); |
1391 | } |
1392 | |
1393 | private: |
1394 | FORCEINLINE DacHolder& operator=(const Holder<TYPE, ACQUIRE, RELEASEF> &holder) |
1395 | { |
1396 | } |
1397 | |
1398 | FORCEINLINE DacHolder(const Holder<TYPE, ACQUIRE, RELEASEF> &holder) |
1399 | { |
1400 | } |
1401 | }; |
1402 | |
1403 | #endif // #ifndef DACCESS_COMPILE |
1404 | |
1405 | // Holder-specific clr::SafeAddRef and clr::SafeRelease helper functions. |
1406 | namespace clr |
1407 | { |
1408 | // Copied from utilcode.h. We can't include the header directly because there |
1409 | // is circular reference. |
1410 | // Forward declare the overload which is used by 'SafeAddRef' below. |
1411 | template <typename ItfT> |
1412 | static inline |
1413 | typename std::enable_if< std::is_pointer<ItfT>::value, ItfT >::type |
1414 | SafeAddRef(ItfT pItf); |
1415 | |
1416 | template < typename ItfT > __checkReturn |
1417 | ItfT * |
1418 | SafeAddRef(ReleaseHolder<ItfT> & pItf) |
1419 | { |
1420 | STATIC_CONTRACT_LIMITED_METHOD; |
1421 | //@TODO: Would be good to add runtime validation that the return value is used. |
1422 | return SafeAddRef(pItf.GetValue()); |
1423 | } |
1424 | |
1425 | namespace detail |
1426 | { |
1427 | template <typename T> |
1428 | char IsHolderHelper(HolderBase<T>*); |
1429 | int IsHolderHelper(...); |
1430 | |
1431 | template <typename T> |
1432 | struct IsHolder : public std::conditional< |
1433 | sizeof(IsHolderHelper(reinterpret_cast<T*>(NULL))) == sizeof(char), |
1434 | std::true_type, |
1435 | std::false_type>::type |
1436 | {}; |
1437 | } |
1438 | |
1439 | template < typename T > |
1440 | typename std::enable_if<detail::IsHolder<T>::value, ULONG>::type |
1441 | SafeRelease(T& arg) |
1442 | { |
1443 | STATIC_CONTRACT_LIMITED_METHOD; |
1444 | return arg.Release(); |
1445 | } |
1446 | } |
1447 | |
1448 | #endif // __HOLDER_H_ |
1449 | |