代码之家  ›  专栏  ›  技术社区  ›  James Manning

RegLoadAppKey在32位操作系统上工作正常,在64位操作系统上失败,即使两个进程都是32位的

  •  4
  • James Manning  · 技术社区  · 14 年前

    RegistryKey.FromHandle 打电话给我,这样我就可以拿我打开软件注册表文件时得到的hKey了 RegLoadAppKey 并使用现有的托管API对其进行操作。

    我已经把它归结为一个尽可能简单的repro用例-它只是尝试创建一个“随机”子键,然后向它写入一个值。它在我的Win7 x86机器上工作正常,在Win7 x64和2008 r2x64上失败,即使它仍然是32位进程,甚至从32位cmd提示符运行。编辑:如果是64位进程,它也会以同样的方式失败。

    在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)
    

    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;
        }
    }
    
    2 回复  |  直到 14 年前
        1
  •  2
  •   James Manning    14 年前

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

        2
  •  0
  •   Jatinder Bahl    13 年前

    以下链接在这种情况下应该很有用:

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