SafeHandle Klasse

Definition

Stellt eine Wrapperklasse für Betriebssystemhandles dar.Represents a wrapper class for operating system handles. Die Klasse muss geerbt werden.This class must be inherited.

public ref class SafeHandle abstract : System::Runtime::ConstrainedExecution::CriticalFinalizerObject, IDisposable
[System.Security.SecurityCritical]
public abstract class SafeHandle : System.Runtime.ConstrainedExecution.CriticalFinalizerObject, IDisposable
type SafeHandle = class
    inherit CriticalFinalizerObject
    interface IDisposable
Public MustInherit Class SafeHandle
Inherits CriticalFinalizerObject
Implements IDisposable
Vererbung
Abgeleitet
Attribute
Implementiert

Beispiele

Im folgenden Codebeispiel wird ein benutzerdefiniertes sicheres Handle für ein Betriebssystem-Datei Handle SafeHandleZeroOrMinusOneIsInvaliderstellt, das von abgeleitet wird.The following code example creates a custom safe handle for an operating system file handle, deriving from SafeHandleZeroOrMinusOneIsInvalid. Er liest Bytes aus einer Datei und zeigt deren hexadezimal Werte an.It reads bytes from a file and displays their hexadecimal values. Sie enthält auch eine fehlertestumgebung, die bewirkt, dass der Thread abgebrochen wird, der Handle-Wert jedoch freigegeben wird.It also contains a fault testing harness that causes the thread to abort, but the handle value is freed. Wenn Sie einen IntPtr zur Darstellung von Handles verwenden, wird das Handle aufgrund des asynchronen Thread Abbruchs gelegentlich kompromittiert.When using an IntPtr to represent handles, the handle is occasionally leaked due to the asynchronous thread abort.

Sie benötigen eine Textdatei im selben Ordner wie die kompilierte Anwendung.You will need a text file in the same folder as the compiled application. Wenn Sie die Anwendung "hexviewer" benennen, lautet die Befehlszeilen Syntax wie folgt:Assuming that you name the application "HexViewer", the command line usage is:

HexViewer <filename> -Fault

Geben -Fault Sie optional an, um zu versuchen, den Handle zu entschlüsseln, indem Sie den Thread in einem bestimmten Fenster abbrechen.Optionally specify -Fault to intentionally attempt to leak the handle by aborting the thread in a certain window. Verwenden Sie das Windows Perfmon. exe-Tool, um die Anzahl der Handles beim Einfügen von Fehlern zu überwachen.Use the Windows Perfmon.exe tool to monitor handle counts while injecting faults.

using System;
using System.Runtime.InteropServices;
using System.IO;
using System.ComponentModel;
using System.Security.Permissions;
using System.Security;
using System.Threading;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;

