RegLoadAppKey在32位操作系统上运行良好,在64位操作系统上失败,即使两个进程都是32位

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

我一开始以为这只是一个被破坏的DllImport的问题而且我的调用在params中有一个无效的类型或者缺少MarshalAs或者其他什么,但是查看其他注册表函数及其DllImport声明(例如,在pinvoke.net上),我没有看到还有什么要尝试(我已经将hKey作为int和IntPtr返回,两者都在32位操作系统上运行并在64位操作系统上失败)

我已经把它归结为一个简单的repro案例 – 它只是尝试创建一个’随机’子键然后写一个值。 它在我的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; } } 

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

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

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