SafeHandle SafeHandle SafeHandle SafeHandle Class

Definizione

Rappresenta una classe wrapper per gli handle del sistema operativo.Represents a wrapper class for operating system handles. La classe deve essere ereditata.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
Ereditarietà
Derivato
Attributi
Implementazioni

Esempi

Esempio di codice seguente crea un handle sicuro personalizzato per un handle di file del sistema operativo, che deriva da SafeHandleZeroOrMinusOneIsInvalid.The following code example creates a custom safe handle for an operating system file handle, deriving from SafeHandleZeroOrMinusOneIsInvalid. Legge i byte da un file e visualizza i valori esadecimali.It reads bytes from a file and displays their hexadecimal values. Contiene anche un test harness degli errori che causa l'interruzione del thread, ma il valore dell'handle viene liberato.It also contains a fault testing harness that causes the thread to abort, but the handle value is freed. Quando si usa un IntPtr per rappresentare gli handle, l'handle viene perso occasionalmente a causa dell'interruzione del thread asincroni.When using an IntPtr to represent handles, the handle is occasionally leaked due to the asynchronous thread abort.

È necessario un file di testo nella stessa cartella dell'applicazione compilata.You will need a text file in the same folder as the compiled application. Supponendo che il nome dell'applicazione "HexViewer", l'utilizzo della riga di comando è:Assuming that you name the application "HexViewer", the command line usage is:

HexViewer <filename> -Fault

Facoltativamente, specificare -Fault intenzionalmente tentativi di perdere l'handle per l'interruzione del thread in una determinata finestra.Optionally specify -Fault to intentionally attempt to leak the handle by aborting the thread in a certain window. Usare lo strumento Windows Perfmon.exe per monitorare i conteggi di handle durante l'inserimento di errori.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);
                }
            }

        }
    }
}

Commenti

Il SafeHandle classe fornisce la finalizzazione critica delle risorse di handle, impedendo agli handle di essere recuperati in anticipo da garbage collection e di essere riciclati da Windows per fare riferimento a oggetti non gestiti non intenzionali.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.

Questo argomento include le sezioni seguenti:This topic includes the following sections:

Il motivo per cui SafeHandle? Why SafeHandle?
Funzionamento di SafeHandle What SafeHandle does
Classi derivate da SafeHandleClasses derived from SafeHandle

Il motivo per cui SafeHandle?Why SafeHandle?

Prima di .NET Framework versione 2.0, sistema operativo tutti gli handle possono solo essere incapsulati nel IntPtr oggetto wrapper gestito.Before the .NET Framework version 2.0, all operating system handles could only be encapsulated in the IntPtr managed wrapper object. Mentre questo è un modo pratico per l'interoperabilità con codice nativo, gli handle è stato possibile andrà persa per le eccezioni asincrone, ad esempio un thread che si interrompe in modo imprevisto o un overflow dello stack.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. Queste eccezioni asincrone sono un ostacolo alla pulizia delle risorse di sistema operativo e possono verificarsi quasi ovunque nell'app.These asynchronous exceptions are an obstacle to cleaning up operating system resources, and they can occur almost anywhere in your app.

Anche se esegue l'override di Object.Finalize metodo consente la pulizia delle risorse non gestite quando un oggetto viene sottoposto a garbage collection, in alcune circostanze, oggetti finalizzabili possono essere recuperati da garbage collection durante l'esecuzione di un metodo all'interno di una piattaforma di richiamare chiamare.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. Se un finalizzatore rilascia l'handle passato a tale piattaforma chiamata invoke, ciò potrebbe causare per il danneggiamento di gestire.If a finalizer frees the handle passed to that platform invoke call, it could lead to handle corruption. L'handle può anche essere recuperato mentre il metodo è bloccato durante una chiamata PInvoke, ad esempio durante la lettura di un file.The handle could also be reclaimed while your method is blocked during a platform invoke call, such as while reading a file.

Ancora più importante, poiché Windows viene riciclato in modo aggressivo gli handle, un handle può essere riciclato e puntare a un'altra risorsa che potrebbe contenere dati sensibili.More critically, because Windows aggressively recycles handles, a handle could be recycled and point to another resource that might contain sensitive data. Questo è noto come un attacco di riciclo e può potenzialmente danneggiare i dati e rappresentare una minaccia alla sicurezza.This is known as a recycle attack and can potentially corrupt data and be a security threat.

Funzionamento di SafeHandleWhat SafeHandle does

