title: RegLoadAppKey working fine on 32-bit OS, failing on 64-bit OS, even if both processes are 32-bit
body: <p>I'm using .NET 4 and the new <a href="http://msdn.microsoft.com/en-us/library/dd780891.aspx" rel="nofollow noreferrer">RegistryKey.FromHandle</a> call so I can take the hKey I get from opening a software registry file with <a href="http://msdn.microsoft.com/en-us/library/ms724886.aspx" rel="nofollow noreferrer">RegLoadAppKey</a> and operate on it with the existing managed API.</p>
  
  <p>I thought at first it was just a matter of a busted DllImport and my call had an invalid type in the params or a missing MarshalAs or whatever, but looking at other registry functions and their DllImport declarations (for instance, on pinvoke.net), I don't see what else to try (I've had hKey returned as both int and IntPtr, both worked on 32-bit OS and fail on 64-bit OS)</p>
  
  <p>I've got it down to as simple a repro case as I can - it just tries to create a 'random' subkey then write a value to it. It works fine on my Win7 x86 box and fails on Win7 x64 and 2008 R2 x64, even when it's still a 32-bit process, even run from a 32-bit cmd prompt.  EDIT: It also fails in the same way if it's a 64-bit process.
  EDIT: it works fine if the file passed in is empty - the problem case is for the existing software registry hive.  I extracted 'bare' software registry hive files from 2008 r2 (x64) and WHS v1 (x86) iso's and both have the same problem.</p>
  
  <p>on Win7 x86:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>on Win7 x64, as 32-bit:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>on Win7 x64, as 64-bit:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>source:</p>
  
  <pre><code>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;
      }
  }
  </code></pre>