Questo articolo è stato tradotto automaticamente. Per visualizzare l'articolo in inglese, selezionare la casella di controllo Inglese. È possibile anche visualizzare il testo inglese in una finestra popup posizionando il puntatore del mouse sopra il testo.
Traduzione
Inglese

Classe SafeHandle

 

Data di pubblicazione: ottobre 2016

Rappresenta una classe wrapper per gli handle del sistema operativo. La classe deve essere ereditata.

Spazio dei nomi:   System.Runtime.InteropServices
Assembly:  mscorlib (in mscorlib.dll)


[SecurityCriticalAttribute]
[SecurityPermissionAttribute(SecurityAction.InheritanceDemand, 
	UnmanagedCode = true)]
public abstract class SafeHandle : CriticalFinalizerObject, IDisposable

NomeDescrizione
System_CAPS_protmethodSafeHandle(IntPtr, Boolean)

Inizializza una nuova istanza della classe SafeHandle con il valore di handle non valido specificato.

NomeDescrizione
System_CAPS_pubpropertyIsClosed

Ottiene un valore che indica se l'handle è chiuso.

System_CAPS_pubpropertyIsInvalid

Quando ne viene eseguito l'override in una classe derivata, ottiene un valore che indica se il valore dell'handle non è valido.

NomeDescrizione
System_CAPS_pubmethodClose()

Contrassegna l'handle per il rilascio delle risorse.

System_CAPS_pubmethodDangerousAddRef(Boolean)

Incrementa manualmente il numero di riferimenti nelle istanze di SafeHandle.

System_CAPS_pubmethodDangerousGetHandle()

Restituisce il valore del campo handle.

System_CAPS_pubmethodDangerousRelease()

Decrementa manualmente il numero di riferimenti in un'istanza di SafeHandle.

System_CAPS_pubmethodDispose()

Rilascia tutte le risorse usate dalla classe SafeHandle.

System_CAPS_protmethodDispose(Boolean)

Rilascia le risorse non gestite usate dalla classe SafeHandle specificando se eseguire una normale operazione di eliminazione.

System_CAPS_pubmethodEquals(Object)

Determina se l'oggetto specificato è uguale all'oggetto corrente. (Ereditato da Object.)

System_CAPS_protmethodFinalize()

Libera tutte le risorse associate all'handle.(Esegue l'override di CriticalFinalizerObject.Finalize().)

System_CAPS_pubmethodGetHashCode()

Funge da funzione hash predefinita.(Ereditato da Object.)

System_CAPS_pubmethodGetType()

Ottiene l'oggetto Type dell'istanza corrente.(Ereditato da Object.)

System_CAPS_protmethodMemberwiseClone()

Crea una copia superficiale dell'oggetto Object corrente.(Ereditato da Object.)

System_CAPS_protmethodReleaseHandle()

Quando ne viene eseguito l'override in una classe derivata, esegue il codice necessario per liberare l'handle.

System_CAPS_protmethodSetHandle(IntPtr)

Imposta l'handle sull'handle preesistente specificato.

System_CAPS_pubmethodSetHandleAsInvalid()

Contrassegna un handle come non più usato.

System_CAPS_pubmethodToString()

Restituisce una stringa che rappresenta l'oggetto corrente. (Ereditato da Object.)

NomeDescrizione
System_CAPS_protfieldhandle

Specifica l'handle di cui eseguire il wrapping.

La SafeHandle classe fornisce la finalizzazione critica di risorse di handle, impedendo agli handle di essere recuperati in anticipo dal garbage collection e di essere riciclati da Windows per fare riferimento a oggetti non gestiti imprevisti.

In questo argomento sono incluse le seguenti sezioni:

Perché SafeHandle?
Che cosa SafeHandle
Classi derivate da SafeHandle

Prima di .NET Framework versione 2.0, sistema operativo tutti gli handle possono essere incapsulati solo di IntPtr oggetto wrapper gestito. Mentre questo è un modo pratico per l'interoperabilità con codice nativo, è Impossibile perso handle per le eccezioni asincrone, ad esempio un thread di interruzione in modo imprevisto o un overflow dello stack. Queste eccezioni asincrone rappresentano un ostacolo alla pulizia delle risorse del sistema operativo e possono verificarsi praticamente ovunque nell'applicazione.

Anche se esegue l'override per il Object.Finalize metodo consentire pulizia delle risorse non gestite quando un oggetto viene sottoposto a garbage collection, in alcuni casi, gli oggetti finalizzabili possono essere recuperati da garbage collection durante l'esecuzione di un metodo all'interno di una piattaforma di richiamo. Se un finalizzatore libera l'handle passato alla chiamata di PInvoke, può causare l'handle venga danneggiato. L'handle può anche essere recuperato mentre il metodo è bloccato durante una chiamata PInvoke, ad esempio durante la lettura di un file.

Ancora più importante, poiché Windows riciclati handle, un handle può essere riciclato e puntare a un'altra risorsa che potrebbe contenere dati sensibili. Questo è noto come attacco di riciclo e possa potenzialmente danneggiare dati e rappresentare una minaccia alla sicurezza.

