SafeHandle SafeHandle SafeHandle SafeHandle Class

Definicja

Reprezentuje klasę otoki dla systemu operacyjnego.Represents a wrapper class for operating system handles. Ta klasa musi być dziedziczona.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
Dziedziczenie
Pochodne
Atrybuty
Implementuje

Przykłady

Poniższy przykład kodu tworzy niestandardowe bezpiecznego dojścia na uchwyt pliku systemu operacyjnego, wynikające z SafeHandleZeroOrMinusOneIsInvalid.The following code example creates a custom safe handle for an operating system file handle, deriving from SafeHandleZeroOrMinusOneIsInvalid. Odczytuje bajtów z pliku i wyświetla ich wartości szesnastkowych.It reads bytes from a file and displays their hexadecimal values. Zawiera również testowanie kontroler pod kątem błędów, dzięki któremu wątku przerwać, ale wartość dojścia jest zwalniana.It also contains a fault testing harness that causes the thread to abort, but the handle value is freed. Korzystając z IntPtr do reprezentowania uchwyty, od czasu do czasu przeciek uchwytu ze względu na przerwanie asynchronicznego wątku.When using an IntPtr to represent handles, the handle is occasionally leaked due to the asynchronous thread abort.

Konieczne będzie plik tekstowy, w tym samym folderze co skompilowanej aplikacji.You will need a text file in the same folder as the compiled application. Przy założeniu, że nazwy aplikacji "HexViewer" jest użycie wiersza polecenia:Assuming that you name the application "HexViewer", the command line usage is:

HexViewer <filename> -Fault

Opcjonalnie można określić -Fault próbuje celowo przecieku uchwytu przerywanie wątków niektóre okna.Optionally specify -Fault to intentionally attempt to leak the handle by aborting the thread in a certain window. Użyj narzędzia Windows Perfmon.exe do monitorowania liczby uchwytu podczas wstrzykiwania błędów.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);
                }
            }

        }
    }
}

Uwagi

SafeHandle Klasa udostępnia krytyczna finalizacja zasobów uchwyt, zapobieganie uchwyty z są odzyskiwane przedwcześnie przez wyrzucanie elementów bezużytecznych i odtwarzaniu przez Windows, aby odwoływać się do niezamierzonych niezarządzane obiekty.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.

Ten temat zawiera następujące sekcje:This topic includes the following sections:

Dlaczego SafeHandle? Why SafeHandle?
Jak działa SafeHandle What SafeHandle does
Klasy pochodne klasy SafeHandleClasses derived from SafeHandle

Dlaczego SafeHandle?Why SafeHandle?

Przed .NET Framework w wersji 2.0, wszystkie system operacyjny obsługuje tylko może być hermetyzowane w IntPtr zarządzanych otoka obiektu.Before the .NET Framework version 2.0, all operating system handles could only be encapsulated in the IntPtr managed wrapper object. Gdy jest to wygodny sposób na potrzeby współdziałania z kodem natywnym, obsługuje można wyciek przez wyjątków asynchronicznych, takich jak wątek nieoczekiwanie zostanie przerwany lub przepełnienie stosu.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. Te wyjątki asynchroniczne są przeszkody Oczyszczanie zasobów systemu operacyjnego i może wystąpić praktycznie dowolnym miejscu w aplikacji.These asynchronous exceptions are an obstacle to cleaning up operating system resources, and they can occur almost anywhere in your app.

Mimo że zastąpienia Object.Finalize metoda umożliwia oczyszczania niezarządzanych zasobów, gdy obiekt jest bezużyteczne w pewnych okolicznościach, które można sfinalizować obiektów można odzyskać przez wyrzucanie elementów bezużytecznych podczas wykonywania metody za pomocą platformy wywołania wywołanie.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. Jeśli finalizator powoduje zwolnienie dojście przekazane do tej platformy wywołaniem, może prowadzić do obsługi uszkodzeń.If a finalizer frees the handle passed to that platform invoke call, it could lead to handle corruption. Ponadto można odzyskać uchwytu, gdy metoda jest zablokowane podczas jej platformy wywołania wywołania, takie jak podczas odczytywania pliku.The handle could also be reclaimed while your method is blocked during a platform invoke call, such as while reading a file.