namespace SafeHandleDemo
{
    [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
    [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
    internal class MySafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        // Create a SafeHandle, informing the base class
        // that this SafeHandle instance "owns" the handle,
        // and therefore SafeHandle should call
        // our ReleaseHandle method when the SafeHandle
        // is no longer in use.
        private MySafeFileHandle()
            : base(true)
        {
        }
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        override protected bool ReleaseHandle()
        {
            // Here, we must obey all rules for constrained execution regions.
            return NativeMethods.CloseHandle(handle);
            // If ReleaseHandle failed, it can be reported via the
            // "releaseHandleFailed" managed debugging assistant (MDA).  This
            // MDA is disabled by default, but can be enabled in a debugger
            // or during testing to diagnose handle corruption problems.
            // We do not throw an exception because most code could not recover
            // from the problem.
        }
    }

    [SuppressUnmanagedCodeSecurity()]
    internal static class NativeMethods
    {
        // Win32 constants for accessing files.
        internal const int GENERIC_READ = unchecked((int)0x80000000);

        // Allocate a file object in the kernel, then return a handle to it.
        [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
        internal extern static MySafeFileHandle CreateFile(String fileName,
           int dwDesiredAccess, System.IO.FileShare dwShareMode,
           IntPtr securityAttrs_MustBeZero, System.IO.FileMode dwCreationDisposition,
           int dwFlagsAndAttributes, IntPtr hTemplateFile_MustBeZero);

        // Use the file handle.
        [DllImport("kernel32", SetLastError = true)]
        internal extern static int ReadFile(MySafeFileHandle handle, byte[] bytes,
           int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);

        // Free the kernel's file object (close the file).
        [DllImport("kernel32", SetLastError = true)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        internal extern static bool CloseHandle(IntPtr handle);
    }

    // The MyFileReader class is a sample class that accesses an operating system
    // resource and implements IDisposable. This is useful to show the types of
    // transformation required to make your resource wrapping classes
    // more resilient. Note the Dispose and Finalize implementations.
    // Consider this a simulation of System.IO.FileStream.
    public class MyFileReader : IDisposable
    {
        // _handle is set to null to indicate disposal of this instance.
        private MySafeFileHandle _handle;

        public MyFileReader(String fileName)
        {
            // Security permission check.
            String fullPath = Path.GetFullPath(fileName);
            new FileIOPermission(FileIOPermissionAccess.Read, fullPath).Demand();

            // Open a file, and save its handle in _handle.
            // Note that the most optimized code turns into two processor
            // instructions: 1) a call, and 2) moving the return value into
            // the _handle field.  With SafeHandle, the CLR's platform invoke
            // marshaling layer will store the handle into the SafeHandle
            // object in an atomic fashion. There is still the problem
            // that the SafeHandle object may not be stored in _handle, but
            // the real operating system handle value has been safely stored
            // in a critical finalizable object, ensuring against leaking
            // the handle even if there is an asynchronous exception.

            MySafeFileHandle tmpHandle;
            tmpHandle = NativeMethods.CreateFile(fileName, NativeMethods.GENERIC_READ,
                FileShare.Read, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);

            // An async exception here will cause us to run our finalizer with
            // a null _handle, but MySafeFileHandle's ReleaseHandle code will
            // be invoked to free the handle.

            // This call to Sleep, run from the fault injection code in Main,
            // will help trigger a race. But it will not cause a handle leak
            // because the handle is already stored in a SafeHandle instance.
            // Critical finalization then guarantees that freeing the handle,
            // even during an unexpected AppDomain unload.
            Thread.Sleep(500);
            _handle = tmpHandle;  // Makes _handle point to a critical finalizable object.

            // Determine if file is opened successfully.
            if (_handle.IsInvalid)
                throw new Win32Exception(Marshal.GetLastWin32Error(), fileName);
        }

        public void Dispose()  // Follow the Dispose pattern - public nonvirtual.
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        // No finalizer is needed. The finalizer on SafeHandle
        // will clean up the MySafeFileHandle instance,
        // if it hasn't already been disposed.
        // Howerver, there may be a need for a subclass to
        // introduce a finalizer, so Dispose is properly implemented here.
        [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
        protected virtual void Dispose(bool disposing)
        {
            // Note there are three interesting states here:
            // 1) CreateFile failed, _handle contains an invalid handle
            // 2) We called Dispose already, _handle is closed.
            // 3) _handle is null, due to an async exception before
            //    calling CreateFile. Note that the finalizer runs
            //    if the constructor fails.
            if (_handle != null && !_handle.IsInvalid)
            {
                // Free the handle
                _handle.Dispose();
            }
            // SafeHandle records the fact that we've called Dispose.
        }


        [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
        public byte[] ReadContents(int length)
        {
            if (_handle.IsInvalid)  // Is the handle disposed?
                throw new ObjectDisposedException("FileReader is closed");

            // This sample code will not work for all files.
            byte[] bytes = new byte[length];
            int numRead = 0;
            int r = NativeMethods.ReadFile(_handle, bytes, length, out numRead, IntPtr.Zero);
            // Since we removed MyFileReader's finalizer, we no longer need to
            // call GC.KeepAlive here.  Platform invoke will keep the SafeHandle
            // instance alive for the duration of the call.
            if (r == 0)
                throw new Win32Exception(Marshal.GetLastWin32Error());
            if (numRead < length)
            {
                byte[] newBytes = new byte[numRead];
                Array.Copy(bytes, newBytes, numRead);
                bytes = newBytes;
            }
            return bytes;
        }
    }

    static class Program
    {
        // Testing harness that injects faults.
        private static bool _printToConsole = false;
        private static bool _workerStarted = false;

        private static void Usage()
        {
            Console.WriteLine("Usage:");
            // Assumes that application is named HexViwer"
            Console.WriteLine("HexViewer <fileName> [-fault]");
            Console.WriteLine(" -fault Runs hex viewer repeatedly, injecting faults.");
        }

        private static void ViewInHex(Object fileName)
        {
            _workerStarted = true;
            byte[] bytes;
            using (MyFileReader reader = new MyFileReader((String)fileName))
            {
                bytes = reader.ReadContents(20);
            }  // Using block calls Dispose() for us here.

            if (_printToConsole)
            {
                // Print up to 20 bytes.
                int printNBytes = Math.Min(20, bytes.Length);
                Console.WriteLine("First {0} bytes of {1} in hex", printNBytes, fileName);
                for (int i = 0; i < printNBytes; i++)
                    Console.Write("{0:x} ", bytes[i]);
                Console.WriteLine();
            }
        }

        static void Main(string[] args)
        {
            if (args.Length == 0 || args.Length > 2 ||
                args[0] == "-?" || args[0] == "/?")
            {
                Usage();
                return;
            }

            String fileName = args[0];
            bool injectFaultMode = args.Length > 1;
            if (!injectFaultMode)
            {
                _printToConsole = true;
                ViewInHex(fileName);
            }
            else
            {
                Console.WriteLine("Injecting faults - watch handle count in perfmon (press Ctrl-C when done)");
                int numIterations = 0;
                while (true)
                {
                    _workerStarted = false;
                    Thread t = new Thread(new ParameterizedThreadStart(ViewInHex));
                    t.Start(fileName);
                    Thread.Sleep(1);
                    while (!_workerStarted)
                    {
                        Thread.Sleep(0);
                    }
                    t.Abort();  // Normal applications should not do this.
                    numIterations++;
                    if (numIterations % 10 == 0)
                        GC.Collect();
                    if (numIterations % 10000 == 0)
                        Console.WriteLine(numIterations);
                }
            }

        }
    }
}

Hinweise

Die SafeHandle -Klasse stellt eine kritische Finalisierung der Handle-Ressourcen bereit, wodurch verhindert wird, dass Handles vorzeitig durch Garbage Collection und von Windows wieder verwendet werden, um auf unbeabsichtigte nicht verwaltete Objekte zu verweisen.The SafeHandle class provides critical finalization of handle resources, preventing handles from being reclaimed prematurely by garbage collection and from being recycled by Windows to reference unintended unmanaged objects.

Dieses Thema enthält die folgenden Abschnitte:This topic includes the following sections:

Warum SafeHandle? Why SafeHandle?
Funktionsweise von SafeHandle What SafeHandle does
Von SafeHandle abgeleitete KlassenClasses derived from SafeHandle

Warum SafeHandle?Why SafeHandle?

Vor der .NET Framework Version 2,0 konnten alle Betriebssystem Handles nur im IntPtr Managed Wrapper-Objekt gekapselt werden.Before the .NET Framework version 2.0, all operating system handles could only be encapsulated in the IntPtr managed wrapper object. Obwohl dies eine bequeme Methode für die Interoperabilität mit System eigenem Code war, können Handles durch asynchrone Ausnahmen kompromittiert werden, z. b. ein unerwarteter Thread oder ein Stapelüberlauf.While this was a convenient way to interoperate with native code, handles could be leaked by asynchronous exceptions, such as a thread aborting unexpectedly or a stack overflow. Diese asynchronen Ausnahmen sind ein Hindernis für das Bereinigen von Betriebssystemressourcen und können fast überall in der app auftreten.These asynchronous exceptions are an obstacle to cleaning up operating system resources, and they can occur almost anywhere in your app.

Obwohl die über Schreibungen für Object.Finalize die-Methode das Bereinigen von nicht verwalteten Ressourcen ermöglichen, wenn ein Objekt in der Garbage Collection erfasst wird, können finalisierbare Objekte in einigen Fällen von Garbage Collection freigegeben werden, während eine Methode innerhalb eines Platt Form Aufrufs ausgeführt wird. erfordern.Although overrides to the Object.Finalize method allow cleanup of unmanaged resources when an object is being garbage collected, in some circumstances, finalizable objects can be reclaimed by garbage collection while executing a method within a platform invoke call. Wenn ein Finalizer das an diesen Platt Form Aufruf-Aufruf über gegebene handle freigibt, kann dies zur Behandlung von Beschädigungen führen.If a finalizer frees the handle passed to that platform invoke call, it could lead to handle corruption. Das Handle kann auch freigegeben werden, während die Methode während eines Platt Form Aufrufs blockiert wird, z. b. beim Lesen einer Datei.The handle could also be reclaimed while your method is blocked during a platform invoke call, such as while reading a file.

Kritischer, da Windows die Handles aggressiv wieder verwendet, könnte ein Handle wieder verwendet werden und auf eine andere Ressource zeigen, die vertrauliche Daten enthalten könnte.More critically, because Windows aggressively recycles handles, a handle could be recycled and point to another resource that might contain sensitive data. Dies wird als Wiederverwendungs Angriff bezeichnet und kann möglicherweise Daten beschädigen und eine Sicherheitsbedrohung darstellen.This is known as a recycle attack and can potentially corrupt data and be a security threat.

Funktionsweise von SafeHandleWhat SafeHandle does

Die SafeHandle -Klasse vereinfacht einige dieser Probleme mit der Objekt Lebensdauer und ist in einen Platt Form Aufruf integriert, sodass Betriebssystemressourcen nicht verloren gehen.The SafeHandle class simplifies several of these object lifetime issues, and is integrated with platform invoke so that operating system resources are not leaked. Die SafeHandle -Klasse löst Probleme mit der Objekt Lebensdauer durch zuweisen und Freigeben von Handles ohne Unterbrechung.The SafeHandle class resolves object lifetime issues by assigning and releasing handles without interruption. Sie enthält einen kritischen Finalizer, mit dem sichergestellt wird, dass das Handle geschlossen und auch bei AppDomain unerwarteten entladen ausgeführt wird. Dies gilt auch für Fälle, in denen angenommen wird, dass der Platt Form Aufruf in einem beschädigten Zustand ist.It contains a critical finalizer that ensures that the handle is closed and is guaranteed to run during unexpected AppDomain unloads, even in cases when the platform invoke call is assumed to be in a corrupted state.

Da SafeHandle vonCriticalFinalizerObjecterbt, werden alle nicht kritischen Finalizer vor den kritischen Finalizern aufgerufen.Because SafeHandle inherits from CriticalFinalizerObject, all the noncritical finalizers are called before any of the critical finalizers. Die Finalizer werden für Objekte aufgerufen, die nicht mehr Live während desselben Garbage Collection bestanden werden.The finalizers are called on objects that are no longer live during the same garbage collection pass. Beispielsweise kann ein FileStream -Objekt einen normalen Finalizer ausführen, um vorhandene gepufferte Daten auszuleeren, ohne das Risiko zu haben, dass das Handle kompromittiert oder wieder verwendet wird.For example, a FileStream object can run a normal finalizer to flush out existing buffered data without the risk of the handle being leaked or recycled. Diese sehr schwache Reihenfolge zwischen kritischen und nicht kritischen Finalizern ist nicht für die allgemeine Verwendung vorgesehen.This very weak ordering between critical and noncritical finalizers is not intended for general use. Es ist hauptsächlich zur Unterstützung bei der Migration vorhandener Bibliotheken, da diese Bibliotheken SafeHandle die Verwendung ohne Änderung ihrer Semantik erlauben.It exists primarily to assist in the migration of existing libraries by allowing those libraries to use SafeHandle without altering their semantics. Außerdem müssen sich der kritische Finalizer und alle Aufrufe, wie z. SafeHandle.ReleaseHandle() b. die-Methode, in einem eingeschränkten Ausführungs Bereich befinden.Additionally, the critical finalizer and anything it calls, such as the SafeHandle.ReleaseHandle() method, must be in a constrained execution region. Dies erzwingt Einschränkungen für den Code, der innerhalb des Aufruf Diagramms des Finalizers geschrieben werden kann.This imposes constraints on what code can be written within the finalizer's call graph.

Platt Form Aufrufe erhöhen automatisch den Verweis Zähler von Handles, die von einem SafeHandle gekapselt werden, und Dekrement bei Abschluss.Platform invoke operations automatically increment the reference count of handles encapsulated by a SafeHandle and decrement them upon completion. Dadurch wird sichergestellt, dass das Handle nicht unerwartet wieder verwendet oder geschlossen wird.This ensures that the handle will not be recycled or closed unexpectedly.

Sie können den Besitz des zugrunde liegenden Handles beim Erstellen SafeHandle von-Objekten angeben, indem Sie ownsHandle dem-Argument SafeHandle im-Klassenkonstruktor einen Wert bereitstellen.You can specify ownership of the underlying handle when constructing SafeHandle objects by supplying a value to the ownsHandle argument in the SafeHandle class constructor. Hiermit wird gesteuert, SafeHandle ob das Objekt das Handle freigibt, nachdem das Objekt verworfen wurde.This controls whether the SafeHandle object will release the handle after the object has been disposed. Dies ist hilfreich bei Handles mit besonderen Anforderungen an die Lebensdauer oder der Verwendung eines Handles, dessen Lebensdauer von einem anderen Benutzer gesteuert wird.This is useful for handles with peculiar lifetime requirements or for consuming a handle whose lifetime is controlled by someone else.

Von SafeHandle abgeleitete KlassenClasses derived from SafeHandle

SafeHandleist eine abstrakte Wrapper Klasse für Betriebssystem Handles.SafeHandle is an abstract wrapper class for operating system handles. Das Ableiten von dieser Klasse ist schwierig.Deriving from this class is difficult. Verwenden Sie stattdessen die abgeleiteten Klassen im Microsoft.Win32.SafeHandles-Namespace, die sichere Handles für Folgendes bereitstellen:Instead, use the derived classes in the Microsoft.Win32.SafeHandles namespace that provide safe handles for the following:

Hinweise für Vererber

Um eine von SafeHandleabgeleitete Klasse zu erstellen, müssen Sie wissen, wie ein Betriebssystem Handle erstellt und freigegeben wird.To create a class derived from SafeHandle, you must know how to create and free an operating system handle. Dieser Prozess unterscheidet sich für verschiedene handle-Typen, da einige die CloseHandle -Funktion verwenden, während andere spezifischere Funktionen verwenden, z. b. UnmapViewOfFile oder FindClose.This process is different for different handle types because some use the CloseHandle function, while others use more specific functions such as UnmapViewOfFile or FindClose. Aus diesem Grund müssen Sie für jeden Betriebssystem-Handle SafeHandle -Typ, den Sie in einem sicheren handle einschließen möchten, eine abgeleitete Klasse von erstellen.For this reason, you must create a derived class of SafeHandle for each operating system handle type that you want to wrap in a safe handle.

Wenn Sie von SafeHandle erben, müssen die folgenden Member überschrieben werden: IsInvalid und ReleaseHandle().When you inherit from SafeHandle, you must override the following members: IsInvalid and ReleaseHandle().

Sie sollten auch einen Parameter losen Konstruktor bereitstellen, der den Basiskonstruktor mit einem Wert aufruft, der einen ungültigen Handle- Boolean Wert darstellt, und einen Wert, der angibt, SafeHandle ob das Native Handle im Besitz von ist und daher freigegeben werden soll. Wenn das SafeHandle verworfen wurde.You should also provide a parameterless constructor that calls the base constructor with a value that represent an invalid handle value, and a Boolean value indicating whether the native handle is owned by the SafeHandle and consequently should be freed when that SafeHandle has been disposed.

Konstruktoren

SafeHandle()
SafeHandle(IntPtr, Boolean)

Initialisiert eine neue Instanz der SafeHandle-Klasse mit dem angegebenen ungültigen Handlewert.Initializes a new instance of the SafeHandle class with the specified invalid handle value.

Felder

handle

Gibt das zu umschließende Handle an.Specifies the handle to be wrapped.

Eigenschaften

IsClosed

Ruft einen Wert ab, der angibt, ob das Handle geschlossen ist.Gets a value indicating whether the handle is closed.

IsInvalid

Ruft beim Überschreiben in einer abgeleiteten Klasse einen Wert ab, der angibt, ob dieses Handle ungültig ist.When overridden in a derived class, gets a value indicating whether the handle value is invalid.

Methoden

Close()

Markiert das Handle für das Freigeben und Verfügbarmachen von Ressourcen.Marks the handle for releasing and freeing resources.

DangerousAddRef(Boolean)

Inkrementiert manuell den Verweiszähler für SafeHandle-Instanzen.Manually increments the reference counter on SafeHandle instances.

DangerousGetHandle()

Gibt den Wert des handle-Felds zurück.Returns the value of the handle field.

DangerousRelease()

Dekrementiert manuell den Verweiszähler für eine SafeHandle-Instanz.Manually decrements the reference counter on a SafeHandle instance.

Dispose()

Gibt alle von der SafeHandle-Klasse verwendeten Ressourcen frei.Releases all resources used by the SafeHandle class.

Dispose(Boolean)

Gibt die von der SafeHandle-Klasse verwendeten, nicht verwalteten Ressourcen frei und gibt an, ob ein normaler Freigabevorgang ausgeführt werden soll.Releases the unmanaged resources used by the SafeHandle class specifying whether to perform a normal dispose operation.

Equals(Object)

Bestimmt, ob das angegebene Objekt mit dem aktuellen Objekt identisch ist.Determines whether the specified object is equal to the current object.

(Geerbt von Object)
Finalize()

Gibt alle dem Handle zugeordneten Ressourcen frei.Frees all resources associated with the handle.

GetHashCode()

Fungiert als Standardhashfunktion.Serves as the default hash function.

(Geerbt von Object)
GetType()

Ruft den Type der aktuellen Instanz ab.Gets the Type of the current instance.

(Geerbt von Object)
MemberwiseClone()

Erstellt eine flache Kopie des aktuellen Object.Creates a shallow copy of the current Object.

(Geerbt von Object)
ReleaseHandle()

Führt beim Überschreiben in einer abgeleiteten Klasse den Code aus, der für das Freigeben des Handles erforderlich ist.When overridden in a derived class, executes the code required to free the handle.

SetHandle(IntPtr)

Legt das Handle für das angegebene, bereits vorhandene Handle fest.Sets the handle to the specified pre-existing handle.

SetHandleAsInvalid()

Markiert ein Handle als nicht mehr verwendet.Marks a handle as no longer used.

ToString()

Gibt eine Zeichenfolge zurück, die das aktuelle Objekt darstellt.Returns a string that represents the current object.

(Geerbt von Object)

Sicherheit

InheritanceDemand
für vollständige Vertrauenswürdigkeit für Vererber.for full trust for inheritors. Dieser Member kann nicht von teilweise vertrauenswürdigem Code geerbt werden.This member cannot be inherited by partially trusted code.

SecurityCriticalAttribute
Erfordert volle Vertrauenswürdigkeit für den unmittelbaren Aufrufer.requires full trust for the immediate caller. Dieser Member kann nicht von teilweise vertrauenswürdigem oder transparentem Code verwendet werden.This member cannot be used by partially trusted or transparent code.

Gilt für:

Siehe auch