using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
///
/// Static core class providing tools for manipulating threads.
///
public static class ThreadCore
{ #region GetThreadContext
///
/// Retrieves the context of the specified thread.
///
/// The type of the context to dump.
/// The type must be unmanaged, so it can be fixed while the native call is done.
/// The performance is increased if the structure is blittable, which is the case for the structures
/// provided with the library.
/// A handle to the thread whose context is to be retrieved.
/// An instance of the structure where the context is loaded into.
/// The context cannot be retrieved from the thread.
public static unsafe void GetThreadContext(SafeMemoryHandle threadHandle, ref TContext context)
where TContext : unmanaged
{
// Check if the handle is valid
HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle");
// Get the pointer of the structure and pin it, so the GC does not move it
fixed (void* contextPtr = &context)
{
// Get the thread context
if (NativeMethods.GetThreadContext(threadHandle, contextPtr) == (void*)0)
{
throw new Win32Exception("The context cannot be retrieved from the thread.");
}
}
}
#endregion
#region NtQueryInformationThread
///
/// Retrieves information about the specified thread.
///
/// A handle to the thread to query.
/// A structure containing thread information.
public static unsafe ThreadBasicInformation NtQueryInformationThread(SafeMemoryHandle threadHandle)
{
// Check if the handle is valid
HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle");
// Create a structure to store thread info
var info = new ThreadBasicInformation();
// Get the thread info
void* infoPtr = &info; // info is already fixed
var ret = NativeMethods.NtQueryInformationThread(threadHandle, ThreadInformationClass.ThreadBasicInformation,
infoPtr, MarshalType.SizeAsPointer, out var returnLength);
// If the function succeeded
if (ret == 0)
{
return info;
}
// Else, couldn't get the thread info, throws an exception
throw new ApplicationException($"The thread information cannot be queried; error code '{ret}'.");
}
///
/// Retrieves information about the specified thread.
///
/// A handle to the thread to query.
/// The class of the thread to retrieve.
/// The requested data as an unsigned integer.
public static unsafe ulong NtQueryInformationThread(SafeMemoryHandle threadHandle, ThreadInformationClass threadInformationClass)
{
// Check if the handle is valid
HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle");
// Get the thread info
ulong info = 0;
var ret = NativeMethods.NtQueryInformationThread(threadHandle, ThreadInformationClass.ThreadBasicInformation,
&info, new IntPtr(sizeof(ulong)), out var returnLength);
// If the function succeeded
if (ret == 0)
{
return info;
}
// Else, couldn't get the thread info, throws an exception
throw new ApplicationException($"The thread information cannot be queried; error code '{ret}'.");
}
#endregion
#region ResumeThread
///
/// Decrements a thread's suspend count. When the suspend count is decremented to zero, the execution of the thread is resumed.
///
/// A handle to the thread to be restarted.
/// The thread's previous suspend count.
public static uint ResumeThread(SafeMemoryHandle threadHandle)
{
// Check if the handle is valid
HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle");
// Resume the thread
var ret = NativeMethods.ResumeThread(threadHandle);
// If the function failed
if (ret == uint.MaxValue)
throw new Win32Exception("Couldn't resume the thread.");
return ret;
}
#endregion
#region SetThreadContext
///
/// Sets the context for the specified thread.
///
/// The type of the context to set.
/// The type must be unmanaged, so it can be fixed while the native call is done.
/// The performance is increased if the structure is blittable, which is the case for the structures
/// provided with the library.
/// A handle to the thread whose context is to be set.
/// A pointer to a structure that contains the context to be set in the specified thread.
/// The context cannot be set to the thread.
public static unsafe void SetThreadContext(SafeMemoryHandle threadHandle, ref TContext context)
where TContext : unmanaged
{
// Check if the handle is valid
HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle");
// Get the pointer of the structure and pin it, so the GC does not move it
fixed (void* contextPtr = &context)
{
// Set the thread context
if (NativeMethods.SetThreadContext(threadHandle, contextPtr) == 0)
{
throw new Win32Exception("The context cannot be set to the thread.");
}
}
}
#endregion
#region SuspendThread
///
/// Suspends the specified thread.
///
/// A handle to the thread that is to be suspended.
/// The thread's previous suspend count.
public static uint SuspendThread(SafeMemoryHandle threadHandle)
{
// Check if the handle is valid
HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle");
// Suspend the thread
var ret = NativeMethods.SuspendThread(threadHandle);
// If the function failed
if (ret == uint.MaxValue)
throw new Win32Exception("Couldn't suspend the thread.");
return ret;
}
#endregion
#region TerminateThread
///
/// Terminates a thread.
///
/// A handle to the thread to be terminated.
/// The exit code for the thread.
public static void TerminateThread(SafeMemoryHandle threadHandle, int exitCode)
{
// Check if the handle is valid
HandleManipulator.ValidateAsArgument(threadHandle, "threadHandle");
// Terminate the thread
var ret = NativeMethods.TerminateThread(threadHandle, exitCode);
// If the function failed
if(!ret)
throw new Win32Exception("Couldn't terminate the thread.");
}
#endregion
#region ThreadContextFlags
///
/// Determines which registers are returned or set when using or .
///
[Flags]
public enum ThreadContextFlags : uint
{
///
/// The Intel 80386 microprocessor, also known as the i386.
///
Intel386 = 0x10000,
///
/// The Intel 80486 microprocessor, also known as the i486.
///
Intel486 = 0x10000,
///
/// SS:SP, CS:IP, FLAGS, BP
///
Control = Intel386 | 0x01,
///
/// AX, BX, CX, DX, SI, DI
///
Integer = Intel386 | 0x02,
///
/// DS, ES, FS, GS
///
Segments = Intel386 | 0x04,
///
/// 387 state
///
FloatingPoint = Intel386 | 0x08,
///
/// DB 0-3,6,7
///
DebugRegisters = Intel386 | 0x10,
///
/// CPU specific extensions
///
ExtendedRegisters = Intel386 | 0x20,
///
/// All flags excepted FloatingPoint, DebugRegisters and ExtendedRegisters.
///
Full = Control | Integer | Segments,
///
/// All flags.
///
All = Control | Integer | Segments | FloatingPoint | DebugRegisters | ExtendedRegisters
}
#endregion
#region ThreadInformationClass
///
///The numeration that corresponds to the classes of thread information.
///
public enum ThreadInformationClass : uint
{
ThreadBasicInformation = 0,
ThreadTimes = 1,
ThreadPriority = 2,
ThreadBasePriority = 3,
ThreadAffinityMask = 4,
ThreadImpersonationToken = 5,
ThreadDescriptorTableEntry = 6,
ThreadEnableAlignmentFaultFixup = 7,
ThreadEventPair_Reusable = 8,
ThreadQuerySetWin32StartAddress = 9,
ThreadZeroTlsCell = 10,
ThreadPerformanceCount = 11,
ThreadAmILastThread = 12,
ThreadIdealProcessor = 13,
ThreadPriorityBoost = 14,
ThreadSetTlsArrayAddress = 15,
ThreadIsIoPending = 16,
ThreadHideFromDebugger = 17,
ThreadBreakOnTermination = 18,
ThreadSwitchLegacyState = 19,
ThreadIsTerminated = 20,
ThreadLastSystemCall = 21,
ThreadIoPriority = 22,
ThreadCycleTime = 23,
ThreadPagePriority = 24,
ThreadActualBasePriority = 25,
ThreadTebInformation = 26,
ThreadCSwitchMon = 27,
ThreadCSwitchPmu = 28,
ThreadWow64Context = 29,
ThreadGroupInformation = 30,
ThreadUmsInformation = 31,
ThreadCounterProfiling = 32,
ThreadIdealProcessorEx = 33,
ThreadCpuAccountingInformation = 34,
ThreadSuspendCount = 35,
ThreadHeterogeneousCpuPolicy = 36,
ThreadContainerId = 37,
ThreadNameInformation = 38,
ThreadSelectedCpuSets = 39,
ThreadSystemThreadInformation = 40,
ThreadActualGroupAffinity = 41,
ThreadDynamicCodePolicyInfo = 42,
ThreadExplicitCaseSensitivity = 43,
ThreadWorkOnBehalfTicket = 44,
ThreadSubsystemInformation = 45,
ThreadDbgkWerReportActive = 46,
ThreadAttachContainer = 47,
ThreadManageWritesToExecutableMemory = 48,
ThreadPowerThrottlingState = 49,
ThreadWorkloadClass = 50,
}
#endregion
#region ProcessBasicInformation
///
/// Structure containing basic information about a process.
///
[StructLayout(LayoutKind.Sequential)]
public struct ProcessBasicInformation
{
///
/// The exit status.
///
public IntPtr ExitStatus;
///
/// The base address of Process Environment Block.
///
public IntPtr PebBaseAddress;
///
/// The affinity mask.
///
public IntPtr AffinityMask;
///
/// The base priority.
///
public IntPtr BasePriority;
///
/// The process id.
///
public IntPtr ProcessId;
///
/// The process id of the parent process.
///
public IntPtr InheritedFromUniqueProcessId;
}
#endregion ProcessBasicInformation
#region ThreadBasicInformation
///
/// Structure containing basic information about a thread.
///
[StructLayout(LayoutKind.Sequential)]
public struct ThreadBasicInformation
{
///
/// the exit status (NTSTATUS).
///
public uint ExitStatus;
///
/// The base address of Thread Environment Block.
///
public IntPtr TebBaseAddress;
///
/// The process and thread identifiers.
///
public ClientIdStruct ClientIdStruct;
///
/// The affinity mask.
///
public IntPtr AffinityMask;
///
/// The priority.
///
public int Priority;
///
/// The base priority.
///
public int BasePriority;
}
#endregion ThreadBasicInformation
#region ThreadContext32
///
/// Represents a thread context for 32-bit processes on Windows. Create a new instance using the constructor with the
/// flags.
///
///
/// This structure is blittable and therefore, does not require any marshaling from Platform Invoke.
/// Referenced on https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_wow64_context.
/// Refer to the header file WinNT.h for definitions of this structure for each processor architecture.
///
[StructLayout(LayoutKind.Explicit, Size = ThreadContext32Metadata.TotalSize)]
public unsafe struct ThreadContext32
{
///
/// Initializes a new instance of the struct.
///
/// Determines which registers are returned or set during the context query.
public ThreadContext32(ThreadContextFlags flags) : this()
{
ContextFlags = flags;
}
///
/// Determines which registers are returned or set when using or
/// .
/// If the context record is used as an INPUT parameter, then for each portion of the context record controlled by a flag
/// whose value is set, it is assumed that portion of the
/// context record contains valid context. If the context record is being used to modify a threads context, then only that
/// portion of the threads context will be modified.
/// If the context record is used as an INPUT/OUTPUT parameter to capture the context of a thread, then only those portions
/// of the thread's context corresponding to set flags will be returned.
/// The context record is never used as an OUTPUT only parameter.
///
[FieldOffset(ThreadContext32Metadata.Offsets.ContextFlags)]
public ThreadContextFlags ContextFlags;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Dr0)]
public uint Dr0;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Dr1)]
public uint Dr1;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Dr2)]
public uint Dr2;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Dr3)]
public uint Dr3;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Dr6)]
public uint Dr6;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Dr7)]
public uint Dr7;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.ControlWord)]
public uint ControlWord;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.StatusWord)]
public uint StatusWord;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.TagWord)]
public uint TagWord;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.ErrorOffset)]
public uint ErrorOffset;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.ErrorSelector)]
public uint ErrorSelector;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.DataOffset)]
public uint DataOffset;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.DataSelector)]
public uint DataSelector;
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.RegisterArea)]
public fixed byte RegisterArea[ThreadContext32Metadata.Sizes.RegisterAreaSize];
///
/// This is specified/returned if contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Cr0NpxState)]
public uint Cr0NpxState;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.SegGs)]
public uint SegGs;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.SegFs)]
public uint SegFs;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.SegEs)]
public uint SegEs;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.SegDs)]
public uint SegDs;
///
/// This register is specified/returned if the ContextFlags word contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Edi)]
public uint Edi;
///
/// This register is specified/returned if the ContextFlags word contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Esi)]
public uint Esi;
///
/// This register is specified/returned if the ContextFlags word contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Ebx)]
public uint Ebx;
///
/// This register is specified/returned if the ContextFlags word contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Edx)]
public uint Edx;
///
/// This register is specified/returned if the ContextFlags word contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Ecx)]
public uint Ecx;
///
/// This register is specified/returned if the ContextFlags word contains the flag
/// .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Eax)]
public uint Eax;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Ebp)]
public uint Ebp;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Eip)]
public uint Eip;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.SegCs)]
public uint SegCs;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.EFlags)]
public uint EFlags;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.Esp)]
public uint Esp;
///
/// This is specified/returned if contains the flag .
///
[FieldOffset(ThreadContext32Metadata.Offsets.SegSs)]
public uint SegSs;
///
/// This is specified/returned if contains the flag
/// .
/// The format and contexts are processor specific.
///
[FieldOffset(ThreadContext32Metadata.Offsets.ExtendedRegisters)]
public fixed byte ExtendedRegisters[ThreadContext32Metadata.Sizes.ExtendedRegistersSize];
}
#endregion ThreadContext32
#region ThreadContext64
///
/// Represents a thread context for 64-bit processes on Windows. Create a new instance using the constructor with the
/// flags.
///
///
/// This structure is blittable and therefore, does not require any marshaling from Platform Invoke.
/// Referenced on https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_context.
/// Refer to the header file WinNT.h for definitions of this structure for each processor architecture.
///
[StructLayout(LayoutKind.Explicit, Size = ThreadContext64Metadata.TotalSize)]
public unsafe struct ThreadContext64
{
///
/// Initializes a new instance of the struct.
///
/// Determines which registers are returned or set during the context query.
public ThreadContext64(ThreadContextFlags flags) : this()
{
ContextFlags = flags;
}
[FieldOffset(ThreadContext64Metadata.Offsets.P1Home)]
public ulong P1Home;
[FieldOffset(ThreadContext64Metadata.Offsets.P2Home)]
public ulong P2Home;
[FieldOffset(ThreadContext64Metadata.Offsets.P3Home)]
public ulong P3Home;
[FieldOffset(ThreadContext64Metadata.Offsets.P4Home)]
public ulong P4Home;
[FieldOffset(ThreadContext64Metadata.Offsets.P5Home)]
public ulong P5Home;
[FieldOffset(ThreadContext64Metadata.Offsets.P6Home)]
public ulong P6Home;
///
/// Determines which registers are returned or set when using or
/// .
/// If the context record is used as an INPUT parameter, then for each portion of the context record controlled by a flag
/// whose value is set, it is assumed that portion of the
/// context record contains valid context. If the context record is being used to modify a threads context, then only that
/// portion of the threads context will be modified.
/// If the context record is used as an INPUT/OUTPUT parameter to capture the context of a thread, then only those portions
/// of the thread's context corresponding to set flags will be returned.
/// The context record is never used as an OUTPUT only parameter.
///
[FieldOffset(ThreadContext64Metadata.Offsets.ContextFlags)]
public ThreadContextFlags ContextFlags;
[FieldOffset(ThreadContext64Metadata.Offsets.MxCsr)]
public uint MxCsr;
[FieldOffset(ThreadContext64Metadata.Offsets.SegCs)]
public ushort SegCs;
[FieldOffset(ThreadContext64Metadata.Offsets.SegDs)]
public ushort SegDs;
[FieldOffset(ThreadContext64Metadata.Offsets.SegEs)]
public ushort SegEs;
[FieldOffset(ThreadContext64Metadata.Offsets.SegFs)]
public ushort SegFs;
[FieldOffset(ThreadContext64Metadata.Offsets.SegGs)]
public ushort SegGs;
[FieldOffset(ThreadContext64Metadata.Offsets.SegSs)]
public ushort SegSs;
[FieldOffset(ThreadContext64Metadata.Offsets.EFlags)]
public uint EFlags;
[FieldOffset(ThreadContext64Metadata.Offsets.Dr0)]
public ulong Dr0;
[FieldOffset(ThreadContext64Metadata.Offsets.Dr1)]
public ulong Dr1;
[FieldOffset(ThreadContext64Metadata.Offsets.Dr2)]
public ulong Dr2;
[FieldOffset(ThreadContext64Metadata.Offsets.Dr3)]
public ulong Dr3;
[FieldOffset(ThreadContext64Metadata.Offsets.Dr6)]
public ulong Dr6;
[FieldOffset(ThreadContext64Metadata.Offsets.Dr7)]
public ulong Dr7;
[FieldOffset(ThreadContext64Metadata.Offsets.Rax)]
public ulong Rax;
[FieldOffset(ThreadContext64Metadata.Offsets.Rcx)]
public ulong Rcx;
[FieldOffset(ThreadContext64Metadata.Offsets.Rdx)]
public ulong Rdx;
[FieldOffset(ThreadContext64Metadata.Offsets.Rbx)]
public ulong Rbx;
[FieldOffset(ThreadContext64Metadata.Offsets.Rsp)]
public ulong Rsp;
[FieldOffset(ThreadContext64Metadata.Offsets.Rbp)]
public ulong Rbp;
[FieldOffset(ThreadContext64Metadata.Offsets.Rsi)]
public ulong Rsi;
[FieldOffset(ThreadContext64Metadata.Offsets.Rdi)]
public ulong Rdi;
[FieldOffset(ThreadContext64Metadata.Offsets.R8)]
public ulong R8;
[FieldOffset(ThreadContext64Metadata.Offsets.R9)]
public ulong R9;
[FieldOffset(ThreadContext64Metadata.Offsets.R10)]
public ulong R10;
[FieldOffset(ThreadContext64Metadata.Offsets.R11)]
public ulong R11;
[FieldOffset(ThreadContext64Metadata.Offsets.R12)]
public ulong R12;
[FieldOffset(ThreadContext64Metadata.Offsets.R13)]
public ulong R13;
[FieldOffset(ThreadContext64Metadata.Offsets.R14)]
public ulong R14;
[FieldOffset(ThreadContext64Metadata.Offsets.R15)]
public ulong R15;
[FieldOffset(ThreadContext64Metadata.Offsets.Rip)]
public ulong Rip;
[FieldOffset(ThreadContext64Metadata.Offsets.Header)]
public fixed ulong Header[ThreadContext64Metadata.Sizes.Header];
[FieldOffset(ThreadContext64Metadata.Offsets.Legacy)]
public fixed ulong Legacy[ThreadContext64Metadata.Sizes.Legacy];
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm0)]
public M128A Xmm0;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm1)]
public M128A Xmm1;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm2)]
public M128A Xmm2;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm3)]
public M128A Xmm3;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm4)]
public M128A Xmm4;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm5)]
public M128A Xmm5;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm6)]
public M128A Xmm6;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm7)]
public M128A Xmm7;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm8)]
public M128A Xmm8;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm9)]
public M128A Xmm9;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm10)]
public M128A Xmm10;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm11)]
public M128A Xmm11;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm12)]
public M128A Xmm12;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm13)]
public M128A Xmm13;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm14)]
public M128A Xmm14;
[FieldOffset(ThreadContext64Metadata.Offsets.Xmm15)]
public M128A Xmm15;
[FieldOffset(ThreadContext64Metadata.Offsets.VectorRegister)]
public fixed ulong VectorRegister[ThreadContext64Metadata.Sizes.VectorRegister];
[FieldOffset(ThreadContext64Metadata.Offsets.VectorControl)]
public ulong VectorControl;
[FieldOffset(ThreadContext64Metadata.Offsets.DebugControl)]
public ulong DebugControl;
[FieldOffset(ThreadContext64Metadata.Offsets.LastBranchToRip)]
public ulong LastBranchToRip;
[FieldOffset(ThreadContext64Metadata.Offsets.LastBranchFromRip)]
public ulong LastBranchFromRip;
[FieldOffset(ThreadContext64Metadata.Offsets.LastExceptionToRip)]
public ulong LastExceptionToRip;
[FieldOffset(ThreadContext64Metadata.Offsets.LastExceptionFromRip)]
public ulong LastExceptionFromRip;
}
#endregion ThreadContext64
}
///
/// Represents a Win32 handle safely managed.
///
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public sealed class SafeMemoryHandle : SafeHandleZeroOrMinusOneIsInvalid
{
///
/// Parameterless constructor for handles built by the system (like ).
///
public SafeMemoryHandle() : base(true) { }
///
/// Initializes a new instance of the class, specifying the handle to keep in safe.
///
/// The handle to keep in safe.
public SafeMemoryHandle(IntPtr handle) : base(true)
{
SetHandle(handle);
}
///
/// Executes the code required to free the handle.
///
/// True if the handle is released successfully; otherwise, in the event of a catastrophic failure, false. In this case, it generates a releaseHandleFailed MDA Managed Debugging Assistant.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
// Check whether the handle is set AND whether the handle has been successfully closed
return handle != IntPtr.Zero && NativeMethods.CloseHandle(handle);
}
}