6

RegistryKey クラスを使用してWindows レジストリにアクセスする.NETモジュールで奇妙な動作を見つけています。

たとえば、レジ​​ストリにアクセスする .NET モジュール testcom.dll を作成しました。この testcom.dll ファイルは、ネイティブ 32 ビット アプリケーションと 64 ビット アプリケーションの両方で使用されます。私の要件は、regkey の値を取得することです (パスはHKEY_LOCAL_MACHINE\SOFTWARE\Test\MyParametersで、キー名は ですAge)。この「Age」キーは、32 ビット マシンでは 32 ビット レジストリにあり、64 ビット マシンでは 64 ビット レジストリ (WOW64 ではない) にあります。

64 ビット マシンで、32 ビット アプリケーションが testcom.dll を使用している場合、キー「Age」が WOW64 レジストリで検索されます。64 ビット アプリケーションが testcom.dll を使用している場合、キー「Age」が 64 ビット レジストリで検索されます。

私の要件は、アプリケーションが testcom.dll ファイルを使用するものは何でも、64 ビット マシン上の 64 ビット レジストリのキーを読み取ることです。これどうやってするの?

4

5 に答える 5

9

ターゲットの .Net バージョンを v4 に変更できる場合は、新しい OpenBaseKey 関数を使用できます。

RegistryKey registryKey;
if (Environment.Is64BitOperatingSystem == true)
{
    registryKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
}
else
{
    registryKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
}
于 2010-06-01T18:19:52.257 に答える
5

これについて詳しく調べたところ、.NET 4ではマネージコードで簡単に処理できることがわかりましたが、.NET 4より前では、DLLIMportadvapi32.dllをロードする必要があります。

これが私の研究です。

http://www.rhyous.com/2011/01/24/how-read-the-64-bit-registry-from-a-32-bit-application-or-vice-versa/

于 2011-01-25T02:59:10.777 に答える
4

私は同様の問題を抱えていましたが、私が見つけた最良の答えは、Win32 レジストリ関数 ( RegOpenKeyExなど) にフォールバックし、適切なレジストリ キーのセキュリティとアクセス権を渡すことです。具体的には、samDesiredパラメーターとKEY_WOW64_64KEY.

それはひどいものでした。ここでより良い答えが得られることを願っています。

于 2009-09-24T10:08:17.407 に答える
2

次のコードでGetAge()は、キー値が返されるか、キーが存在しない場合は null が返されます。

[DllImport("Advapi32.dll")]
static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out int phkResult);
[DllImport("Advapi32.dll")]
static extern uint RegCloseKey(int hKey);
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
public static extern int RegQueryValueEx(int hKey, string lpValueName, int lpReserved, ref uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData);

public const int KEY_QUERY_VALUE = 0x0001;
public const int KEY_WOW64_64KEY = 0x0100;

static public string GetAge()
{
    string EPG_REGKEY = @"SOFTWARE\Test\MyParameters";
    UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
    int hkey = 0;

    try
    {
        uint lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, EPG_REGKEY, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, out hkey);
        if (0 != lResult) return null;
        uint lpType = 0;
        uint lpcbData = 1024;
        StringBuilder AgeBuffer = new StringBuilder(1024);
        RegQueryValueEx(hkey, "Age", 0, ref lpType, AgeBuffer, ref lpcbData);
        string Age = AgeBuffer.ToString();
        return Age;
    }
    finally
    {
        if (0 != hkey) RegCloseKey(hkey);
    }
}
于 2009-11-12T15:26:37.237 に答える
2

Win32 APIに戻すことに関するブレアの答えと、その中でRegOpenKeyEx関数を呼び出すことは、これを達成するための最良の方法です。

Windows 自体は、レジストリ リダイレクターレジストリ リフレクションを使用して、特定のレジストリの場所を論理ビューにマップします。

このプロセスの詳細については、次の MSDN 記事を参照してください:
レジストリ内の 32 ビットおよび 64 ビットのアプリケーション データ

Win32 API がこれを実現するための最良の方法であるにもかかわらず、取得しようとしているレジストリの場所を「ハードコーディング」する可能性がありますが、これには問題が発生する可能性があります (Microsoft 自身はこの方法をサポートしていません)。 . これについて詳しくは、スタック オーバーフローの質問:
64 ビット .NET アプリケーションから WOW64 レジストリ キーを開く方法を参照してください。

最終的に、現時点では Win32 API が (最もエレガントではないにしても) 最良のソリューションのようです。
Microsoft の Heath Stewart は、この MSDN Socialの質問で次の回答を提供しています。

残念ながら、これらのフラグを Microsoft.Win32 名前空間のマネージ レジストリ API に渡す方法はありません。あなたが言及したRegCreateKeyExなどのネイティブAPIをP/Invokeする必要があります。

ただし、レジストリの 32 ビット ビューまたは 64 ビット ビューにデータを格納する必要があるかどうかを検討してください。MSDN のトピック レジストリ リダイレクターには、リダイレクトされるキーがあり、おそらくご存知でしょう。トピック レジストリ リフレクションには、32 ビット キーと 64 ビット キーの間で値がコピーされるキーがあります。

実際に個別のビューが必要な場合は、32 ビット アプリケーションと 64 ビット アプリケーションの両方で少なくとも一部のレジストリ データを共有する必要がある場合は、キーのレジストリ リフレクションを有効にすることも検討してください。詳細については、RegEnableReflectionKey のドキュメントを参照してください。

于 2009-09-24T10:24:27.997 に答える