SafeHandle SafeHandle SafeHandle SafeHandle Class

定義

オペレーティング システム ハンドルのラッパー クラスを表します。Represents a wrapper class for operating system handles. このクラスは継承する必要があります。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
継承
派生
属性
実装

次のコード例から派生するオペレーティング システム ファイル ハンドル用のカスタムのセーフ ハンドルを作成します。SafeHandleZeroOrMinusOneIsInvalidします。The following code example creates a custom safe handle for an operating system file handle, deriving from SafeHandleZeroOrMinusOneIsInvalid. ファイルからバイトを読み取るし、16 進数の値が表示されます。It reads bytes from a file and displays their hexadecimal values. テスト ハーネスの障害も含まれています。 スレッドを中止するには、原因となったが、ハンドル値は解放されます。It also contains a fault testing harness that causes the thread to abort, but the handle value is freed. 使用する場合、IntPtrハンドルを表す、ハンドルが非同期のスレッドの中止のためリーク場合があります。When using an IntPtr to represent handles, the handle is occasionally leaked due to the asynchronous thread abort.

コンパイル済みのアプリケーションと同じフォルダー内のテキスト ファイルを必要があります。You will need a text file in the same folder as the compiled application. コマンドラインの使用方法は、"hexviewer"だというアプリケーションの名前を入力すると仮定した場合です。Assuming that you name the application "HexViewer", the command line usage is:

HexViewer <filename> -Fault

必要に応じて指定-Fault意図的に特定のウィンドウでスレッドを中止することによって、ハンドルをリークしようとします。Optionally specify -Fault to intentionally attempt to leak the handle by aborting the thread in a certain window. Windows Perfmon.exe ツールを使用すると、エラーを作り出す中にハンドル カウントを監視できます。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);
                }
            }

        }
    }
}

注釈

SafeHandleハンドル リソース、およびガベージ コレクションによって途中で回収されてから意図しないアンマネージ オブジェクトを参照する Windows では、リサイクル中にハンドルを防止のクリティカル ファイナライズがクラスに用意されています。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.

このトピックには、次のセクションがあります。This topic includes the following sections:

なぜ SafeHandle でしょうか。 Why SafeHandle?
SafeHandle の特長 What SafeHandle does
SafeHandle から派生したクラスClasses derived from SafeHandle

なぜ SafeHandle でしょうか。Why SafeHandle?

.NET Framework version 2.0 では、すべてのオペレーティング システム ハンドルでしたのみにカプセル化する前に、IntPtrマネージ ラッパー オブジェクト。Before the .NET Framework version 2.0, all operating system handles could only be encapsulated in the IntPtr managed wrapper object. これは、ネイティブ コードと相互運用する便利な方法でしたが予期せず中止されたスレッドまたはスタック オーバーフローなどの非同期例外によってハンドルがリークする可能性があります。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. これらの非同期例外は妨げにオペレーティング システムのリソースをクリーンアップして、アプリでほぼどこでも発生することができます。These asynchronous exceptions are an obstacle to cleaning up operating system resources, and they can occur almost anywhere in your app.

上書きをObject.Finalizeオブジェクトがガベージ コレクション、状況によってをされているときに、メソッドがアンマネージ リソースのクリーンアップを許可する、ファイナライズ可能なオブジェクトは、プラットフォーム内でのメソッドの実行中にガベージ コレクションによって解放することができますを呼び出す呼び出します。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. ファイナライザーは、そのプラットフォームに渡されるハンドルを解放する場合は、呼び出し、ハンドルの破損する可能性が。If a finalizer frees the handle passed to that platform invoke call, it could lead to handle corruption. プラットフォームの中に、メソッドがブロックされている間、ハンドルが解放もされるなど、ファイルの読み取り中に呼び出しを起動します。The handle could also be reclaimed while your method is blocked during a platform invoke call, such as while reading a file.

非常により、Windows では、積極的にハンドルを再利用、ため、ハンドルはリサイクルされ、機密データを含む可能性がある別のリソースをポイントが。More critically, because Windows aggressively recycles handles, a handle could be recycled and point to another resource that might contain sensitive data. これは、リサイクルの攻撃と呼ばれますとできますデータが破損する可能性のあるセキュリティの脅威となります。This is known as a recycle attack and can potentially corrupt data and be a security threat.

SafeHandle の特長What SafeHandle does

SafeHandleクラスは、これらオブジェクトの有効期間に関する問題のいくつかを簡素化し、プラットフォームと統合されて起動オペレーティング システムのリソースがリークしないようにします。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クラスは、割り当てと解放を中断することがなくハンドルによってオブジェクトの有効期間に関する問題を解決します。The SafeHandle class resolves object lifetime issues by assigning and releasing handles without interruption. によって、ハンドルが閉じられるし、予期しない時に実行することが保証 クリティカル ファイナライザーが含まれているAppDomainアンロードされると、プラットフォーム呼び出しの場合であってが破損した状態であると見なされます。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.