Il SafeHandle classe semplifica molti di questi problemi di durata degli oggetti ed è integrata con platform invoke in modo che si verifichino perdite di risorse del sistema operativo.The SafeHandle class simplifies several of these object lifetime issues, and is integrated with platform invoke so that operating system resources are not leaked. Il SafeHandle classe risolve i problemi di durata degli oggetti assegnando e rilasciando handle senza interruzione.The SafeHandle class resolves object lifetime issues by assigning and releasing handles without interruption. Contiene un finalizzatore critico la cui garantisce che l'handle è chiuso e verrà sicuramente eseguito durante imprevisto AppDomain viene scaricato, anche in casi in cui la chiamata di PInvoke presuppone che sia stato danneggiato.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.

In quanto SafeHandle eredita da CriticalFinalizerObject, tutti i finalizzatori non critici vengono richiamati prima di qualsiasi dei finalizzatori.Because SafeHandle inherits from CriticalFinalizerObject, all the noncritical finalizers are called before any of the critical finalizers. I finalizzatori vengono richiamati su oggetti che non sono più in tempo reale durante il passaggio della garbage collection stessa.The finalizers are called on objects that are no longer live during the same garbage collection pass. Ad esempio, un FileStream oggetto può eseguire un finalizzatore normale per cancellare i dati memorizzati nel buffer esistenti senza il rischio che l'handle viene persa o riciclati.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. Questo ordinamento molto debole tra dei finalizzatori critici e non per uso generale.This very weak ordering between critical and noncritical finalizers is not intended for general use. Esiste principalmente per facilitare la migrazione delle raccolte esistenti, consentendo a tali librerie da utilizzare SafeHandle senza modificare la semantica.It exists primarily to assist in the migration of existing libraries by allowing those libraries to use SafeHandle without altering their semantics. Inoltre, il finalizzatore critico e qualsiasi valore chiama, ad esempio il SafeHandle.ReleaseHandle() metodo, deve essere in un'area a esecuzione vincolata.Additionally, the critical finalizer and anything it calls, such as the SafeHandle.ReleaseHandle() method, must be in a constrained execution region. Ciò impone vincoli per il tipo di codice può essere scritti nel grafico delle chiamate del finalizzatore.This imposes constraints on what code can be written within the finalizer's call graph.

Operazioni automaticamente di platform invoke incrementare il conteggio dei riferimenti degli handle incapsulato da un SafeHandle e li decremento dopo il completamento.Platform invoke operations automatically increment the reference count of handles encapsulated by a SafeHandle and decrement them upon completion. Ciò garantisce che l'handle non verrà riciclato o chiusa in modo imprevisto.This ensures that the handle will not be recycled or closed unexpectedly.

È possibile specificare la proprietà di handle sottostante durante la costruzione SafeHandle oggetti fornendo un valore per il ownsHandle argomento nel SafeHandle costruttore della classe.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. Consente di controllare se il SafeHandle oggetto verrà rilasciato l'handle dopo che l'oggetto è stato eliminato.This controls whether the SafeHandle object will release the handle after the object has been disposed. Ciò è utile per gli handle con requisiti particolari durata o per l'utilizzo di un handle di cui durata è controllata da un altro utente.This is useful for handles with peculiar lifetime requirements or for consuming a handle whose lifetime is controlled by someone else.

Classi derivate da SafeHandleClasses derived from SafeHandle

SafeHandle è una classe wrapper astratta per gli handle del sistema operativo.SafeHandle is an abstract wrapper class for operating system handles. La derivazione da questa classe è difficile.Deriving from this class is difficult. Utilizzare invece le classi derivate nello spazio dei nomi Microsoft.Win32.SafeHandles che forniscono handle sicuri per gli elementi seguenti:Instead, use the derived classes in the Microsoft.Win32.SafeHandles namespace that provide safe handles for the following:

Note per gli eredi

Per creare una classe derivata da SafeHandle, è necessario sapere come creare database e un handle del sistema operativo.To create a class derived from SafeHandle, you must know how to create and free an operating system handle. Questo processo è diverso per i tipi di handle diverso perché alcune usano i CloseHandle funzionare, mentre in altre funzioni più specifiche, ad esempio UnmapViewOfFile o 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. Per questo motivo, è necessario creare una classe derivata di SafeHandle per ogni tipo di handle del sistema operativo che si desidera eseguire il wrapping in un handle sicuro.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.

Quando si eredita da SafeHandle, è necessario eseguire l'override dei seguenti membri: IsInvalid e ReleaseHandle().When you inherit from SafeHandle, you must override the following members: IsInvalid and ReleaseHandle().

È inoltre necessario fornire un costruttore predefinito che chiama il costruttore di base con un valore che rappresentano un valore di handle non valido, e un Boolean valore che indica se l'handle nativo è di proprietà per il SafeHandle e, di conseguenza, deve essere liberata quando che SafeHandle byla zahozena.You should also provide a default 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.