La 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. La SafeHandle classe risolve i problemi di durata degli oggetti assegnando e rilasciando handle senza interruzione. Contiene un finalizzatore critico che garantisce che l'handle è chiuso e garantisce l'esecuzione durante imprevisto AppDomain viene scaricata, anche nei casi in cui la chiamata di PInvoke si presuppone che sia in uno stato danneggiato.

Poiché SafeHandle eredita da CriticalFinalizerObject, tutti i finalizzatori non critici vengono chiamati prima dei finalizzatori. I finalizzatori vengono richiamati su oggetti che non sono più tempo durante il passaggio della garbage collection stessa. Ad esempio, un FileStream oggetto può eseguire un finalizzatore normale per rimuovere i dati memorizzati nel buffer senza il rischio che l'handle viene perduto o venga riciclato. Questo ordinamento tra finalizzatori critici e non è per uso generale. Esiste principalmente per facilitare la migrazione di librerie esistenti consentendo a tali librerie da utilizzare SafeHandle senza modificare la semantica. Inoltre, il finalizzatore critico e qualsiasi elemento chiama, ad esempio il SafeHandle.ReleaseHandle() (metodo), deve essere in un'area a esecuzione vincolata. Questo impone vincoli per il codice può essere scritto nel grafico delle chiamate del finalizzatore.

Le operazioni pInvoke automaticamente incrementa il conteggio dei riferimenti degli handle incapsulati da un SafeHandle e li decremento al completamento. Ciò garantisce che l'handle non verrà riciclato o chiuso in modo imprevisto.

È possibile specificare la proprietà dell'handle sottostante durante la costruzione di SafeHandle oggetti fornendo un valore per il ownsHandle argomento il SafeHandle costruttore della classe. Consente di controllare se il SafeHandle oggetto rilascerà l'handle dopo l'oggetto è stato eliminato. Ciò è utile per gli handle con requisiti di durata particolari o per l'utilizzo di un handle la cui durata è controllata da un altro utente.

SafeHandle è una classe wrapper astratta per gli handle del sistema operativo. La derivazione da questa classe è difficile. Utilizzare invece le classi derivate nello spazio dei nomi Microsoft.Win32.SafeHandles che forniscono handle sicuri per gli elementi seguenti:

Note per gli eredi:

Per creare una classe derivata da SafeHandle, è necessario sapere come creare e liberare un handle del sistema operativo. Questo processo è diverso per i tipi di handle diverso poiché alcuni utilizzano il CloseHandle funzione, mentre altri utilizzano le funzioni più specifiche, ad esempio UnmapViewOfFile o 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.

System_CAPS_importantImportante

Scrivere le proprie classi derivate da SafeHandle è una funzionalità di programmazione avanzata. .NET Framework fornisce un set di classi prescritte derivate dalla SafeHandle nel Microsoft.Win32.SafeHandles dello spazio dei nomi. Queste classi sono progettate per fornire funzionalità comuni che supportano gli handle di file e del sistema operativo.

Quando si eredita da SafeHandle, è necessario eseguire l'override dei seguenti membri: IsInvalid e ReleaseHandle.

È inoltre necessario fornire un costruttore predefinito che chiama il costruttore base con un valore che rappresenta un valore di handle non valido, e un Boolean valore che indica se l'handle nativo è di proprietà di SafeHandle e pertanto deve essere liberata quando che SafeHandle è stato eliminato.

Esempio di codice seguente crea un handle sicuro personalizzato per un handle di file del sistema operativo, che derivano da SafeHandleZeroOrMinusOneIsInvalid. Legge i byte da un file e visualizza i valori esadecimali. Contiene inoltre un test harness degli errori che provoca l'interruzione del thread, ma il valore dell'handle viene liberato. Quando si utilizza un IntPtr per rappresentare gli handle, l'handle viene occasionalmente perso a causa dell'interruzione di thread asincroni.

È necessario un file di testo nella stessa cartella dell'applicazione compilata. Supponendo che l'applicazione "HexViewer" nome, tuttavia, l'utilizzo della riga di comando è:

HexViewer <filename> -Fault

Facoltativamente, specificare -Fault per tentare intenzionalmente di perdere l'handle interrompendo il thread in una determinata finestra. Utilizzare lo strumento Windows Perform.exe per monitorare i conteggi degli handle durante l'inserimento di errori.

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);
                }
            }

        }
    }
}

InheritanceDemand

for full trust for inheritors. This member cannot be inherited by partially trusted code.

SecurityCriticalAttribute

requires full trust for the immediate caller. This member cannot be used by partially trusted or transparent code.

Universal Windows Platform
Disponibile da 8
.NET Framework
Disponibile da 2.0
Libreria di classi portabile
Supportato in: piattaforme .NET portabili
Silverlight
Disponibile da 2.0
Windows Phone Silverlight
Disponibile da 7.0
Windows Phone
Disponibile da 8.1

I membri statici pubblici ( Condiviso in Visual Basic) di questo tipo è thread safe. Non tutti i membri di istanza sono garantiti come thread safe.

Torna all'inizio
Mostra: