1

状況:

  • 特定のレジストリ キーのすべてのサブキーのリストを取得する必要があります。
  • 32 ビットと 64 ビットの両方のソフトウェア キーにアクセスする必要があるため、レジストリの名前空間を使用できません。
  • .Net 3.5 で CSharp を使用し、advapi32.dll のレジストリ機能を使用する

ほとんどの機能が動作していますが、エラーが発生しています。値を含むキーに到達すると、それをスキップするか、次のエラーをスローします。

  • 「xxxxx.exe の 0x00C819CD で未処理の例外: 0xC0000005: アクセス違反書き込み場所 0x00720077.」

エラーが発生した場合、どちらの catch ステートメントにも到達しません。プログラムを激しくクラッシュさせます。フォーラムで読んだことから、保護されたメモリへの書き込みに問題がある可能性があると思いますが、表示される例はすべてC ++用です

私の宣言 (P/Invoke Interop Assistant から):

    [DllImportAttribute("advapi32.dll", EntryPoint = "RegEnumKeyExW")]
    public static extern int RegEnumKeyExW(
        [InAttribute()] IntPtr hKey, 
        uint dwIndex, 
        [OutAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] StringBuilder lpName, 
        ref uint lpcchName, 
        IntPtr lpReserved, 
        IntPtr lpClass, 
        IntPtr lpcchClass, 
        IntPtr lpftLastWriteTime);

私の機能(明らかに進行中の作業なので、少し面倒です):

    static private List<string> GetSubKeys(UIntPtr inHive, String inKeyName, RegSAM in32or64key) {
        int hkey = 0;
        uint dwIndex = 0;
        long enumStatus = 0;

        List<string> keys = new List<string>();
        try {
            uint lResult = RegOpenKeyEx(
                HKEY_LOCAL_MACHINE,
                inKeyName,
                0,
                (int)RegSAM.QueryValue | (int)RegSAM.EnumerateSubKeys | (int)in32or64key,
                out hkey);

            if (lResult == 0) {

                while (enumStatus == ERROR_SUCCESS) {
                    StringBuilder lpName = new StringBuilder();
                    uint lpcchName = 256;
                    IntPtr lpReserved = IntPtr.Zero;
                    IntPtr lpClass = IntPtr.Zero;
                    IntPtr lpcchClass = IntPtr.Zero;
                    IntPtr lpftLastWriteTime = IntPtr.Zero;

                    enumStatus = RegEnumKeyExW(
                        (IntPtr)hkey,
                        dwIndex,
                        lpName,
                        ref lpcchName,
                        lpReserved,
                        lpClass,
                        lpcchClass,
                        lpftLastWriteTime);

                    switch (enumStatus) {
                        case ERROR_SUCCESS:
                            Console.WriteLine(string.Format("Key Found: {0}", lpName.ToString()));
                            break;
                        case ERROR_NO_MORE_ITEMS:
                            break;
                        default:
                            string error = new System.ComponentModel.Win32Exception((int)enumStatus).Message;
                            Console.WriteLine(string.Format("RegEnumKeyEx Error: {0}", error));

                            break;
                    }
                    dwIndex++;
                }
            } else {
                Console.WriteLine(string.Format("RegOpenKey Error: {0}", lResult));
            }
        } catch (System.Runtime.InteropServices.COMException ex) {
            Console.WriteLine(string.Format("COM Error: {0}", ex.Message));
        } catch (Exception ex) {
            Console.WriteLine(string.Format("Managed Error: {0}", ex.Message));
        } finally {
            if (0 != hkey) RegCloseKey(hkey);
        }
        return keys;
    }

    #endregion
4

3 に答える 3

1
    StringBuilder lpName = new StringBuilder();
    uint lpcchName = 256;

StringBuilder の容量について嘘をついています。256 ではなく 0 です。これにより、pinvoke 呼び出しによって GC ヒープが破損します。これにより、通常はガベージ コレクションが行われるときに、最終的にハード クラッシュが発生します。修理:

    uint lpcchName = 256;
    StringBuilder lpName = new StringBuilder(lpcchName);

代わりに .NET RegistryKey.GetSubKeyNames() メソッドを使用するのが賢明でしょう。

于 2014-12-08T18:28:22.447 に答える