SafeHandle継承CriticalFinalizerObject、クリティカル ファイナライザーの前に、すべてのクリティカル ファイナライザーと呼ばれます。Because SafeHandle inherits from CriticalFinalizerObject, all the noncritical finalizers are called before any of the critical finalizers. 同じガベージ コレクションの実行中にライブは不要になったオブジェクトでは、ファイナライザーが呼び出されます。The finalizers are called on objects that are no longer live during the same garbage collection pass. たとえば、FileStreamオブジェクトがリークまたはリサイクルされるハンドルのリスクを負うことがなくバッファー内の既存のデータをフラッシュする通常のファイナライザーを実行できます。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. 一般的な用途は、重要および重大でないファイナライザーの間でこの非常に弱い順序付けすることはありません。This very weak ordering between critical and noncritical finalizers is not intended for general use. 使用するこれらのライブラリを許可することで既存のライブラリの移行を支援するには、主に存在するSafeHandleのセマンティクスを変更することがなく。It exists primarily to assist in the migration of existing libraries by allowing those libraries to use SafeHandle without altering their semantics. さらに、クリティカル ファイナライザーと何も呼び出してなど、SafeHandle.ReleaseHandle()メソッドが制約された実行領域である必要があります。Additionally, the critical finalizer and anything it calls, such as the SafeHandle.ReleaseHandle() method, must be in a constrained execution region. これには、ファイナライザーの呼び出しグラフ内でどのようなコードを記述する制約が適用されます。This imposes constraints on what code can be written within the finalizer's call graph.

プラットフォームが自動的に操作を呼び出しによってカプセル化されたハンドルの参照カウントをインクリメント、SafeHandleと完了時にそれらをデクリメントします。Platform invoke operations automatically increment the reference count of handles encapsulated by a SafeHandle and decrement them upon completion. これにより、ハンドル リサイクルまたはされませんを閉じました。This ensures that the handle will not be recycled or closed unexpectedly.

基になるハンドルの所有権を指定するには、構築するときにSafeHandleオブジェクトに値を指定して、ownsHandle引数、SafeHandleクラスのコンス トラクター。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. これを制御するかどうか、SafeHandleオブジェクトは、オブジェクトが破棄された後に、ハンドルが解放されます。This controls whether the SafeHandle object will release the handle after the object has been disposed. これは特殊な有効期間の要件でのハンドルまたは有効期限が他のユーザーによって制御されるハンドルを使用するために役立ちます。This is useful for handles with peculiar lifetime requirements or for consuming a handle whose lifetime is controlled by someone else.

SafeHandle から派生したクラスClasses derived from SafeHandle

SafeHandle オペレーティング システム ハンドルの抽象ラッパー クラスです。SafeHandle is an abstract wrapper class for operating system handles. このクラスからの派生は困難です。Deriving from this class is difficult. 代わりに、次のセーフ ハンドルを提供する Microsoft.Win32.SafeHandles 名前空間の派生クラスを使用してください。Instead, use the derived classes in the Microsoft.Win32.SafeHandles namespace that provide safe handles for the following:

注意 (継承者)

派生したクラスを作成するSafeHandleを作成し、オペレーティング システム ハンドルを解放する方法を理解する必要があります。To create a class derived from SafeHandle, you must know how to create and free an operating system handle. 別のハンドル型の一部を使用しているために、このプロセスは異なる、 CloseHandle関数などのより特定の機能を使用しながらunmapviewoffile にまたは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. このための派生クラスを作成する必要がありますSafeHandleでセーフ ハンドルをラップするオペレーティング システム ハンドルの種類ごとにします。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.

SafeHandle から継承する場合は、IsInvalid メンバーと ReleaseHandle() メンバーをオーバーライドする必要があります。When you inherit from SafeHandle, you must override the following members: IsInvalid and ReleaseHandle().

値は、無効なハンドル値を表す、基本コンス トラクターを呼び出す既定のコンス トラクターを提供することも必要があります、Booleanネイティブ ハンドルを所有するかどうかを示す値、SafeHandleされ、その結果はときに解放する必要がありますSafeHandleは破棄されています。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.

コンストラクター

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

指定した無効なハンドル値を使用して、SafeHandle クラスの新しいインスタンスを初期化します。Initializes a new instance of the SafeHandle class with the specified invalid handle value.

フィールド

handle handle handle handle

ラップするハンドルを指定します。Specifies the handle to be wrapped.

プロパティ

IsClosed IsClosed IsClosed IsClosed

ハンドルが閉じているかどうかを示す値を取得します。Gets a value indicating whether the handle is closed.

IsInvalid IsInvalid IsInvalid IsInvalid

派生クラスでオーバーライドされると、ハンドル値が無効かどうかを示す値を取得します。When overridden in a derived class, gets a value indicating whether the handle value is invalid.

メソッド

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

リソースを解放するためのハンドルをマークします。Marks the handle for releasing and freeing resources.

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

SafeHandle インスタンスの参照カウンターを手動でインクリメントします。Manually increments the reference counter on SafeHandle instances.

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

handle フィールドの値を返します。Returns the value of the handle field.

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

SafeHandle インスタンスの参照カウンターを手動でデクリメントします。Manually decrements the reference counter on a SafeHandle instance.

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

SafeHandle クラスによって使用されているすべてのリソースを解放します。Releases all resources used by the SafeHandle class.

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

通常の破棄操作を実行するかどうかを指定して、SafeHandle クラスによって使用されているアンマネージ リソースを解放します。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)

指定したオブジェクトが、現在のオブジェクトと等しいかどうかを判断します。Determines whether the specified object is equal to the current object.

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

ハンドルに関連付けられたすべてのリソースを解放します。Frees all resources associated with the handle.

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

既定のハッシュ関数として機能します。Serves as the default hash function.

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

現在のインスタンスの Type を取得します。Gets the Type of the current instance.

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

現在の Object の簡易コピーを作成します。Creates a shallow copy of the current Object.

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

派生クラスでオーバーライドされると、ハンドルを解放するために必要なコードを実行します。When overridden in a derived class, executes the code required to free the handle.

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

ハンドルを指定した既存のハンドルに設定します。Sets the handle to the specified pre-existing handle.

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

今後は使用しないものとしてハンドルをマークします。Marks a handle as no longer used.

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

現在のオブジェクトを表す文字列を返します。Returns a string that represents the current object.

(Inherited from Object)

セキュリティ

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.

適用対象

こちらもご覧ください