/*** *gcroot.h * * Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: Template class that wraps GCHandle from mscorlib.dll. * * Use this class to declare gc "pointers" that live in the C++ heap. * * Example: * struct StringList { * msclr::gcroot str; * StringList *next; * StringList(); // should have ctors and dtors * ~StringList(); * }; * * By convention, we maintain a 1-to-1 relationship between C++ objects * and the handle slots they "point" to. Thus, two distinct C++ objects * always refer to two distinct handles, even if they "point" to the same * object. Therefore, when the C++ object is destroyed, its handle can * be freed without error. * * Note that we cannot currently embed a GCHandle directly in an unmanaged C++ * class. We therefore store a void*, and use the conversion methods of * GCHandle to reconstitute a GCHandle from the void* on demand. * * [Public] * ****/ #pragma once #if !defined (_INC_MSCLR_GCROOT) #define _INC_MSCLR_GCROOT #include #if _STL_COMPILER_PREPROCESSOR #include #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 */ template struct gcroot { typedef System::Runtime::InteropServices::GCHandle GCHandle; // always allocate a new handle during construction (see above) // // Initializes to a NULL handle, which is always safe [System::Diagnostics::DebuggerStepThroughAttribute] [System::Security::SecuritySafeCritical] gcroot() { _handle = __GCHANDLE_TO_VOIDPTR(GCHandle::Alloc(__NULLPTR)); } // this can't be T& here because & does not yet work on managed types // (T should be a pointer anyway). // gcroot(T t) { _handle = __GCHANDLE_TO_VOIDPTR(GCHandle::Alloc(t)); } gcroot(const 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 )); } // 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] ~gcroot() { GCHandle g = __VOIDPTR_TO_GCHANDLE(_handle); g.Free(); _handle = 0; // should fail if reconstituted } [System::Diagnostics::DebuggerStepThroughAttribute] [System::Security::SecurityCritical] gcroot& operator=(T t) { // no need to check for valid handle; was allocated in ctor __VOIDPTR_TO_GCHANDLE(_handle).Target = t; return *this; } gcroot& operator=(const 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( gcroot & _right ) { void* t = _handle; _handle = _right._handle; _right._handle = t; } // 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( __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(__VOIDPTR_TO_GCHANDLE(_handle).Target); } 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; T* operator& (); }; template void swap( gcroot & _left, gcroot & _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 #endif /* _STL_COMPILER_PREPROCESSOR */ #endif /* !defined (_INC_MSCLR_GCROOT) */