Bardziej krytycznie ponieważ Windows agresywnie jest odtwarzany uchwyty, uchwyt może poddana recyklingowi, a wskaż inny zasób, który może zawierać dane poufne.More critically, because Windows aggressively recycles handles, a handle could be recycled and point to another resource that might contain sensitive data. To jest znany jako atak odtwarzanie i może potencjalnie uszkodzić dane i stanowić zagrożenie dla bezpieczeństwa.This is known as a recycle attack and can potentially corrupt data and be a security threat.

Jak działa SafeHandleWhat SafeHandle does

SafeHandle Klasa upraszcza kilka te kwestie okresu istnienia obiektów i jest zintegrowana z platformą wywołania, tak aby nie wyciek zasobów systemu operacyjnego.The SafeHandle class simplifies several of these object lifetime issues, and is integrated with platform invoke so that operating system resources are not leaked. SafeHandle Klasy jest rozpoznawana jako kwestie istnienia obiektu i zwalniają dojścia bez zakłóceń.The SafeHandle class resolves object lifetime issues by assigning and releasing handles without interruption. Zawiera krytyczny finalizator, który zapewnia, że uchwyt jest zamknięty, a następnie gwarantuje działanie w trakcie nieoczekiwany AppDomain zwalnia, nawet w przypadkach, gdy wywołanie platformy wywołanie zakłada, że w stanie uszkodzenia.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.

Ponieważ SafeHandle dziedziczy CriticalFinalizerObject, wszystkie niekrytyczne finalizatory są wywoływane przed każdą krytyczne finalizatory.Because SafeHandle inherits from CriticalFinalizerObject, all the noncritical finalizers are called before any of the critical finalizers. Finalizatory są nazywane dla obiektów, które nie są już na żywo podczas przebiegu tej samej kolekcji wyrzucania elementów.The finalizers are called on objects that are no longer live during the same garbage collection pass. Na przykład FileStream obiektu można uruchomić normalne finalizator opróżnić się istniejących buforowane dane, bez ryzyka stałego skanowania dojścia jest ujawnione lub poddawane recyklingowi.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. To bardzo słabe porządkowanie między finalizatory krytyczne i niekrytyczne nie jest przeznaczona do użytku ogólnego.This very weak ordering between critical and noncritical finalizers is not intended for general use. Istnieje przede wszystkim ułatwiają migrację istniejących bibliotek, umożliwiając tych bibliotek do użycia SafeHandle bez zmiany ich semantyki.It exists primarily to assist in the migration of existing libraries by allowing those libraries to use SafeHandle without altering their semantics. Ponadto krytyczne finalizatory i nic wywoływanych przez nią, takie jak SafeHandle.ReleaseHandle() metody, musi znajdować się w regionie ograniczonego wykonania.Additionally, the critical finalizer and anything it calls, such as the SafeHandle.ReleaseHandle() method, must be in a constrained execution region. To nakłada ograniczenia dotyczące kodu, które mogą być zapisywane w obrębie wykresu wywołań finalizatora.This imposes constraints on what code can be written within the finalizer's call graph.

Wywołanie operacji platformy automatycznie zwiększyć licznik odwołań uchwytów zamknięte przez SafeHandle i dekrementacyjne je po zakończeniu.Platform invoke operations automatically increment the reference count of handles encapsulated by a SafeHandle and decrement them upon completion. Daje to gwarancję, że dojście będą nie odtwarzania lub został nieoczekiwanie zamknięty.This ensures that the handle will not be recycled or closed unexpectedly.

Można określić własność podstawowego dojścia przy konstruowaniu SafeHandle obiekty podając wartości do ownsHandle argument SafeHandle konstruktora klasy.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. W ten sposób kontroluje czy SafeHandle obiektu spowoduje zwolnienie uchwytu po obiekt został usunięty.This controls whether the SafeHandle object will release the handle after the object has been disposed. Jest to przydatne, obsługuje istnienia szczególne wymagania lub używania uchwyt, którego okres istnienia jest kontrolowany przez kogoś innego.This is useful for handles with peculiar lifetime requirements or for consuming a handle whose lifetime is controlled by someone else.

Klasy pochodne klasy SafeHandleClasses derived from SafeHandle

SafeHandle jest klasą abstrakcyjna otoki dla systemu operacyjnego.SafeHandle is an abstract wrapper class for operating system handles. Wyprowadzanie z tej klasy jest trudne.Deriving from this class is difficult. Zamiast tego należy użyć klas pochodnych w Microsoft.Win32.SafeHandles przestrzeni nazw, które zapewniają bezpieczne dojścia dla następujących:Instead, use the derived classes in the Microsoft.Win32.SafeHandles namespace that provide safe handles for the following:

Uwagi dotyczące dziedziczenia

Aby utworzyć klasę pochodną SafeHandle, trzeba wiedzieć, jak utworzyć i bezpłatne dojście systemu operacyjnego.To create a class derived from SafeHandle, you must know how to create and free an operating system handle. Ten proces różni się dla dojście do różnych typów, ponieważ jest używany przez niektóre funkcja CloseHandle funkcji, a w innych stosuje bardziej szczegółowe funkcje takie jak UnmapViewOfFile lub 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. Z tego powodu należy utworzyć klasę pochodną z SafeHandle dla każdego typu dojście systemu operacyjnego, który ma być zawijany w bezpiecznym dojściu.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.

Przy dziedziczeniu z SafeHandle, konieczne jest przesłonięcie następujących składowych: IsInvalid i ReleaseHandle().When you inherit from SafeHandle, you must override the following members: IsInvalid and ReleaseHandle().

Należy również podać domyślnego konstruktora, który wywołuje konstruktora podstawowego o wartości, które reprezentują wartości nieprawidłowego dojścia i Boolean wartość wskazującą, czy uchwyt macierzysty jest własnością SafeHandle i w związku z tym powinna być zwolniona po które SafeHandle został usunięty.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.

Konstruktory

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

Inicjuje nowe wystąpienie klasy SafeHandle klasy z wartością określoną nieprawidłowego dojścia.Initializes a new instance of the SafeHandle class with the specified invalid handle value.

Pola

handle handle handle handle

Określa dojścia w celu jej opakowania.Specifies the handle to be wrapped.

Właściwości

IsClosed IsClosed IsClosed IsClosed

Pobiera wartość wskazującą, czy uchwyt jest zamknięty.Gets a value indicating whether the handle is closed.

IsInvalid IsInvalid IsInvalid IsInvalid

W przypadku przesłonięcia w klasie pochodnej pobiera wartość wskazującą, czy wartość dojścia jest nieprawidłowy.When overridden in a derived class, gets a value indicating whether the handle value is invalid.

Metody

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

Oznacza dojście do zwalniania i zwalnianiu zasobów.Marks the handle for releasing and freeing resources.

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

Ręcznie zwiększa licznik odwołań na SafeHandle wystąpień.Manually increments the reference counter on SafeHandle instances.

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

Zwraca wartość handle pola.Returns the value of the handle field.

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

Dekrementuje ręcznie licznik odwołań na SafeHandle wystąpienia.Manually decrements the reference counter on a SafeHandle instance.

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

Zwalnia wszelkie zasoby używane przez SafeHandle klasy.Releases all resources used by the SafeHandle class.

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

Zwalnia zasoby niezarządzane używane przez SafeHandle klasa określająca, czy wykonać normalnego dispose operacji.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)

Określa, czy określony obiekt jest równy bieżącemu obiektowi.Determines whether the specified object is equal to the current object.

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

Zwalnia wszystkie zasoby skojarzone z uchwytu.Frees all resources associated with the handle.

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

Służy jako domyślnej funkcji skrótu.Serves as the default hash function.

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

Pobiera Type bieżącego wystąpienia.Gets the Type of the current instance.

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

Tworzy płytką kopię bieżącego Object.Creates a shallow copy of the current Object.

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

W przypadku przesłonięcia w klasie pochodnej, wykonuje kod wymagane zwolnienie uchwytu.When overridden in a derived class, executes the code required to free the handle.

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

Ustawia określone dojście istniejące uchwytu.Sets the handle to the specified pre-existing handle.

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

Oznacza uchwyt tak nie jest już używana.Marks a handle as no longer used.

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

Zwraca ciąg, który reprezentuje bieżący obiekt.Returns a string that represents the current object.

(Inherited from Object)

Zabezpieczenia

InheritanceDemand
aby uzyskać pełne zaufanie dla obiektów dziedziczących.for full trust for inheritors. Ten element członkowski nie może być dziedziczona przez częściowo zaufany kod.This member cannot be inherited by partially trusted code.

SecurityCriticalAttribute
Wymaga pełnego zaufania do bezpośredniego obiektu wywołującego.requires full trust for the immediate caller. Ten element członkowski nie może być używany przez częściowo zaufany lub przejrzysty kod.This member cannot be used by partially trusted or transparent code.

Dotyczy

Zobacz też