Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / clr / src / BCL / System / Runtime / InteropServices / SafePointer.cs / 1 / SafePointer.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Purpose: Unsafe code that uses pointers should use ** SafePointer to fix subtle lifetime problems with the ** underlying resource. ** ===========================================================*/ // Design points: // *) Avoid handle-recycling problems (including ones triggered via // resurrection attacks) for all accesses via pointers. This requires tying // together the lifetime of the unmanaged resource with the code that reads // from that resource, in a package that uses synchronization to enforce // the correct semantics during finalization. We're using SafeHandle's // ref count as a gate on whether the pointer can be dereferenced because that // controls the lifetime of the resource. // // *) Keep the penalties for using this class small, both in terms of space // and time. Having multiple threads reading from a memory mapped file // will already require 2 additional interlocked operations. If we add in // a "current position" concept, that requires additional space in memory and // synchronization. Since the position in memory is often (but not always) // something that can be stored on the stack, we can save some memory by // excluding it from this object. However, avoiding the need for // synchronization is a more significant win. This design allows multiple // threads to read and write memory simultaneously without locks (as long as // you don't write to a region of memory that overlaps with what another // thread is accessing). // // *) Space-wise, we use the following memory, including SafeHandle's fields: // Object Header MT* handle int bool bool <2 pad bytes> length // On 32 bit platforms: 24 bytes. On 64 bit platforms: 40 bytes. // (We can safe 4 bytes on x86 only by shrinking SafeHandle) // // *) Wrapping a SafeHandle would have been a nice solution, but without an // ordering between critical finalizable objects, it would have required // changes to each SafeHandle subclass to opt in to being usable from a // SafePointer (or some clever exposure of SafeHandle's state fields and a // way of forcing ReleaseHandle to run even after the SafeHandle has been // finalized with a ref count > 1). We can use less memory and create fewer // objects by simply inserting a SafePointer into the class hierarchy. // // *) In an ideal world, we could get marshaling support for SafePointer that // would allow us to annotate a P/Invoke declaration, saying this parameter // specifies the length of the buffer, and the units of that length are X. // P/Invoke would then pass that size parameter to SafePointer. // [DllImport(...)] // static extern SafeMemoryHandle AllocCharBuffer(int numChars); // If we could put an attribute on the SafeMemoryHandle saying numChars is // the element length, and it must be multiplied by 2 to get to the byte // length, we can simplify the usage model for SafePointer. // // *) This class could benefit from a constraint saying T is a value type // containing no GC references. // Implementation notes: // *) The Initialize method must be called before you use any instance of // a SafePointer. To avoid ----s when storing SafePointers in statics, // you either need to take a lock when publishing the SafePointer, or you // need to create a local, initialize the SafePointer, then assign to the // static variable (perhaps using Interlocked.CompareExchange). Of course, // assignments in a static class constructor are under a lock implicitly. using System; using System.Security.Permissions; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Runtime.Versioning; using Microsoft.Win32.SafeHandles; namespace System.Runtime.InteropServices { [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)] internal abstract unsafe class SafePointer : SafeHandleZeroOrMinusOneIsInvalid { // Steal UIntPtr.MaxValue as our uninitialized value. private static readonly UIntPtr Uninitialized = (UIntPtr.Size == 4) ? ((UIntPtr) UInt32.MaxValue) : ((UIntPtr) UInt64.MaxValue); private UIntPtr _numBytes; protected SafePointer(bool ownsHandle) : base(ownsHandle) { _numBytes = Uninitialized; } ////// Specifies the size of the region of memory, in bytes. Must be /// called before using the SafePointer. /// /// Number of valid bytes in memory. //[CLSCompliant(false)] public void Initialize(ulong numBytes) { if (numBytes < 0) throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (IntPtr.Size == 4 && numBytes > UInt32.MaxValue) throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_AddressSpace")); if (numBytes >= (ulong) Uninitialized) throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_UIntPtrMax-1")); _numBytes = (UIntPtr) numBytes; } ////// Specifies the the size of the region in memory, as the number of /// elements in an array. Must be called before using the SafePointer. /// //[CLSCompliant(false)] public void Initialize(uint numElements, uint sizeOfEachElement) { if (numElements < 0) throw new ArgumentOutOfRangeException("numElements", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (sizeOfEachElement < 0) throw new ArgumentOutOfRangeException("sizeOfEachElement", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (IntPtr.Size == 4 && numElements * sizeOfEachElement > UInt32.MaxValue) throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_AddressSpace")); if (numElements * sizeOfEachElement >= (ulong)Uninitialized) throw new ArgumentOutOfRangeException("numElements", Environment.GetResourceString("ArgumentOutOfRange_UIntPtrMax-1")); _numBytes = checked((UIntPtr) (numElements * sizeOfEachElement)); } ////// Specifies the the size of the region in memory, as the number of /// elements in an array. Must be called before using the SafePointer. /// //[CLSCompliant(false)] public void Initialize(uint numElements) where T : struct { Initialize(numElements, SizeOf ()); } /// /// Returns the size of an instance of a value type. /// ///Provide a value type to figure out its size ///The size of T in bytes. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static uint SizeOf() where T : struct { return SizeOfType(typeof(T)); } // Callers should ensure that they check whether the pointer ref param // is null when AcquirePointer returns. If it is not null, they must // call ReleasePointer in a CER. This method calls DangerousAddRef // & exposes the pointer. Unlike Read, it does not alter the "current // position" of the pointer. Here's how to use it: // // byte* pointer = null; // RuntimeHelpers.PrepareConstrainedRegions(); // try { // safePointer.AcquirePointer(ref pointer); // // Use pointer here, with your own bounds checking // } // finally { // if (pointer != null) // safePointer.ReleasePointer(); // } // // Note: If you cast this byte* to a T*, you have to worry about // whether your pointer is aligned. Additionally, you must take // responsibility for all bounds checking with this pointer. /// /// Obtain the pointer from a SafePointer for a block of code, /// with the express responsibility for bounds checking and calling /// ReleasePointer later within a CER to ensure the pointer can be /// freed later. This method either completes successfully or /// throws an exception and returns with pointer set to null. /// /// A byte*, passed by reference, to receive /// the pointer from within the SafePointer. You must set /// pointer to null before calling this method. //[CLSCompliant(false)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public void AcquirePointer(ref byte* pointer) { if (_numBytes == Uninitialized) throw NotInitialized(); pointer = null; RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { bool junk = false; DangerousAddRef(ref junk); pointer = (byte*)handle; } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public void ReleasePointer() { if (_numBytes == Uninitialized) throw NotInitialized(); DangerousRelease(); } ////// Read a value type from memory at the given offset. This is /// equivalent to: return *(T*)(bytePtr + byteOffset); /// ///The value type to read /// Where to start reading from memory. You /// may have to consider alignment. ///An instance of T read from memory. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public T Read(uint byteOffset) where T : struct { if (_numBytes == Uninitialized) throw NotInitialized(); uint sizeofT = SizeOf (); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, sizeofT); // return *(T*) (_ptr + byteOffset); T value; bool mustCallRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustCallRelease); GenericPtrToStructure (ptr, out value, sizeofT); } finally { if (mustCallRelease) DangerousRelease(); } return value; } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public void ReadArray (uint byteOffset, T[] array, int index, int count) where T : struct { if (array == null) throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer")); if (index < 0) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (array.Length - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); if (_numBytes == Uninitialized) throw NotInitialized(); uint sizeofT = SizeOf (); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, checked((ulong) (sizeofT * count))); bool mustCallRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustCallRelease); for (int i = 0; i < count; i++) unsafe { GenericPtrToStructure (ptr + sizeofT * i, out array[i + count], sizeofT); } } finally { if (mustCallRelease) DangerousRelease(); } } /// /// Write a value type to memory at the given offset. This is /// equivalent to: *(T*)(bytePtr + byteOffset) = value; /// ///The type of the value type to write to memory. /// The location in memory to write to. You /// may have to consider alignment. /// The value type to write to memory. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public void Write(uint byteOffset, T value) where T : struct { if (_numBytes == Uninitialized) throw NotInitialized(); uint sizeofT = SizeOf (); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, sizeofT); // *((T*) (_ptr + byteOffset)) = value; bool mustCallRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustCallRelease); GenericStructureToPtr(ref value, ptr, sizeofT); } finally { if (mustCallRelease) DangerousRelease(); } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public void WriteArray (uint byteOffset, T[] array, int index, int count) where T : struct { if (array == null) throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer")); if (index < 0) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (array.Length - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); if (_numBytes == Uninitialized) throw NotInitialized(); uint sizeofT = SizeOf (); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, checked((ulong)(sizeofT * count))); bool mustCallRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustCallRelease); for (int i = 0; i < count; i++) unsafe { GenericStructureToPtr(ref array[i + count], ptr + sizeofT * i, sizeofT); } } finally { if (mustCallRelease) DangerousRelease(); } } /// /// Returns the number of bytes in the memory region. /// public ulong ByteLength { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get { if (_numBytes == Uninitialized) throw NotInitialized(); return (ulong) _numBytes; } } /* No indexer. The perf would be misleadingly bad. People should use * AcquirePointer and ReleasePointer instead. */ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private void SpaceCheck(byte* ptr, ulong sizeInBytes) { if ((ulong)(ptr - (byte*) handle) > ((ulong)_numBytes) - sizeInBytes) NotEnoughRoom(); } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private static void NotEnoughRoom() { throw new ArgumentException(Environment.GetResourceString("Arg_BufferTooSmall")); } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private static InvalidOperationException NotInitialized() { BCLDebug.Assert(false, "Unintialized SafePointer! Someone needs to call Initialize before using this instance!"); return new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MustCallInitialize")); } // FCALL limitations mean we can't have generic FCALL methods. However, we can pass // TypedReferences to FCALL methods. private static void GenericPtrToStructure(byte* ptr, out T structure, uint sizeofT) where T : struct { structure = default(T); // Dummy assignment to silence the compiler PtrToStructureNative(ptr, __makeref(structure), sizeofT); } [MethodImpl(MethodImplOptions.InternalCall)] [ResourceExposure(ResourceScope.None)] private static extern void PtrToStructureNative(byte* ptr, /*out T*/ TypedReference structure, uint sizeofT); private static void GenericStructureToPtr (ref T structure, byte* ptr, uint sizeofT) where T : struct { StructureToPtrNative(__makeref(structure), ptr, sizeofT); } [MethodImpl(MethodImplOptions.InternalCall)] [ResourceExposure(ResourceScope.None)] private static extern void StructureToPtrNative(/*ref T*/ TypedReference structure, byte* ptr, uint sizeofT); // Type must be a value type with no object reference fields. We only // assert this, due to the lack of a suitable generic constraint. [MethodImpl(MethodImplOptions.InternalCall)] [ResourceExposure(ResourceScope.None)] private static extern uint SizeOfType(Type type); } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================ ** ** Purpose: Unsafe code that uses pointers should use ** SafePointer to fix subtle lifetime problems with the ** underlying resource. ** ===========================================================*/ // Design points: // *) Avoid handle-recycling problems (including ones triggered via // resurrection attacks) for all accesses via pointers. This requires tying // together the lifetime of the unmanaged resource with the code that reads // from that resource, in a package that uses synchronization to enforce // the correct semantics during finalization. We're using SafeHandle's // ref count as a gate on whether the pointer can be dereferenced because that // controls the lifetime of the resource. // // *) Keep the penalties for using this class small, both in terms of space // and time. Having multiple threads reading from a memory mapped file // will already require 2 additional interlocked operations. If we add in // a "current position" concept, that requires additional space in memory and // synchronization. Since the position in memory is often (but not always) // something that can be stored on the stack, we can save some memory by // excluding it from this object. However, avoiding the need for // synchronization is a more significant win. This design allows multiple // threads to read and write memory simultaneously without locks (as long as // you don't write to a region of memory that overlaps with what another // thread is accessing). // // *) Space-wise, we use the following memory, including SafeHandle's fields: // Object Header MT* handle int bool bool <2 pad bytes> length // On 32 bit platforms: 24 bytes. On 64 bit platforms: 40 bytes. // (We can safe 4 bytes on x86 only by shrinking SafeHandle) // // *) Wrapping a SafeHandle would have been a nice solution, but without an // ordering between critical finalizable objects, it would have required // changes to each SafeHandle subclass to opt in to being usable from a // SafePointer (or some clever exposure of SafeHandle's state fields and a // way of forcing ReleaseHandle to run even after the SafeHandle has been // finalized with a ref count > 1). We can use less memory and create fewer // objects by simply inserting a SafePointer into the class hierarchy. // // *) In an ideal world, we could get marshaling support for SafePointer that // would allow us to annotate a P/Invoke declaration, saying this parameter // specifies the length of the buffer, and the units of that length are X. // P/Invoke would then pass that size parameter to SafePointer. // [DllImport(...)] // static extern SafeMemoryHandle AllocCharBuffer(int numChars); // If we could put an attribute on the SafeMemoryHandle saying numChars is // the element length, and it must be multiplied by 2 to get to the byte // length, we can simplify the usage model for SafePointer. // // *) This class could benefit from a constraint saying T is a value type // containing no GC references. // Implementation notes: // *) The Initialize method must be called before you use any instance of // a SafePointer. To avoid ----s when storing SafePointers in statics, // you either need to take a lock when publishing the SafePointer, or you // need to create a local, initialize the SafePointer, then assign to the // static variable (perhaps using Interlocked.CompareExchange). Of course, // assignments in a static class constructor are under a lock implicitly. using System; using System.Security.Permissions; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Runtime.Versioning; using Microsoft.Win32.SafeHandles; namespace System.Runtime.InteropServices { [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)] internal abstract unsafe class SafePointer : SafeHandleZeroOrMinusOneIsInvalid { // Steal UIntPtr.MaxValue as our uninitialized value. private static readonly UIntPtr Uninitialized = (UIntPtr.Size == 4) ? ((UIntPtr) UInt32.MaxValue) : ((UIntPtr) UInt64.MaxValue); private UIntPtr _numBytes; protected SafePointer(bool ownsHandle) : base(ownsHandle) { _numBytes = Uninitialized; } /// /// Specifies the size of the region of memory, in bytes. Must be /// called before using the SafePointer. /// /// Number of valid bytes in memory. //[CLSCompliant(false)] public void Initialize(ulong numBytes) { if (numBytes < 0) throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (IntPtr.Size == 4 && numBytes > UInt32.MaxValue) throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_AddressSpace")); if (numBytes >= (ulong) Uninitialized) throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_UIntPtrMax-1")); _numBytes = (UIntPtr) numBytes; } ////// Specifies the the size of the region in memory, as the number of /// elements in an array. Must be called before using the SafePointer. /// //[CLSCompliant(false)] public void Initialize(uint numElements, uint sizeOfEachElement) { if (numElements < 0) throw new ArgumentOutOfRangeException("numElements", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (sizeOfEachElement < 0) throw new ArgumentOutOfRangeException("sizeOfEachElement", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (IntPtr.Size == 4 && numElements * sizeOfEachElement > UInt32.MaxValue) throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_AddressSpace")); if (numElements * sizeOfEachElement >= (ulong)Uninitialized) throw new ArgumentOutOfRangeException("numElements", Environment.GetResourceString("ArgumentOutOfRange_UIntPtrMax-1")); _numBytes = checked((UIntPtr) (numElements * sizeOfEachElement)); } ////// Specifies the the size of the region in memory, as the number of /// elements in an array. Must be called before using the SafePointer. /// //[CLSCompliant(false)] public void Initialize(uint numElements) where T : struct { Initialize(numElements, SizeOf ()); } /// /// Returns the size of an instance of a value type. /// ///Provide a value type to figure out its size ///The size of T in bytes. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public static uint SizeOf() where T : struct { return SizeOfType(typeof(T)); } // Callers should ensure that they check whether the pointer ref param // is null when AcquirePointer returns. If it is not null, they must // call ReleasePointer in a CER. This method calls DangerousAddRef // & exposes the pointer. Unlike Read, it does not alter the "current // position" of the pointer. Here's how to use it: // // byte* pointer = null; // RuntimeHelpers.PrepareConstrainedRegions(); // try { // safePointer.AcquirePointer(ref pointer); // // Use pointer here, with your own bounds checking // } // finally { // if (pointer != null) // safePointer.ReleasePointer(); // } // // Note: If you cast this byte* to a T*, you have to worry about // whether your pointer is aligned. Additionally, you must take // responsibility for all bounds checking with this pointer. /// /// Obtain the pointer from a SafePointer for a block of code, /// with the express responsibility for bounds checking and calling /// ReleasePointer later within a CER to ensure the pointer can be /// freed later. This method either completes successfully or /// throws an exception and returns with pointer set to null. /// /// A byte*, passed by reference, to receive /// the pointer from within the SafePointer. You must set /// pointer to null before calling this method. //[CLSCompliant(false)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public void AcquirePointer(ref byte* pointer) { if (_numBytes == Uninitialized) throw NotInitialized(); pointer = null; RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { bool junk = false; DangerousAddRef(ref junk); pointer = (byte*)handle; } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public void ReleasePointer() { if (_numBytes == Uninitialized) throw NotInitialized(); DangerousRelease(); } ////// Read a value type from memory at the given offset. This is /// equivalent to: return *(T*)(bytePtr + byteOffset); /// ///The value type to read /// Where to start reading from memory. You /// may have to consider alignment. ///An instance of T read from memory. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public T Read(uint byteOffset) where T : struct { if (_numBytes == Uninitialized) throw NotInitialized(); uint sizeofT = SizeOf (); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, sizeofT); // return *(T*) (_ptr + byteOffset); T value; bool mustCallRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustCallRelease); GenericPtrToStructure (ptr, out value, sizeofT); } finally { if (mustCallRelease) DangerousRelease(); } return value; } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public void ReadArray (uint byteOffset, T[] array, int index, int count) where T : struct { if (array == null) throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer")); if (index < 0) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (array.Length - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); if (_numBytes == Uninitialized) throw NotInitialized(); uint sizeofT = SizeOf (); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, checked((ulong) (sizeofT * count))); bool mustCallRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustCallRelease); for (int i = 0; i < count; i++) unsafe { GenericPtrToStructure (ptr + sizeofT * i, out array[i + count], sizeofT); } } finally { if (mustCallRelease) DangerousRelease(); } } /// /// Write a value type to memory at the given offset. This is /// equivalent to: *(T*)(bytePtr + byteOffset) = value; /// ///The type of the value type to write to memory. /// The location in memory to write to. You /// may have to consider alignment. /// The value type to write to memory. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public void Write(uint byteOffset, T value) where T : struct { if (_numBytes == Uninitialized) throw NotInitialized(); uint sizeofT = SizeOf (); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, sizeofT); // *((T*) (_ptr + byteOffset)) = value; bool mustCallRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustCallRelease); GenericStructureToPtr(ref value, ptr, sizeofT); } finally { if (mustCallRelease) DangerousRelease(); } } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] public void WriteArray (uint byteOffset, T[] array, int index, int count) where T : struct { if (array == null) throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer")); if (index < 0) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (count < 0) throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); if (array.Length - index < count) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen")); if (_numBytes == Uninitialized) throw NotInitialized(); uint sizeofT = SizeOf (); byte* ptr = (byte*)handle + byteOffset; SpaceCheck(ptr, checked((ulong)(sizeofT * count))); bool mustCallRelease = false; RuntimeHelpers.PrepareConstrainedRegions(); try { DangerousAddRef(ref mustCallRelease); for (int i = 0; i < count; i++) unsafe { GenericStructureToPtr(ref array[i + count], ptr + sizeofT * i, sizeofT); } } finally { if (mustCallRelease) DangerousRelease(); } } /// /// Returns the number of bytes in the memory region. /// public ulong ByteLength { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get { if (_numBytes == Uninitialized) throw NotInitialized(); return (ulong) _numBytes; } } /* No indexer. The perf would be misleadingly bad. People should use * AcquirePointer and ReleasePointer instead. */ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private void SpaceCheck(byte* ptr, ulong sizeInBytes) { if ((ulong)(ptr - (byte*) handle) > ((ulong)_numBytes) - sizeInBytes) NotEnoughRoom(); } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private static void NotEnoughRoom() { throw new ArgumentException(Environment.GetResourceString("Arg_BufferTooSmall")); } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private static InvalidOperationException NotInitialized() { BCLDebug.Assert(false, "Unintialized SafePointer! Someone needs to call Initialize before using this instance!"); return new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MustCallInitialize")); } // FCALL limitations mean we can't have generic FCALL methods. However, we can pass // TypedReferences to FCALL methods. private static void GenericPtrToStructure(byte* ptr, out T structure, uint sizeofT) where T : struct { structure = default(T); // Dummy assignment to silence the compiler PtrToStructureNative(ptr, __makeref(structure), sizeofT); } [MethodImpl(MethodImplOptions.InternalCall)] [ResourceExposure(ResourceScope.None)] private static extern void PtrToStructureNative(byte* ptr, /*out T*/ TypedReference structure, uint sizeofT); private static void GenericStructureToPtr (ref T structure, byte* ptr, uint sizeofT) where T : struct { StructureToPtrNative(__makeref(structure), ptr, sizeofT); } [MethodImpl(MethodImplOptions.InternalCall)] [ResourceExposure(ResourceScope.None)] private static extern void StructureToPtrNative(/*ref T*/ TypedReference structure, byte* ptr, uint sizeofT); // Type must be a value type with no object reference fields. We only // assert this, due to the lack of a suitable generic constraint. [MethodImpl(MethodImplOptions.InternalCall)] [ResourceExposure(ResourceScope.None)] private static extern uint SizeOfType(Type type); } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WorkflowView.cs
- ZipFileInfoCollection.cs
- CodePropertyReferenceExpression.cs
- DataRowView.cs
- ToolStripItem.cs
- TransformProviderWrapper.cs
- XamlStream.cs
- MultiDataTrigger.cs
- WizardPanel.cs
- ComponentDispatcherThread.cs
- ConfigXmlSignificantWhitespace.cs
- WorkflowCompensationBehavior.cs
- IOException.cs
- MultiViewDesigner.cs
- RedBlackList.cs
- FrugalList.cs
- ImmutableObjectAttribute.cs
- PropertyValueChangedEvent.cs
- ConfigXmlWhitespace.cs
- TypeSystemHelpers.cs
- ProfessionalColors.cs
- RectIndependentAnimationStorage.cs
- wgx_commands.cs
- SmiXetterAccessMap.cs
- MenuBase.cs
- PerfCounters.cs
- ProfessionalColors.cs
- XmlAttributeOverrides.cs
- ToolConsole.cs
- SspiWrapper.cs
- ParseHttpDate.cs
- SqlXmlStorage.cs
- MsmqElementBase.cs
- FocusManager.cs
- Bits.cs
- LineServicesCallbacks.cs
- PersonalizablePropertyEntry.cs
- DelegatedStream.cs
- CustomErrorsSection.cs
- DataGridViewCellToolTipTextNeededEventArgs.cs
- ClassHandlersStore.cs
- HelloMessage11.cs
- HeaderedContentControl.cs
- GeometryCollection.cs
- RotationValidation.cs
- HyperLinkColumn.cs
- RegexParser.cs
- shaperfactoryquerycacheentry.cs
- SelectionListComponentEditor.cs
- MarkupCompilePass2.cs
- XmlValidatingReaderImpl.cs
- ErrorStyle.cs
- SmiEventSink.cs
- TypeDefinition.cs
- LongSumAggregationOperator.cs
- CodeTypeDeclaration.cs
- WebServiceData.cs
- RecognizerBase.cs
- FakeModelPropertyImpl.cs
- WorkerRequest.cs
- TextDecorationCollection.cs
- EqualityComparer.cs
- DeferredReference.cs
- SecurityState.cs
- IPAddressCollection.cs
- PlaceHolder.cs
- TextBox.cs
- ValidationEventArgs.cs
- IIS7UserPrincipal.cs
- XmlEventCache.cs
- columnmapkeybuilder.cs
- _ListenerAsyncResult.cs
- ImageMapEventArgs.cs
- View.cs
- KeyValueConfigurationCollection.cs
- HttpCachePolicyElement.cs
- UriSection.cs
- Point3DCollection.cs
- CompositeKey.cs
- VerificationException.cs
- ManagedIStream.cs
- input.cs
- StaticFileHandler.cs
- ToolboxDataAttribute.cs
- XmlWrappingReader.cs
- PerformanceCounterPermissionEntry.cs
- SyndicationItem.cs
- TokenizerHelper.cs
- ValueTypePropertyReference.cs
- SamlAssertionDirectKeyIdentifierClause.cs
- ResolveNameEventArgs.cs
- Repeater.cs
- ControllableStoryboardAction.cs
- ExpandedProjectionNode.cs
- NullReferenceException.cs
- BezierSegment.cs
- WebPartConnectionsConnectVerb.cs
- FlowDocumentFormatter.cs
- SignedXml.cs
- CorrelationValidator.cs