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
|
//
// $Id$
//
//
// Original author: Matt Chambers <matt.chambers .@. vanderbilt.edu>
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Slightly modified version of gcroot.h that pins the GCHandle and allows access to the handle.
//
#pragma once
#include <gcroot.h>
#ifdef __cplusplus_cli
#define __GCHANDLE_TO_VOIDPTR(x) ((GCHandle::operator System::IntPtr(x)).ToPointer())
#define __VOIDPTR_TO_GCHANDLE(x) (GCHandle::operator GCHandle(System::IntPtr(x)))
#define __NULLPTR nullptr
#else /* __cplusplus_cli */
#define __GCHANDLE_TO_VOIDPTR(x) ((GCHandle::op_Explicit(x)).ToPointer())
#define __VOIDPTR_TO_GCHANDLE(x) (GCHandle::op_Explicit(x))
#define __NULLPTR 0
#endif /* __cplusplus_cli */
#ifndef __DEFINE_GCROOT_IN_GLOBAL_NAMESPACE
namespace msclr
{
#endif /* __DEFINE_GCROOT_IN_GLOBAL_NAMESPACE */
/// pinned_gcroot: a slightly modified gcroot that pins its GCHandle
template <class T> struct pinned_gcroot {
typedef System::Runtime::InteropServices::GCHandle GCHandle;
typedef System::Runtime::InteropServices::GCHandleType GCHandleType;
// always allocate a new handle during construction (see above)
//
// Initializes to a NULL handle, which is always safe
[System::Diagnostics::DebuggerStepThroughAttribute]
[System::Security::SecuritySafeCritical]
pinned_gcroot() {
_handle = __GCHANDLE_TO_VOIDPTR(GCHandle::Alloc(__NULLPTR, GCHandleType::Pinned));
}
// this can't be T& here because & does not yet work on managed types
// (T should be a pointer anyway).
//
pinned_gcroot(T t) {
_handle = __GCHANDLE_TO_VOIDPTR(GCHandle::Alloc(t, GCHandleType::Pinned));
}
pinned_gcroot(const pinned_gcroot& r) {
// don't copy a handle, copy what it points to (see above)
_handle = __GCHANDLE_TO_VOIDPTR(
GCHandle::Alloc(
__VOIDPTR_TO_GCHANDLE(r._handle).Target, GCHandleType::Pinned));
}
// Since C++ objects and handles are allocated 1-to-1, we can
// free the handle when the object is destroyed
//
[System::Diagnostics::DebuggerStepThroughAttribute]
[System::Security::SecurityCritical]
~pinned_gcroot() {
GCHandle g = __VOIDPTR_TO_GCHANDLE(_handle);
g.Free();
_handle = 0; // should fail if reconstituted
}
[System::Diagnostics::DebuggerStepThroughAttribute]
[System::Security::SecurityCritical]
pinned_gcroot& operator=(T t) {
// no need to check for valid handle; was allocated in ctor
__VOIDPTR_TO_GCHANDLE(_handle).Target = t;
return *this;
}
pinned_gcroot& operator=(const pinned_gcroot &r) {
// no need to check for valid handle; was allocated in ctor
T t = (T)r;
__VOIDPTR_TO_GCHANDLE(_handle).Target = t;
return *this;
}
void swap(pinned_gcroot<T> & _right)
{
using std::swap;
swap(_handle, _right._handle);
}
// The managed object is not a secret or protected resource, so it's okay to expose to anyone who has access to the gcroot object
[System::Security::SecuritySafeCritical]
operator T () const {
// gcroot is typesafe, so use static_cast
return static_cast<T>(__VOIDPTR_TO_GCHANDLE(_handle).Target);
}
// don't return T& here because & to gc pointer not yet implemented
// (T should be a pointer anyway).
[System::Security::SecuritySafeCritical]
T operator->() const {
// gcroot is typesafe, so use static_cast
return static_cast<T>(__VOIDPTR_TO_GCHANDLE(_handle).Target);
}
System::IntPtr operator& () const {
return __VOIDPTR_TO_GCHANDLE(_handle).AddrOfPinnedObject();
}
void* handle() const {
return _handle;
}
private:
// Don't let anyone copy the handle value directly, or make a copy
// by taking the address of this object and pointing to it from
// somewhere else. The root will be freed when the dtor of this
// object gets called, and anyone pointing to it still will
// cause serious harm to the Garbage Collector.
//
void* _handle;
};
template<typename T>
void swap(pinned_gcroot<T> & _left,
pinned_gcroot<T> & _right)
{
_left.swap(_right);
}
#ifndef __DEFINE_GCROOT_IN_GLOBAL_NAMESPACE
} // namespace msclr
#endif /* __DEFINE_GCROOT_IN_GLOBAL_NAMESPACE */
#undef __GCHANDLE_TO_VOIDPTR
#undef __VOIDPTR_TO_GCHANDLE
#undef __NULLPTR
|