Costruttori

SafeHandle() SafeHandle() SafeHandle() SafeHandle()
SafeHandle(IntPtr, Boolean) SafeHandle(IntPtr, Boolean) SafeHandle(IntPtr, Boolean) SafeHandle(IntPtr, Boolean)

Inizializza una nuova istanza della classe SafeHandle con il valore di handle non valido specificato.Initializes a new instance of the SafeHandle class with the specified invalid handle value.

Campi

handle handle handle handle

Specifica l'handle di cui eseguire il wrapping.Specifies the handle to be wrapped.

Proprietà

IsClosed IsClosed IsClosed IsClosed

Ottiene un valore che indica se l'handle è chiuso.Gets a value indicating whether the handle is closed.

IsInvalid IsInvalid IsInvalid IsInvalid

Quando è sottoposto a override in una classe derivata, consente di ottenere un valore che indica se il valore dell'handle non è valido.When overridden in a derived class, gets a value indicating whether the handle value is invalid.

Metodi

Close() Close() Close() Close()

Contrassegna l'handle per il rilascio delle risorse.Marks the handle for releasing and freeing resources.

DangerousAddRef(Boolean) DangerousAddRef(Boolean) DangerousAddRef(Boolean) DangerousAddRef(Boolean)

Incrementa manualmente il numero di riferimenti nelle istanze di SafeHandle.Manually increments the reference counter on SafeHandle instances.

DangerousGetHandle() DangerousGetHandle() DangerousGetHandle() DangerousGetHandle()

Restituisce il valore del campo handle.Returns the value of the handle field.

DangerousRelease() DangerousRelease() DangerousRelease() DangerousRelease()

Decrementa manualmente il numero di riferimenti in un'istanza di SafeHandle.Manually decrements the reference counter on a SafeHandle instance.

Dispose() Dispose() Dispose() Dispose()

Rilascia tutte le risorse usate dalla classe SafeHandle.Releases all resources used by the SafeHandle class.

Dispose(Boolean) Dispose(Boolean) Dispose(Boolean) Dispose(Boolean)

Rilascia le risorse non gestite utilizzate dalla classe SafeHandle specificando se eseguire una normale operazione di eliminazione.Releases the unmanaged resources used by the SafeHandle class specifying whether to perform a normal dispose operation.

Equals(Object) Equals(Object) Equals(Object) Equals(Object)

Determina se l'oggetto specificato è uguale all'oggetto corrente.Determines whether the specified object is equal to the current object.

(Inherited from Object)
Finalize() Finalize() Finalize() Finalize()

Libera tutte le risorse associate all'handle.Frees all resources associated with the handle.

GetHashCode() GetHashCode() GetHashCode() GetHashCode()

Funge da funzione hash predefinita.Serves as the default hash function.

(Inherited from Object)
GetType() GetType() GetType() GetType()

Ottiene l'oggetto Type dell'istanza corrente.Gets the Type of the current instance.

(Inherited from Object)
MemberwiseClone() MemberwiseClone() MemberwiseClone() MemberwiseClone()

Crea una copia superficiale dell'oggetto Object corrente.Creates a shallow copy of the current Object.

(Inherited from Object)
ReleaseHandle() ReleaseHandle() ReleaseHandle() ReleaseHandle()

Quando viene sottoposto a override in una classe derivata, esegue il codice necessario per liberare l'handle.When overridden in a derived class, executes the code required to free the handle.

SetHandle(IntPtr) SetHandle(IntPtr) SetHandle(IntPtr) SetHandle(IntPtr)

Imposta l'handle sull'handle preesistente specificato.Sets the handle to the specified pre-existing handle.

SetHandleAsInvalid() SetHandleAsInvalid() SetHandleAsInvalid() SetHandleAsInvalid()

Contrassegna un handle come non più utilizzato.Marks a handle as no longer used.

ToString() ToString() ToString() ToString()

Restituisce una stringa che rappresenta l'oggetto corrente.Returns a string that represents the current object.

(Inherited from Object)

Sicurezza

InheritanceDemand
per un'attendibilità totale per gli eredi.for full trust for inheritors. Questo membro non può essere ereditato da codice parzialmente attendibile.This member cannot be inherited by partially trusted code.

SecurityCriticalAttribute
richiede l'attendibilità totale per il chiamante immediato.requires full trust for the immediate caller. Questo membro non può essere utilizzato da codice parzialmente attendibile o trasparente.This member cannot be used by partially trusted or transparent code.

Si applica a

Vedi anche