Object.Finalize メソッド
定義
重要
一部の情報は、リリース前に大きく変更される可能性があるプレリリースされた製品に関するものです。 Microsoft は、ここに記載されている情報について、明示または黙示を問わず、一切保証しません。
オブジェクトが、ガベージ コレクションによって収集される前に、リソースの解放とその他のクリーンアップ操作の実行を試みることができるようにします。
!Object ()
~Object ();
abstract member Finalize : unit -> unit
override this.Finalize : unit -> unit
Finalize ()
例
次の例では、オーバーライドする Finalize オブジェクトが破棄されたときにメソッドが呼び出されることを確認します Finalize 。 実稼働アプリケーションでは、 Finalize オブジェクトによって保持されているアンマネージ リソースを解放するためにメソッドがオーバーライドされることに注意してください。 また、C# の例では、メソッドをオーバーライドする代わりにデストラクターが Finalize 提供されることにも注意してください。
using System;
using System.Diagnostics;
public class ExampleClass
{
Stopwatch sw;
public ExampleClass()
{
sw = Stopwatch.StartNew();
Console.WriteLine("Instantiated object");
}
public void ShowDuration()
{
Console.WriteLine("This instance of {0} has been in existence for {1}",
this, sw.Elapsed);
}
~ExampleClass()
{
Console.WriteLine("Finalizing object");
sw.Stop();
Console.WriteLine("This instance of {0} has been in existence for {1}",
this, sw.Elapsed);
}
}
public class Demo
{
public static void Main()
{
ExampleClass ex = new ExampleClass();
ex.ShowDuration();
}
}
// The example displays output like the following:
// Instantiated object
// This instance of ExampleClass has been in existence for 00:00:00.0011060
// Finalizing object
// This instance of ExampleClass has been in existence for 00:00:00.0036294
open System.Diagnostics
type ExampleClass() =
let sw = Stopwatch.StartNew()
do
printfn "Instantiated object"
member this.ShowDuration() =
printfn $"This instance of {this} has been in existence for {sw.Elapsed}"
override this.Finalize() =
printfn "Finalizing object"
sw.Stop()
printfn $"This instance of {this} has been in existence for {sw.Elapsed}"
let ex = ExampleClass()
ex.ShowDuration()
// The example displays output like the following:
// Instantiated object
// This instance of ExampleClass has been in existence for 00:00:00.0011060
// Finalizing object
// This instance of ExampleClass has been in existence for 00:00:00.0036294
Imports System.Diagnostics
Public Class ExampleClass
Dim sw As StopWatch
Public Sub New()
sw = Stopwatch.StartNew()
Console.WriteLine("Instantiated object")
End Sub
Public Sub ShowDuration()
Console.WriteLine("This instance of {0} has been in existence for {1}",
Me, sw.Elapsed)
End Sub
Protected Overrides Sub Finalize()
Console.WriteLine("Finalizing object")
sw.Stop()
Console.WriteLine("This instance of {0} has been in existence for {1}",
Me, sw.Elapsed)
End Sub
End Class
Module Demo
Public Sub Main()
Dim ex As New ExampleClass()
ex.ShowDuration()
End Sub
End Module
' The example displays output like the following:
' Instantiated object
' This instance of ExampleClass has been in existence for 00:00:00.0011060
' Finalizing object
' This instance of ExampleClass has been in existence for 00:00:00.0036294
メソッドをオーバーライドするその他の Finalize 例については、メソッドを GC.SuppressFinalize 参照してください。
注釈
この Finalize メソッドは、オブジェクトが破棄される前に、現在のオブジェクトによって保持されているアンマネージ リソースに対してクリーンアップ操作を実行するために使用されます。 メソッドは保護されているため、このクラスまたは派生クラスを介してのみアクセスできます。
このセクションの内容は次のとおりです。
最終処理のしくみ
このクラスは Object メソッドの実装を Finalize 提供しません。ガベージ コレクターは、メソッドをオーバーライドしない限り、ファイナライズの Object 派生型を Finalize マークしません。
型がメソッドを Finalize オーバーライドする場合、ガベージ コレクターは、型の各インスタンスのエントリを、ファイナライズ キューと呼ばれる内部構造体に追加します。 ファイナライズ キューには、ガベージ コレクターがメモリを解放する前にファイナライズ コードを実行する必要があるマネージド ヒープ内のすべてのオブジェクトのエントリが含まれています。 その後、ガベージ コレクターは、次の条件で Finalize メソッドを自動的に呼び出します。
オブジェクトがメソッドの呼び出しによって最終処理から除外されていない限り、ガベージ コレクターがオブジェクトにアクセスできないことを GC.SuppressFinalize 検出した後。
.NET Frameworkのみ、アプリケーション ドメインのシャットダウン中に、オブジェクトがファイナライズから除外されない限り。 シャットダウン中に、まだアクセス可能なオブジェクトも最終処理されます。
Finalizeは、特定のインスタンスで 1 回だけ自動的に呼び出されます。ただし、オブジェクトが次のようなGC.ReRegisterForFinalizeGC.SuppressFinalizeメカニズムを使用して再登録され、メソッドが後で呼び出されていない場合を除きます。
Finalize 操作には、次の制限があります。
ファイナライザーが実行される正確な時刻は未定義です。 クラスのインスタンスに対するリソースの確定的な解放を保証するには、メソッドを
Close
実装するか、実装を IDisposable.Dispose 提供します。2 つのオブジェクトのファイナライザーは、一方のオブジェクトが他方を参照している場合でも、特定の順序で実行される保証はありません。 つまり、オブジェクト A にオブジェクト B への参照があり、両方にファイナライザーがある場合、オブジェクト A のファイナライザーの開始時にオブジェクト B が既に終了している可能性があります。
ファイナライザーを実行するスレッドが指定されていません。
メソッドは Finalize 、次の例外的な状況では、完了まで実行されないか、まったく実行されない可能性があります。
別のファイナライザーが無期限にブロックする場合 (無限ループに入り、取得できないロックの取得を試みます)。 ランタイムはファイナライザーの実行を完了しようとするため、ファイナライザーが無期限にブロックされると、他のファイナライザーが呼び出されない可能性があります。
ランタイムにクリーンアップの機会を与えずにプロセスが終了した場合。 この場合、ランタイムのプロセス終了の最初の通知は、DLL_PROCESS_DETACH通知です。
終了可能なオブジェクトの数が減少し続けている間のみ、ランタイムはシャットダウン中にオブジェクトの最終処理を続行します。
例外がスローされ、ランタイムが既定のポリシーをオーバーライドするアプリケーションによってホストされていない場合Finalize、ランタイムはプロセスを終了し、アクティブなtry
/finally
ブロックやファイナライザーは実行されません。Finalize この動作により、ファイナライザーがリソースを解放または破棄できない場合に、プロセスの整合性が確保されます。
Finalize メソッドのオーバーライド
ファイル ハンドルや、それらを使用するマネージド オブジェクトがガベージ コレクション中に破棄されるときに解放する必要があるデータベース接続など、アンマネージ リソースを使用するクラスをオーバーライド Finalize する必要があります。 ガベージ コレクターはマネージド リソースを Finalize 自動的に解放するため、マネージド オブジェクトのメソッドを実装しないでください。
重要
アンマネージ リソースを SafeHandle ラップするオブジェクトが使用可能な場合は、オーバーライド Finalizeではなく、安全なハンドルを使用して破棄パターンを実装することをお勧めします。 詳細については、 SafeHandle の別の セクションを参照してください。
このメソッドは Object.Finalize 既定では何も行いませんが、必要な場合にのみオーバーライド Finalize し、アンマネージド リソースのみを解放する必要があります。 ファイナライズ操作を実行すると、少なくとも 2 つのガベージ コレクションが必要になるため、メモリの再利用にははるかに時間がかかる傾向があります。 さらに、参照型のメソッドのみをオーバーライド Finalize する必要があります。 共通言語ランタイムは、参照型のみを最終処理します。 値型のファイナライザーは無視されます。
メソッドの Object.Finalize スコープは protected
. クラス内でこのメソッドをオーバーライドする場合は、このスコープの範囲を維持する必要があります。 メソッドを Finalize 保護することで、アプリケーションのユーザーがオブジェクトのメソッドを直接呼び出すの Finalize を防ぐことができます。
派生型のすべての実装 Finalize では、その基本型の実装 Finalizeを呼び出す必要があります。 これは、アプリケーション コードが呼び出 Finalizeしを許可されている唯一のケースです。 オブジェクトの Finalize メソッドは、基底クラス以外のオブジェクトに対してメソッドを呼び出さないでください。 これは、共通言語ランタイムがシャットダウンされる場合など、呼び出し元のオブジェクトと呼び出された別のオブジェクトが同時にガベージ コレクションされることがあるからです。
注意
C# コンパイラでは、メソッドをオーバーライド Finalize できません。 代わりに、クラスの デストラクター を実装してファイナライザーを提供します。 C# デストラクターは、基底クラスのデストラクターを自動的に呼び出します。
Visual C++ には、メソッドを実装するための独自の Finalize 構文も用意されています。 詳細については、「 方法: クラスと構造体の定義と使用 (C++/CLI)」の「デストラクターとファイナライザー」セクションを参照してください。
ガベージ コレクションは決定論的ではないため、ガベージ コレクターが最終処理をいつ実行するかを正確に把握できません。 リソースをすぐに解放するには、 破棄パターン と IDisposable インターフェイスを実装することもできます。 実装は IDisposable.Dispose 、クラスのコンシューマーがアンマネージ リソースを解放するために呼び出すことができます。また、メソッドが呼び出されない場合は、そのメソッドを使用 Finalize してアンマネージ リソースを Dispose 解放できます。
Finalize は、ガベージ コレクション中にクリーンアップされた後にオブジェクトを再取得する (つまり、オブジェクトを再びアクセスできるようにする) など、ほぼすべてのアクションを実行できます。 ただし、オブジェクトは 1 回だけ再復活できます。 Finalize は、ガベージ コレクション中に復活したオブジェクトで呼び出すことができません。
代替手段としての SafeHandle
信頼性の高いファイナライザーの作成は、多くの場合、アプリケーションの状態に関する仮定を行うことができないため、およびファイナライザーの終了などのOutOfMemoryExceptionStackOverflowExceptionハンドルされないシステム例外のため、困難です。 クラスのファイナライザーを実装してアンマネージ リソースを解放する代わりに、クラスから System.Runtime.InteropServices.SafeHandle 派生したオブジェクトを使用してアンマネージ リソースをラップし、ファイナライザーを使用せずに破棄パターンを実装できます。 .NET Frameworkは、次のクラスからSystem.Runtime.InteropServices.SafeHandle派生した名前空間をMicrosoft.Win32提供します。
SafeFileHandle はファイル ハンドルのラッパー クラスです。
SafeMemoryMappedFileHandle は、メモリ マップされたファイル ハンドルのラッパー クラスです。
SafeMemoryMappedViewHandle は、アンマネージ メモリのブロックへのポインターのラッパー クラスです。
SafeNCryptKeyHandle、 SafeNCryptProviderHandleおよび SafeNCryptSecretHandle 暗号化ハンドルのラッパー クラスです。
SafePipeHandle はパイプ ハンドルのラッパー クラスです。
SafeRegistryHandle は、レジストリ キーへのハンドルのラッパー クラスです。
SafeWaitHandle は待機ハンドルのラッパー クラスです。
次の例では、メソッドをオーバーライドする代わりに、安全なハンドルを持つ dispose パターン を Finalize 使用します。 特定のファイル拡張子を FileAssociation
持つファイルを処理するアプリケーションに関するレジストリ情報をラップするクラスを定義します。 Windows RegOpenKeyEx 関数呼び出しによってパラメーターとしてout
返される 2 つのレジストリ ハンドルがコンストラクターにSafeRegistryHandle渡されます。 その後、型の保護された Dispose
メソッドがメソッドを SafeRegistryHandle.Dispose
呼び出して、これら 2 つのハンドルを解放します。
using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
public class FileAssociationInfo : IDisposable
{
// Private variables.
private String ext;
private String openCmd;
private String args;
private SafeRegistryHandle hExtHandle, hAppIdHandle;
// Windows API calls.
[DllImport("advapi32.dll", CharSet= CharSet.Auto, SetLastError=true)]
private static extern int RegOpenKeyEx(IntPtr hKey,
String lpSubKey, int ulOptions, int samDesired,
out IntPtr phkResult);
[DllImport("advapi32.dll", CharSet= CharSet.Unicode, EntryPoint = "RegQueryValueExW",
SetLastError=true)]
private static extern int RegQueryValueEx(IntPtr hKey,
string lpValueName, int lpReserved, out uint lpType,
string lpData, ref uint lpcbData);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int RegSetValueEx(IntPtr hKey, [MarshalAs(UnmanagedType.LPStr)] string lpValueName,
int Reserved, uint dwType, [MarshalAs(UnmanagedType.LPStr)] string lpData,
int cpData);
[DllImport("advapi32.dll", SetLastError=true)]
private static extern int RegCloseKey(UIntPtr hKey);
// Windows API constants.
private const int HKEY_CLASSES_ROOT = unchecked((int) 0x80000000);
private const int ERROR_SUCCESS = 0;
private const int KEY_QUERY_VALUE = 1;
private const int KEY_SET_VALUE = 0x2;
private const uint REG_SZ = 1;
private const int MAX_PATH = 260;
public FileAssociationInfo(String fileExtension)
{
int retVal = 0;
uint lpType = 0;
if (!fileExtension.StartsWith("."))
fileExtension = "." + fileExtension;
ext = fileExtension;
IntPtr hExtension = IntPtr.Zero;
// Get the file extension value.
retVal = RegOpenKeyEx(new IntPtr(HKEY_CLASSES_ROOT), fileExtension, 0, KEY_QUERY_VALUE, out hExtension);
if (retVal != ERROR_SUCCESS)
throw new Win32Exception(retVal);
// Instantiate the first SafeRegistryHandle.
hExtHandle = new SafeRegistryHandle(hExtension, true);
string appId = new string(' ', MAX_PATH);
uint appIdLength = (uint) appId.Length;
retVal = RegQueryValueEx(hExtHandle.DangerousGetHandle(), String.Empty, 0, out lpType, appId, ref appIdLength);
if (retVal != ERROR_SUCCESS)
throw new Win32Exception(retVal);
// We no longer need the hExtension handle.
hExtHandle.Dispose();
// Determine the number of characters without the terminating null.
appId = appId.Substring(0, (int) appIdLength / 2 - 1) + @"\shell\open\Command";
// Open the application identifier key.
string exeName = new string(' ', MAX_PATH);
uint exeNameLength = (uint) exeName.Length;
IntPtr hAppId;
retVal = RegOpenKeyEx(new IntPtr(HKEY_CLASSES_ROOT), appId, 0, KEY_QUERY_VALUE | KEY_SET_VALUE,
out hAppId);
if (retVal != ERROR_SUCCESS)
throw new Win32Exception(retVal);
// Instantiate the second SafeRegistryHandle.
hAppIdHandle = new SafeRegistryHandle(hAppId, true);
// Get the executable name for this file type.
string exePath = new string(' ', MAX_PATH);
uint exePathLength = (uint) exePath.Length;
retVal = RegQueryValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, out lpType, exePath, ref exePathLength);
if (retVal != ERROR_SUCCESS)
throw new Win32Exception(retVal);
// Determine the number of characters without the terminating null.
exePath = exePath.Substring(0, (int) exePathLength / 2 - 1);
// Remove any environment strings.
exePath = Environment.ExpandEnvironmentVariables(exePath);
int position = exePath.IndexOf('%');
if (position >= 0) {
args = exePath.Substring(position);
// Remove command line parameters ('%0', etc.).
exePath = exePath.Substring(0, position).Trim();
}
openCmd = exePath;
}
public String Extension
{ get { return ext; } }
public String Open
{ get { return openCmd; }
set {
if (hAppIdHandle.IsInvalid | hAppIdHandle.IsClosed)
throw new InvalidOperationException("Cannot write to registry key.");
if (! File.Exists(value)) {
string message = String.Format("'{0}' does not exist", value);
throw new FileNotFoundException(message);
}
string cmd = value + " %1";
int retVal = RegSetValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0,
REG_SZ, value, value.Length + 1);
if (retVal != ERROR_SUCCESS)
throw new Win32Exception(retVal);
} }
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
// Ordinarily, we release unmanaged resources here;
// but all are wrapped by safe handles.
// Release disposable objects.
if (disposing) {
if (hExtHandle != null) hExtHandle.Dispose();
if (hAppIdHandle != null) hAppIdHandle.Dispose();
}
}
}
open Microsoft.Win32.SafeHandles
open System
open System.ComponentModel
open System.IO
open System.Runtime.InteropServices
// Windows API constants.
let HKEY_CLASSES_ROOT = 0x80000000
let ERROR_SUCCESS = 0
let KEY_QUERY_VALUE = 1
let KEY_SET_VALUE = 0x2
let REG_SZ = 1u
let MAX_PATH = 260
// Windows API calls.
[<DllImport("advapi32.dll", CharSet= CharSet.Auto, SetLastError=true)>]
extern int RegOpenKeyEx(nativeint hKey, string lpSubKey, int ulOptions, int samDesired, nativeint& phkResult)
[<DllImport("advapi32.dll", CharSet= CharSet.Unicode, EntryPoint = "RegQueryValueExW", SetLastError=true)>]
extern int RegQueryValueEx(nativeint hKey, string lpValueName, int lpReserved, uint& lpType, string lpData, uint& lpcbData)
[<DllImport("advapi32.dll", SetLastError = true)>]
extern int RegSetValueEx(nativeint hKey, [<MarshalAs(UnmanagedType.LPStr)>] string lpValueName, int Reserved, uint dwType, [<MarshalAs(UnmanagedType.LPStr)>] string lpData, int cpData)
[<DllImport("advapi32.dll", SetLastError=true)>]
extern int RegCloseKey(unativeint hKey)
type FileAssociationInfo(fileExtension: string) =
// Private values.
let ext =
if fileExtension.StartsWith "." |> not then
"." + fileExtension
else
fileExtension
let mutable args = ""
let mutable hAppIdHandle = Unchecked.defaultof<SafeRegistryHandle>
let mutable hExtHandle = Unchecked.defaultof<SafeRegistryHandle>
let openCmd =
let mutable lpType = 0u
let mutable hExtension = 0n
// Get the file extension value.
let retVal = RegOpenKeyEx(nativeint HKEY_CLASSES_ROOT, fileExtension, 0, KEY_QUERY_VALUE, &hExtension)
if retVal <> ERROR_SUCCESS then
raise (Win32Exception retVal)
// Instantiate the first SafeRegistryHandle.
hExtHandle <- new SafeRegistryHandle(hExtension, true)
let appId = String(' ', MAX_PATH)
let mutable appIdLength = uint appId.Length
let retVal = RegQueryValueEx(hExtHandle.DangerousGetHandle(), String.Empty, 0, &lpType, appId, &appIdLength)
if retVal <> ERROR_SUCCESS then
raise (Win32Exception retVal)
// We no longer need the hExtension handle.
hExtHandle.Dispose()
// Determine the number of characters without the terminating null.
let appId = appId.Substring(0, int appIdLength / 2 - 1) + @"\shell\open\Command"
// Open the application identifier key.
let exeName = String(' ', MAX_PATH)
let exeNameLength = uint exeName.Length
let mutable hAppId = 0n
let retVal = RegOpenKeyEx(nativeint HKEY_CLASSES_ROOT, appId, 0, KEY_QUERY_VALUE ||| KEY_SET_VALUE, &hAppId)
if retVal <> ERROR_SUCCESS then
raise (Win32Exception retVal)
// Instantiate the second SafeRegistryHandle.
hAppIdHandle <- new SafeRegistryHandle(hAppId, true)
// Get the executable name for this file type.
let exePath = String(' ', MAX_PATH)
let mutable exePathLength = uint exePath.Length
let retVal = RegQueryValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, &lpType, exePath, &exePathLength)
if retVal <> ERROR_SUCCESS then
raise (Win32Exception retVal)
// Determine the number of characters without the terminating null.
let exePath =
exePath.Substring(0, int exePathLength / 2 - 1)
// Remove any environment strings.
|> Environment.ExpandEnvironmentVariables
let position = exePath.IndexOf '%'
if position >= 0 then
args <- exePath.Substring position
// Remove command line parameters ('%0', etc.).
exePath.Substring(0, position).Trim()
else
exePath
member _.Extension =
ext
member _.Open
with get () = openCmd
and set (value) =
if hAppIdHandle.IsInvalid || hAppIdHandle.IsClosed then
raise (InvalidOperationException "Cannot write to registry key.")
if not (File.Exists value) then
raise (FileNotFoundException $"'{value}' does not exist")
let cmd = value + " %1"
let retVal = RegSetValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, REG_SZ, value, value.Length + 1)
if retVal <> ERROR_SUCCESS then
raise (Win32Exception retVal)
member this.Dispose() =
this.Dispose true
GC.SuppressFinalize this
member _.Dispose(disposing) =
// Ordinarily, we release unmanaged resources here
// but all are wrapped by safe handles.
// Release disposable objects.
if disposing then
if hExtHandle <> null then hExtHandle.Dispose()
if hAppIdHandle <> null then hAppIdHandle.Dispose()
interface IDisposable with
member this.Dispose() =
this.Dispose()
Imports Microsoft.Win32.SafeHandles
Imports System.ComponentModel
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text
Public Class FileAssociationInfo : Implements IDisposable
' Private variables.
Private ext As String
Private openCmd As String
Private args As String
Private hExtHandle, hAppIdHandle As SafeRegistryHandle
' Windows API calls.
Private Declare Unicode Function RegOpenKeyEx Lib"advapi32.dll" _
Alias "RegOpenKeyExW" (hKey As IntPtr, lpSubKey As String, _
ulOptions As Integer, samDesired As Integer, _
ByRef phkResult As IntPtr) As Integer
Private Declare Unicode Function RegQueryValueEx Lib "advapi32.dll" _
Alias "RegQueryValueExW" (hKey As IntPtr, _
lpValueName As String, lpReserved As Integer, _
ByRef lpType As UInteger, lpData As String, _
ByRef lpcbData As UInteger) As Integer
Private Declare Function RegSetValueEx Lib "advapi32.dll" _
(hKey As IntPtr, _
<MarshalAs(UnmanagedType.LPStr)> lpValueName As String, _
reserved As Integer, dwType As UInteger, _
<MarshalAs(UnmanagedType.LPStr)> lpData As String, _
cpData As Integer) As Integer
Private Declare Function RegCloseKey Lib "advapi32.dll" _
(hKey As IntPtr) As Integer
' Windows API constants.
Private Const HKEY_CLASSES_ROOT As Integer = &h80000000
Private Const ERROR_SUCCESS As Integer = 0
Private Const KEY_QUERY_VALUE As Integer = 1
Private Const KEY_SET_VALUE As Integer = &h2
Private REG_SZ As UInteger = 1
Private Const MAX_PATH As Integer = 260
Public Sub New(fileExtension As String)
Dim retVal As Integer = 0
Dim lpType As UInteger = 0
If Not fileExtension.StartsWith(".") Then
fileExtension = "." + fileExtension
End If
ext = fileExtension
Dim hExtension As IntPtr = IntPtr.Zero
' Get the file extension value.
retVal = RegOpenKeyEx(New IntPtr(HKEY_CLASSES_ROOT), fileExtension, 0,
KEY_QUERY_VALUE, hExtension)
if retVal <> ERROR_SUCCESS Then
Throw New Win32Exception(retVal)
End If
' Instantiate the first SafeRegistryHandle.
hExtHandle = New SafeRegistryHandle(hExtension, True)
Dim appId As New String(" "c, MAX_PATH)
Dim appIdLength As UInteger = CUInt(appId.Length)
retVal = RegQueryValueEx(hExtHandle.DangerousGetHandle(), String.Empty, _
0, lpType, appId, appIdLength)
if retVal <> ERROR_SUCCESS Then
Throw New Win32Exception(retVal)
End If
' We no longer need the hExtension handle.
hExtHandle.Dispose()
' Determine the number of characters without the terminating null.
appId = appId.Substring(0, CInt(appIdLength) \ 2 - 1) + "\shell\open\Command"
' Open the application identifier key.
Dim exeName As New string(" "c, MAX_PATH)
Dim exeNameLength As UInteger = CUInt(exeName.Length)
Dim hAppId As IntPtr
retVal = RegOpenKeyEx(New IntPtr(HKEY_CLASSES_ROOT), appId, 0,
KEY_QUERY_VALUE Or KEY_SET_VALUE, hAppId)
If retVal <> ERROR_SUCCESS Then
Throw New Win32Exception(retVal)
End If
' Instantiate the second SafeRegistryHandle.
hAppIdHandle = New SafeRegistryHandle(hAppId, True)
' Get the executable name for this file type.
Dim exePath As New string(" "c, MAX_PATH)
Dim exePathLength As UInteger = CUInt(exePath.Length)
retVal = RegQueryValueEx(hAppIdHandle.DangerousGetHandle(), _
String.Empty, 0, lpType, exePath, exePathLength)
If retVal <> ERROR_SUCCESS Then
Throw New Win32Exception(retVal)
End If
' Determine the number of characters without the terminating null.
exePath = exePath.Substring(0, CInt(exePathLength) \ 2 - 1)
exePath = Environment.ExpandEnvironmentVariables(exePath)
Dim position As Integer = exePath.IndexOf("%"c)
If position >= 0 Then
args = exePath.Substring(position)
' Remove command line parameters ('%0', etc.).
exePath = exePath.Substring(0, position).Trim()
End If
openCmd = exePath
End Sub
Public ReadOnly Property Extension As String
Get
Return ext
End Get
End Property
Public Property Open As String
Get
Return openCmd
End Get
Set
If hAppIdHandle.IsInvalid Or hAppIdHandle.IsClosed Then
Throw New InvalidOperationException("Cannot write to registry key.")
End If
If Not File.Exists(value) Then
Dim message As String = String.Format("'{0}' does not exist", value)
Throw New FileNotFoundException(message)
End If
Dim cmd As String = value + " %1"
Dim retVal As Integer = RegSetValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0,
REG_SZ, value, value.Length + 1)
If retVal <> ERROR_SUCCESS Then
Throw New Win32Exception(retVal)
End If
End Set
End Property
Public Sub Dispose() _
Implements IDisposable.Dispose
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
Protected Sub Dispose(disposing As Boolean)
' Ordinarily, we release unmanaged resources here
' but all are wrapped by safe handles.
' Release disposable objects.
If disposing Then
If hExtHandle IsNot Nothing Then hExtHandle.Dispose()
If hAppIdHandle IsNot Nothing Then hAppIdHandle.Dispose()
End If
End Sub
End Class