MS公开的gchandle.cs源码
1// ==++==
2//
3//
4// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
5//
6// The use and distribution terms for this software are contained in the file
7// named license.txt, which can be found in the root of this distribution.
8// By using this software in any fashion, you are agreeing to be bound by the
9// terms of this license.
10//
11// You must not remove this notice, or any other, from this software.
12//
13//
14// ==--==
15namespace System.Runtime.InteropServices {
16
17 using System;
18 using System.Security.Permissions;
19 using System.Runtime.CompilerServices;
20
21 // These are the types of handles used by the EE. IMPORTANT: These must
22 // match the definitions in ObjectHandle.h in the EE.
23 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType"]/*' />
24 [Serializable]
25 public enum GCHandleType
26 {
27 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Weak"]/*' />
28 Weak = 0,
29 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.WeakTrackResurrection"]/*' />
30 WeakTrackResurrection = 1,
31 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Normal"]/*' />
32 Normal = 2,
33 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Pinned"]/*' />
34 Pinned = 3
35 }
36
37 // This class allows you to create an opaque, GC handle to any
38 // COM+ object. A GC handle is used when an object reference must be
39 // reachable from unmanaged memory. There are 3 kinds of roots:
40 // Normal - keeps the object from being collected.
41 // Weak - allows object to be collected and handle contents will be zeroed.
42 // Weak references are zeroed before the finalizer runs, so if the
43 // object is resurrected in the finalizer the weak reference is
44 // still zeroed.
45 // WeakTrackResurrection - Same as weak, but stays until after object is
46 // really gone.
47 // Pinned - same as normal, but allows the address of the actual object
48 // to be taken.
49 //
50 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle"]/*' />
51 [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
52 public struct GCHandle
53 {
54 // Allocate a handle storing the object and the type.
55 internal GCHandle(Object value, GCHandleType type)
56 {
57 m_handle = InternalAlloc(value, type);
58
59 // Record if the handle is pinned.
60 if (type == GCHandleType.Pinned)
61 SetIsPinned();
62 }
63
64 // Used in the conversion functions below.
65 internal GCHandle(IntPtr handle)
66 {
67 InternalCheckDomain(handle);
68 m_handle = handle;
69 }
70
71 // Creates a new GC handle for an object.
72 //
73 // value - The object that the GC handle is created for.
74 // type - The type of GC handle to create.
75 //
76 // returns a new GC handle that protects the object.
77 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Alloc"]/*' />
78 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
79 public static GCHandle Alloc(Object value)
80 {
81 return new GCHandle(value, GCHandleType.Normal);
82 }
83
84 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Alloc1"]/*' />
85 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
86 public static GCHandle Alloc(Object value, GCHandleType type)
87 {
88 return new GCHandle(value, type);
89 }
90
91 // Frees a GC handle. The caller must provide synchronization to
92 // prevent multiple threads from executing this simultaneously for
93 // a given handle. If you modify this method please modify the
94 // __InternalFree also which is the internal without the linktime check.
95 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Free"]/*' />
96 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
97 public void Free()
98 {
99 // Check if the handle was never initialized for was freed.
100 if (m_handle == IntPtr.Zero)
101 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
102
103 // Free the handle.
104 InternalFree(GetHandleValue());
105 m_handle = IntPtr.Zero;
106 }
107
108 internal void __InternalFree()
109 {
110 // Check if the handle was never initialized for was freed.
111 if (m_handle == IntPtr.Zero)
112 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
113
114 // Free the handle.
115 InternalFree(GetHandleValue());
116 m_handle = IntPtr.Zero;
117 }
118
119 // Target property - allows getting / updating of the handle's referent. If you modify this method
120
121 // then modify the __InternalTarget too which is the internal method without the linktime check.
122 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Target"]/*' />
123 public Object Target
124 {
125 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
126 get
127 {
128 // Check if the handle was never initialized or was freed.
129 if (m_handle == IntPtr.Zero)
130 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
131
132 return InternalGet(GetHandleValue());
133 }
134
135 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
136 set
137 {
138 // Check if the handle was never initialized or was freed.
139 if (m_handle == IntPtr.Zero)
140 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
141
142 InternalSet(GetHandleValue(), value, IsPinned());
143 }
144 }
145
146 internal Object __InternalTarget
147 {
148 get
149 {
150 // Check if the handle was never initialized or was freed.
151 if (m_handle == IntPtr.Zero)
152 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
153
154 return InternalGet(GetHandleValue());
155 }
156 }
157
158 // Retrieve the address of an object in a Pinned handle. This throws
159 // an exception if the handle is any type other than Pinned.
160 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.AddrOfPinnedObject"]/*' />
161 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
162 public IntPtr AddrOfPinnedObject()
163 {
164 // Check if the handle was not a pinned handle.
165 if (!IsPinned())
166 {
167 // Check if the handle was never initialized for was freed.
168 if (m_handle == IntPtr.Zero)
169 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
170
171 // You can only get the address of pinned handles.
172 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotPinned"));
173 }
174
175 // Get the address.
176 return InternalAddrOfPinnedObject(GetHandleValue());
177 }
178
179 // Determine whether this handle has been allocated or not.
180 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.IsAllocated"]/*' />
181 public bool IsAllocated
182 {
183 get
184 {
185 return m_handle != IntPtr.Zero;
186 }
187 }
188
189 // Used to create a GCHandle from an int. This is intended to
190 // be used with the reverse conversion.
191 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.operatorGCHandle"]/*' />
192 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
193 public static explicit operator GCHandle(IntPtr value)
194 {
195 return new GCHandle(value);
196 }
197
198 // Used to get the internal integer representation of the handle out.
199 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.operatorIntPtr"]/*' />
200 public static explicit operator IntPtr(GCHandle value)
201 {
202 return value.m_handle;
203 }
204
205 internal IntPtr GetHandleValue()
206 {
207#if WIN32
208 return new IntPtr(((int)m_handle) & ~1);
209#else
210 return new IntPtr(((long)m_handle) & ~1L);
211#endif
212 }
213
214 internal bool IsPinned()
215 {
216#if WIN32
217 return (((int)m_handle) & 1) != 0;
218#else
219 return (((long)m_handle) & 1) != 0;
220#endif
221 }
222
223 internal void SetIsPinned()
224 {
225#if WIN32
226 m_handle = new IntPtr(((int)m_handle) | 1);
227#else
228 m_handle = new IntPtr(((long)m_handle) | 1L);
229#endif
230 }
231
232 // Internal native calls that this implementation uses.
233 [MethodImplAttribute(MethodImplOptions.InternalCall)]
234 internal static extern IntPtr InternalAlloc(Object value, GCHandleType type);
235 [MethodImplAttribute(MethodImplOptions.InternalCall)]
236 internal static extern void InternalFree(IntPtr handle);
237 [MethodImplAttribute(MethodImplOptions.InternalCall)]
238 internal static extern Object InternalGet(IntPtr handle);
239 [MethodImplAttribute(MethodImplOptions.InternalCall)]
240 internal static extern void InternalSet(IntPtr handle, Object value, bool isPinned);
241 [MethodImplAttribute(MethodImplOptions.InternalCall)]
242 internal static extern void InternalCompareExchange(IntPtr handle, Object value, Object oldValue, bool isPinned);
243 [MethodImplAttribute(MethodImplOptions.InternalCall)]
244 internal static extern IntPtr InternalAddrOfPinnedObject(IntPtr handle);
245 [MethodImplAttribute(MethodImplOptions.InternalCall)]
246 internal static extern void InternalCheckDomain(IntPtr handle);
247
248
249 // The actual integer handle value that the EE uses internally.
250 private IntPtr m_handle;
251 }
252}
253
254
2//
3//
4// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
5//
6// The use and distribution terms for this software are contained in the file
7// named license.txt, which can be found in the root of this distribution.
8// By using this software in any fashion, you are agreeing to be bound by the
9// terms of this license.
10//
11// You must not remove this notice, or any other, from this software.
12//
13//
14// ==--==
15namespace System.Runtime.InteropServices {
16
17 using System;
18 using System.Security.Permissions;
19 using System.Runtime.CompilerServices;
20
21 // These are the types of handles used by the EE. IMPORTANT: These must
22 // match the definitions in ObjectHandle.h in the EE.
23 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType"]/*' />
24 [Serializable]
25 public enum GCHandleType
26 {
27 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Weak"]/*' />
28 Weak = 0,
29 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.WeakTrackResurrection"]/*' />
30 WeakTrackResurrection = 1,
31 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Normal"]/*' />
32 Normal = 2,
33 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandleType.Pinned"]/*' />
34 Pinned = 3
35 }
36
37 // This class allows you to create an opaque, GC handle to any
38 // COM+ object. A GC handle is used when an object reference must be
39 // reachable from unmanaged memory. There are 3 kinds of roots:
40 // Normal - keeps the object from being collected.
41 // Weak - allows object to be collected and handle contents will be zeroed.
42 // Weak references are zeroed before the finalizer runs, so if the
43 // object is resurrected in the finalizer the weak reference is
44 // still zeroed.
45 // WeakTrackResurrection - Same as weak, but stays until after object is
46 // really gone.
47 // Pinned - same as normal, but allows the address of the actual object
48 // to be taken.
49 //
50 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle"]/*' />
51 [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
52 public struct GCHandle
53 {
54 // Allocate a handle storing the object and the type.
55 internal GCHandle(Object value, GCHandleType type)
56 {
57 m_handle = InternalAlloc(value, type);
58
59 // Record if the handle is pinned.
60 if (type == GCHandleType.Pinned)
61 SetIsPinned();
62 }
63
64 // Used in the conversion functions below.
65 internal GCHandle(IntPtr handle)
66 {
67 InternalCheckDomain(handle);
68 m_handle = handle;
69 }
70
71 // Creates a new GC handle for an object.
72 //
73 // value - The object that the GC handle is created for.
74 // type - The type of GC handle to create.
75 //
76 // returns a new GC handle that protects the object.
77 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Alloc"]/*' />
78 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
79 public static GCHandle Alloc(Object value)
80 {
81 return new GCHandle(value, GCHandleType.Normal);
82 }
83
84 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Alloc1"]/*' />
85 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
86 public static GCHandle Alloc(Object value, GCHandleType type)
87 {
88 return new GCHandle(value, type);
89 }
90
91 // Frees a GC handle. The caller must provide synchronization to
92 // prevent multiple threads from executing this simultaneously for
93 // a given handle. If you modify this method please modify the
94 // __InternalFree also which is the internal without the linktime check.
95 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Free"]/*' />
96 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
97 public void Free()
98 {
99 // Check if the handle was never initialized for was freed.
100 if (m_handle == IntPtr.Zero)
101 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
102
103 // Free the handle.
104 InternalFree(GetHandleValue());
105 m_handle = IntPtr.Zero;
106 }
107
108 internal void __InternalFree()
109 {
110 // Check if the handle was never initialized for was freed.
111 if (m_handle == IntPtr.Zero)
112 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
113
114 // Free the handle.
115 InternalFree(GetHandleValue());
116 m_handle = IntPtr.Zero;
117 }
118
119 // Target property - allows getting / updating of the handle's referent. If you modify this method
120
121 // then modify the __InternalTarget too which is the internal method without the linktime check.
122 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.Target"]/*' />
123 public Object Target
124 {
125 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
126 get
127 {
128 // Check if the handle was never initialized or was freed.
129 if (m_handle == IntPtr.Zero)
130 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
131
132 return InternalGet(GetHandleValue());
133 }
134
135 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
136 set
137 {
138 // Check if the handle was never initialized or was freed.
139 if (m_handle == IntPtr.Zero)
140 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
141
142 InternalSet(GetHandleValue(), value, IsPinned());
143 }
144 }
145
146 internal Object __InternalTarget
147 {
148 get
149 {
150 // Check if the handle was never initialized or was freed.
151 if (m_handle == IntPtr.Zero)
152 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
153
154 return InternalGet(GetHandleValue());
155 }
156 }
157
158 // Retrieve the address of an object in a Pinned handle. This throws
159 // an exception if the handle is any type other than Pinned.
160 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.AddrOfPinnedObject"]/*' />
161 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
162 public IntPtr AddrOfPinnedObject()
163 {
164 // Check if the handle was not a pinned handle.
165 if (!IsPinned())
166 {
167 // Check if the handle was never initialized for was freed.
168 if (m_handle == IntPtr.Zero)
169 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
170
171 // You can only get the address of pinned handles.
172 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotPinned"));
173 }
174
175 // Get the address.
176 return InternalAddrOfPinnedObject(GetHandleValue());
177 }
178
179 // Determine whether this handle has been allocated or not.
180 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.IsAllocated"]/*' />
181 public bool IsAllocated
182 {
183 get
184 {
185 return m_handle != IntPtr.Zero;
186 }
187 }
188
189 // Used to create a GCHandle from an int. This is intended to
190 // be used with the reverse conversion.
191 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.operatorGCHandle"]/*' />
192 [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
193 public static explicit operator GCHandle(IntPtr value)
194 {
195 return new GCHandle(value);
196 }
197
198 // Used to get the internal integer representation of the handle out.
199 /// <include file='doc\GcHandle.uex' path='docs/doc[@for="GCHandle.operatorIntPtr"]/*' />
200 public static explicit operator IntPtr(GCHandle value)
201 {
202 return value.m_handle;
203 }
204
205 internal IntPtr GetHandleValue()
206 {
207#if WIN32
208 return new IntPtr(((int)m_handle) & ~1);
209#else
210 return new IntPtr(((long)m_handle) & ~1L);
211#endif
212 }
213
214 internal bool IsPinned()
215 {
216#if WIN32
217 return (((int)m_handle) & 1) != 0;
218#else
219 return (((long)m_handle) & 1) != 0;
220#endif
221 }
222
223 internal void SetIsPinned()
224 {
225#if WIN32
226 m_handle = new IntPtr(((int)m_handle) | 1);
227#else
228 m_handle = new IntPtr(((long)m_handle) | 1L);
229#endif
230 }
231
232 // Internal native calls that this implementation uses.
233 [MethodImplAttribute(MethodImplOptions.InternalCall)]
234 internal static extern IntPtr InternalAlloc(Object value, GCHandleType type);
235 [MethodImplAttribute(MethodImplOptions.InternalCall)]
236 internal static extern void InternalFree(IntPtr handle);
237 [MethodImplAttribute(MethodImplOptions.InternalCall)]
238 internal static extern Object InternalGet(IntPtr handle);
239 [MethodImplAttribute(MethodImplOptions.InternalCall)]
240 internal static extern void InternalSet(IntPtr handle, Object value, bool isPinned);
241 [MethodImplAttribute(MethodImplOptions.InternalCall)]
242 internal static extern void InternalCompareExchange(IntPtr handle, Object value, Object oldValue, bool isPinned);
243 [MethodImplAttribute(MethodImplOptions.InternalCall)]
244 internal static extern IntPtr InternalAddrOfPinnedObject(IntPtr handle);
245 [MethodImplAttribute(MethodImplOptions.InternalCall)]
246 internal static extern void InternalCheckDomain(IntPtr handle);
247
248
249 // The actual integer handle value that the EE uses internally.
250 private IntPtr m_handle;
251 }
252}
253
254