1 /***
2 *gcroot.h
3 *
4 *           Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 *Purpose:  Template class that wraps GCHandle from mscorlib.dll.
7 *
8 *    Use this class to declare gc "pointers" that live in the C++ heap.
9 *    
10 *    Example:
11 *        struct StringList {
12 *            msclr::gcroot<String^> str;
13 *            StringList *next;
14 *            StringList(); // should have ctors and dtors
15 *            ~StringList();
16 *        };
17 *
18 *    By convention, we maintain a 1-to-1 relationship between C++ objects
19 *    and the handle slots they "point" to.  Thus, two distinct C++ objects
20 *    always refer to two distinct handles, even if they "point" to the same
21 *    object.  Therefore, when the C++ object is destroyed, its handle can
22 *    be freed without error.
23 *
24 *    Note that we cannot currently embed a GCHandle directly in an unmanaged C++
25 *    class.  We therefore store a void*, and use the conversion methods of
26 *    GCHandle to reconstitute a GCHandle from the void* on demand.
27 *
28 *     [Public]
29 *
30 ****/
31
32 #pragma once
33
34 #if !defined(_INC_MSCLR_GCROOT)
35 #define _INC_MSCLR_GCROOT
36 #ifndef RC_INVOKED
37
38 #include <stddef.h>
39
40
41 #ifdef __cplusplus_cli
42  #define __GCHANDLE_TO_VOIDPTR(x) ((GCHandle::operator System::IntPtr(x)).ToPointer())
43  #define __VOIDPTR_TO_GCHANDLE(x) (GCHandle::operator GCHandle(System::IntPtr(x)))
44  #define __NULLPTR nullptr
45 #else
46  #define __GCHANDLE_TO_VOIDPTR(x) ((GCHandle::op_Explicit(x)).ToPointer())
47  #define __VOIDPTR_TO_GCHANDLE(x) (GCHandle::op_Explicit(x))
48  #define __NULLPTR 0
49 #endif
50
51 #ifndef __DEFINE_GCROOT_IN_GLOBAL_NAMESPACE
52 namespace msclr
53 {
54 #endif
55
56 template <class T> struct gcroot {
57
58     typedef System::Runtime::InteropServices::GCHandle GCHandle;
59
60     // always allocate a new handle during construction (see above)
61     //
62     [System::Diagnostics::DebuggerStepThroughAttribute]
63     gcroot() {
64         _handle = __GCHANDLE_TO_VOIDPTR(GCHandle::Alloc(__NULLPTR));
65     }
66
67     // this can't be T& here because & does not yet work on managed types
68     // (T should be a pointer anyway).
69     //
70     gcroot(T t) {
71         _handle = __GCHANDLE_TO_VOIDPTR(GCHandle::Alloc(t));
72     }
73
74     gcroot(const gcroot& r) {
75         // don't copy a handle, copy what it points to (see above)
76         _handle = __GCHANDLE_TO_VOIDPTR(
77                         GCHandle::Alloc(
78                             __VOIDPTR_TO_GCHANDLE(r._handle).Target ));
79     }
80
81     // Since C++ objects and handles are allocated 1-to-1, we can 
82     // free the handle when the object is destroyed
83     //
84     [System::Diagnostics::DebuggerStepThroughAttribute]
85     ~gcroot() {
86         GCHandle g = __VOIDPTR_TO_GCHANDLE(_handle);
87         g.Free();
88         _handle = 0; // should fail if reconstituted
89     }
90
Lines 91 ... 100 are skipped.
101         __VOIDPTR_TO_GCHANDLE(_handle).Target = t;
102         return *this;
103     }
104
105     void swap( gcroot<T> & _right )
106     {
107         using std::swap;
108         swap( _handle, _right._handle );
109     }
110
111     operator T () const {
112         // gcroot is typesafe, so use static_cast
113         return static_cast<T>( __VOIDPTR_TO_GCHANDLE(_handle).Target );
114     }
115
116     // don't return T& here because & to gc pointer not yet implemented
117     // (T should be a pointer anyway).
118     T operator->() const {
119         // gcroot is typesafe, so use static_cast
120         return static_cast<T>(__VOIDPTR_TO_GCHANDLE(_handle).Target);
121     }
122
123 private:
124     // Don't let anyone copy the handle value directly, or make a copy
125     // by taking the address of this object and pointing to it from
126     // somewhere else.  The root will be freed when the dtor of this
127     // object gets called, and anyone pointing to it still will
128     // cause serious harm to the Garbage Collector.
129     //
130     void* _handle;
131     T* operator& ();
132 };
133
134 template<typename T>
135 void swap( gcroot<T> & _left,
136     gcroot<T> & _right )
137 {
138     _left.swap( _right );
139 }
140
141 #ifndef __DEFINE_GCROOT_IN_GLOBAL_NAMESPACE
142 } // namespace msclr
143 #endif
144
145 #undef __GCHANDLE_TO_VOIDPTR
146 #undef __VOIDPTR_TO_GCHANDLE
147 #undef __NULLPTR
148
149 #endif /* RC_INVOKED */
150 #endif  // _INC_MSCLR_GCROOT 
151