【问题标题】:RegLoadAppKey working fine on 32-bit OS, failing on 64-bit OS, even if both processes are 32-bitRegLoadAppKey 在 32 位操作系统上工作正常,在 64 位操作系统上失败,即使两个进程都是 32 位
【发布时间】:2010-05-26 22:32:12
【问题描述】:

我正在使用 .NET 4 和新的 RegistryKey.FromHandle 调用,因此我可以使用通过 RegLoadAppKey 打开软件注册表文件获得的 hKey 并使用现有的托管 API 对其进行操作。

起初我以为这只是 DllImport 失败的问题,而我的调用在参数中的类型无效或缺少 MarshalAs 或其他什么,但查看其他注册表函数及其 DllImport 声明(例如,在 pinvoke. net),我看不出还有什么可以尝试的(我已经将 hKey 作为 int 和 IntPtr 返回,都在 32 位操作系统上工作,在 64 位操作系统上失败)

我已经把它归结为一个尽可能简单的复制案例——它只是尝试创建一个“随机”子键,然后向它写入一个值。它在我的 Win7 x86 机器上运行良好,但在 Win7 x64 和 2008 R2 x64 上运行失败,即使它仍然是 32 位进程,甚至从 32 位 cmd 提示符运行。编辑:如果它是 64 位进程,它也会以同样的方式失败。 编辑:如果传入的文件为空,它工作正常 - 问题案例是针对现有的软件注册表配置单元。我从 2008 r2 (x64) 和 WHS v1 (x86) iso 中提取了“裸”软件注册表配置单元文件,它们都有同样的问题。

在 Win7 x86 上:

INFO: Running as Admin in 32-bit process on 32-bit OS
Was able to create Microsoft\Windows\CurrentVersion\RunOnceEx\a95b1bbf-7a04-4707-bcca-6aee6afbfab7 and write a value under it

在 Win7 x64 上,作为 32 位:

INFO: Running as Admin in 32-bit process on 64-bit OS

Unhandled Exception: System.UnauthorizedAccessException: Access to the registry key '\Microsoft\Windows\CurrentVersion\RunOnceEx\ce6d5ff6-c3af-47f7-b3dc-c5a1b9a3cd22' is denied.
   at Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
   at Microsoft.Win32.RegistryKey.CreateSubKeyInternal(String subkey, RegistryKeyPermissionCheck permissionCheck, Object registrySecurityObj, RegistryOptions registryOptions)
   at Microsoft.Win32.RegistryKey.CreateSubKey(String subkey)
   at LoadAppKeyAndModify.Program.Main(String[] args)

在 Win7 x64 上,作为 64 位:

INFO: Running as Admin in 64-bit process on 64-bit OS

Unhandled Exception: System.UnauthorizedAccessException: Access to the registry key '\Microsoft\Windows\CurrentVersion\RunOnceEx\43bc857d-7d07-499c-8070-574d6732c130' is denied.
   at Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
   at Microsoft.Win32.RegistryKey.CreateSubKeyInternal(String subkey, RegistryKeyPermissionCheck permissionCheck, Object registrySecurityObj, RegistryOptions registryOptions)
   at Microsoft.Win32.RegistryKey.CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck)
   at LoadAppKeyAndModify.Program.Main(String[] args)

来源:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("INFO: Running as {0} in {1}-bit process on {2}-bit OS",
            new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator) ? "Admin" : "Normal User",
            Environment.Is64BitProcess ? 64 : 32,
            Environment.Is64BitOperatingSystem ? 64 : 32);

        if (args.Length != 1)
        {
            throw new ApplicationException("Need 1 argument - path to the software hive file on disk");
        }
        string softwareHiveFile = Path.GetFullPath(args[0]);
        if (File.Exists(softwareHiveFile) == false)
        {
            throw new ApplicationException("Specified file does not exist: " + softwareHiveFile);
        }

        // pick a random subkey so it doesn't already exist
        var existingKeyPath = @"Microsoft\Windows\CurrentVersion";
        var keyPathToCreate = @"RunOnceEx\" + Guid.NewGuid();
        var completeKeyPath = Path.Combine(existingKeyPath, keyPathToCreate);
        var hKey = RegistryNativeMethods.RegLoadAppKey(softwareHiveFile);
        using (var safeRegistryHandle = new SafeRegistryHandle(new IntPtr(hKey), true))
        using (var appKey = RegistryKey.FromHandle(safeRegistryHandle))
        using (var currentVersionKey = appKey.OpenSubKey(existingKeyPath, true))
        {
            if (currentVersionKey == null)
            {
                throw new ApplicationException("Specified file is not a well-formed software registry hive: " + softwareHiveFile);
            }

            using (var randomSubKey = currentVersionKey.CreateSubKey(keyPathToCreate))
            {
                randomSubKey.SetValue("foo", "bar");
                Console.WriteLine("Was able to create {0} and write a value under it", completeKeyPath);
            }
        }
    }
}

internal static class RegistryNativeMethods
{
    [Flags]
    public enum RegSAM
    {
        AllAccess = 0x000f003f
    }

    private const int REG_PROCESS_APPKEY = 0x00000001;

    // approximated from pinvoke.net's RegLoadKey and RegOpenKey
    // NOTE: changed return from long to int so we could do Win32Exception on it
    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern int RegLoadAppKey(String hiveFile, out int hKey, RegSAM samDesired, int options, int reserved);

    public static int RegLoadAppKey(String hiveFile)
    {
        int hKey;
        int rc = RegLoadAppKey(hiveFile, out hKey, RegSAM.AllAccess, REG_PROCESS_APPKEY, 0);

        if (rc != 0)
        {
            throw new Win32Exception(rc, "Failed during RegLoadAppKey of file " + hiveFile);
        }

        return hKey;
    }
}

【问题讨论】:

  • 在 64 位机器上作为 64 位进程运行它是否工作?

标签: c# .net .net-4.0 c#-4.0


【解决方案1】:

最终通过 Microsoft 支持打开了一个支持案例 - 问题特定于 1) 安装媒体上为最新版本的 Windows 提供的配置单元和 2) RegLoadAppKey 作为 API。切换到 RegLoadKey/RegUnLoadKey 对完全相同的文件(甚至在同一进程中)效果很好,并且由于 RegLoadAppKey 中的错误不太可能得到修复(更不用说很快)来处理这些特定文件,我只是切换到RegLoadKey/RegUnLoadKey 代替。

【讨论】:

    【解决方案2】:

    以下链接在这种情况下应该会有所帮助:

    http://msdn.microsoft.com/en-us/library/ms973190.aspx#64mig_topic5

    【讨论】:

    • 欢迎来到 Stack Overflow。你能详细说明一下吗?
    猜你喜欢
    • 2016-09-27
    • 2015-09-26
    • 2013-08-29
    • 1970-01-01
    • 2011-07-06
    • 2012-07-26
    • 2011-12-18
    • 1970-01-01
    • 2012-05-14
    相关资源
    最近更新 更多