File: pinned_gcroot.h

package info (click to toggle)
libpwiz 3.0.18342-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 14,888 kB
  • sloc: cpp: 157,552; sh: 4,182; makefile: 317
file content (139 lines) | stat: -rw-r--r-- 4,775 bytes parent folder | download | duplicates (3)
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