動作確認環境:C# 8.0(.NET Core 3.1)、9.0(.NET 5.0)
C#ではWin32 APIで取得したレジストリキーハンドルHKEY
からMicrosoft.Win32.RegistryKey
を作成するとキーの名前(Name
プロパティ)が空の文字列""
になります。ZwQueryKey
関数に準ずるNtQueryKey
関数を使用すればキーの名前を取得できます。
ただし、NtQueryKey
は非公開APIであり仕様変更の可能性があります。また取得される名前はリダイレクト前の名前です。
トップレベルステートメント(C# 9)
using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32.SafeHandles; const uint KEY_READ = 0x20019; using var keyHandle = NativeMethods.RegOpenKeyExW( NativeMethods.HKEY_CLASSES_ROOT, ".txt", 0, KEY_READ); var name = QueryRegistryKeyName(keyHandle); // \REGISTRY\USER\<ログオンユーザーのSID>_Classes\.txt [return: MaybeNull] static string QueryRegistryKeyName(SafeRegistryHandle handle) { const int STATUS_BUFFER_TOO_SMALL = unchecked((int)0xC0000023); if (handle == null) return null; var lstatus = NativeMethods.NtQueryKey(handle, KEY_INFORMATION_CLASS.KeyNameInformation, null, 0, out var bufferSize); if (lstatus != STATUS_BUFFER_TOO_SMALL) return null; var buffer = new byte[bufferSize]; lstatus = NativeMethods.NtQueryKey(handle, KEY_INFORMATION_CLASS.KeyNameInformation, buffer, bufferSize, out bufferSize); if (lstatus != 0) return null; var nameLength = BitConverter.ToUInt32(buffer, 0); return Encoding.Unicode.GetString(buffer, sizeof(uint), buffer.Length - sizeof(uint)); } static class NativeMethods { [DllImport("advapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] public static extern int RegOpenKeyExW( IntPtr hKey, [In] string lpSubKey, uint ulOptions, uint samDesired, out SafeRegistryHandle phkResult); [return: MaybeNull] public static SafeRegistryHandle RegOpenKeyExW( IntPtr hKey, [In] string lpSubKey, uint ulOptions, uint samDesired) { // エラー時はhandleがIntPtr.Zeroなのでnullを返す。 RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, out var handle); return handle; } public static IntPtr HKEY_CLASSES_ROOT => new IntPtr((uint)0x80000000); [DllImport("ntdll.dll")] public static extern int NtQueryKey( SafeRegistryHandle KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, byte[] KeyInformation, uint Length, out uint ResultLength); } enum KEY_INFORMATION_CLASS : int { KeyNameInformation = 3, }
コンソールアプリケーションの場合はプロジェクトファイルに<TargetFramework>net5-windows</TargetFramework>
、<UseWindowsForms>true</UseWindowsForms>
を追加します。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net5-windows</TargetFramework> <UseWindowsForms>true</UseWindowsForms> </PropertyGroup> </Project>
Main関数(C# 8)
using System; using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32.SafeHandles; class Program { static void Main() { using var keyHandle = NativeMethods.RegOpenKeyExW( HKEY_CLASSES_ROOT, ".txt", 0, KEY_READ); var name = QueryRegistryKeyName(keyHandle); // \REGISTRY\USER\<ログオンユーザーのSID>_Classes\.txt } private static string QueryRegistryKeyName(SafeRegistryHandle handle) { if (handle == null) return null; var lstatus = NativeMethods.NtQueryKey(handle, KEY_INFORMATION_CLASS.KeyNameInformation, null, 0, out var bufferSize); if (lstatus != STATUS_BUFFER_TOO_SMALL) return null; var buffer = new byte[bufferSize]; lstatus = NativeMethods.NtQueryKey(handle, KEY_INFORMATION_CLASS.KeyNameInformation, buffer, bufferSize, out bufferSize); if (lstatus != 0) return null; var nameLength = BitConverter.ToUInt32(buffer, 0); return Encoding.Unicode.GetString(buffer, 4, buffer.Length - 4); } private static class NativeMethods { [DllImport("advapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] public static extern int RegOpenKeyExW( IntPtr hKey, [In] string lpSubKey, uint ulOptions, uint samDesired, out SafeRegistryHandle phkResult); public static SafeRegistryHandle RegOpenKeyExW( IntPtr hKey, [In] string lpSubKey, uint ulOptions, uint samDesired) { // エラー時はhandleがIntPtr.Zeroなのでnullを返す。 RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, out var handle); return handle; } [DllImport("ntdll.dll")] public static extern int NtQueryKey( SafeRegistryHandle KeyHandle, KEY_INFORMATION_CLASS KeyInformationClass, byte[] KeyInformation, uint Length, out uint ResultLength); } private static IntPtr HKEY_CLASSES_ROOT => new IntPtr((uint)0x80000000); private const uint KEY_READ = 0x20019; private const int STATUS_BUFFER_TOO_SMALL = unchecked((int)0xC0000023); public enum KEY_INFORMATION_CLASS : int { KeyNameInformation = 3, } }
コンソールアプリケーションの場合はプロジェクトファイルに<UseWindowsForms>true</UseWindowsForms>
を追加します。
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <UseWindowsForms>true</UseWindowsForms> </PropertyGroup> </Project>