Risks of using KEY_WOW64_64KEY on a 32bit application - winapi

We currently have a 32bit application that requires various key/value pairs to be loaded from the registry before use.
Previously we had completed this by loading the .reg as part of the installation. Running it on 64-bit Windows the .reg components end up in the 64-bit store, but our 32-bit application looks in the 32-bit store.
I was thinking of using KEY_WOW64_64KEY to force our 32-bit application to always use the 64-bit store however this answer advises against that. Then I thought we could change the .reg file to point to the 32-bit store but the comment on this answer advises against assuming the key will always be called "Wow6432Node"
Is there any perferred way to do this (other than migrating the whole app to 64-bit)? What are risks of a 32-bit application using the 64-bit store?

As long as you don't pass the HKEY handle to non Reg* functions that expect x86==native registry I don't think there are any risks. (Filesystem redirection on the other hand is not per handle and can cause problems if a sub-function calls LoadLibrary or CoCreateInstance etc)
If using KEY_WOW64_64KEY seems like too much of a hack, why not have the (32 bit) installer write to the registry instead of using .reg files? The only downside by doing this is that if you create a x64 version of your app in the future it will not share the settings with the x86 version. (This might be a good thing or a bad thing)

Related

How do certain Windows DLL apparently manage to support both 32 and 64 bit?

I seem to be able to access the functions in C:\WINDOWS\system32\opengl32.dll (and likewise C:\WINDOWS\system32\glu32.dll) from either a 32-bit or a 64-bit application (for what it's worth, I'm doing this from separate 32-bit and 64-bit Python 2.7 interpreters, via the ctypes module).
With glut32.dll, things are different. It only happens to be on my Path as part of a 32-bit installation of GraphViz. From 32-bit Python, I can link dynamically to it, but from 64-bit Python I get [Error 193] %1 is not a valid Win32 application.
Now, this error does not surprise me, because I had always thought DLLs were obliged to commit to one architecture or another on Windows (in particular, this recent question and its answers seem to say so). What surprises me is the lack of an error in the first case... How does opengl32.dll do it, and how can I replicate this behaviour when building my own DLLs?
On 64 bit system only 64 bit processes use c:\Windows\System32\opengl32.dll. For 32 bit processes system redirects c:\Windows\System32\opengl32.dll to c:\Windows\SysWOW64\opengl32.dll.
File System Redirector
In most cases, whenever a 32-bit application attempts to access %windir%\System32, the access is redirected to %windir%\SysWOW64. Access to %windir%\lastgood\system32 is redirected to %windir%\lastgood\SysWOW64. Access to %windir%\regedit.exe is redirected to %windir%\SysWOW64\regedit.exe.

Install 32 bit files and 64 bit registry settings in WiX installer

Can I set up a 64-bit registry key to refer to a 32-bit program files path using WiX?
I'm writing a plugin for another piece of software. I want my plugin dll to go in C:\Program Files (x86)\MyPlugin\MyPlugin.dll not in C:\Program Files\MyPlugin\MyPlugin.dll because the dll is 32-bit, not 64-bit.
However, I need the registry key to go in HKLM/Software/Company/Product/Etc.... not in HKLM/Wow6432Node/Software/Company/Product/Etc.... because the process that actually reads the registry key is 64-bit. That 64-bit process reads the registry and launches a 32-bit process to sandbox the dll.
Is there any way to do this? I've tried using different components with different Win64 attribute values, and even putting them in separate component groups. However, I keep getting these build errors (not warnings):
ICE80: This 64BitComponent RegistryComponent uses 32BitDirectory INSTALLFOLDER
A somewhat poor solution, but you could just a custom action to add registry entries, if you don't mind them sticking around after an uninstall.
If you write a custom action in C# you can just do something like this:
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
{
// do it
}
If you support 32-bit and 64-bit machines you need two separate MSI setups:
http://blogs.msdn.com/b/heaths/archive/2008/01/15/different-packages-are-required-for-different-processor-architectures.aspx
So your 32-bit install creates any COM entries for any 32-bit Clients and the 64-bit setup has 32-bit and 64-bit components that write to the registry.
http://msdn.microsoft.com/en-us/library/aa367451(v=vs.85).aspx
A rather easy solution to only have one installer version for 32 and 64 bit is to export a .reg file with the keys you want to add (from regedit) and then run a custom action during install, ie:
<CustomAction Id='Add_Registry_Keys' Execute='deferred' Directory='DriverDir' Impersonate='no' ExeCommand='regedit.exe /s "[DriverDir]default.reg' Return='ignore' />
You can suppress ICE errors also, not just warnings. This means you can use Win64 attributes in your x86 msi.
The setting to ignore ICE validations is found in the Project Properties under the Tool Settings tab.
It might not be recommended, but if it works its still better than the alternative of a custom action.

launching correct installer for 32 and 64-bit apps

We have an application which, for various reasons, needs to be compiled as both a 32-bit and 64-bit app. The thing is, we want to distribute both setup files (msi) on a single CD. Is there a launch condition or autorun.inf entry that we can use to know which setup.exe to launch? Or do we need to write a separate little exe that gets called by autorun, and which determines the OS, and calls the appropriate setup.exe?
There does not appear to be any 32/64bit detection support inherent in autorun.inf files.
The convention that most applications which supply a 32 and 64 bit MSI follow is similar to the second option you mention.
Create a single 32bit setup.exe application (so that it will run on either platform). Ideally this will be written in C/C++ so that it is as small and quick as possible, and has no dependencies on other libraries/frameworks (eg. static linked).
Detect if you are running on 64bit or not (see sample code for Windows API IsWow64Process function
Execute the appropriate MSI
You can use a custom action to detect the OS, then call the right installer.
I've given an example here: Single MSI to install correct 32 or 64 bit c# application

How do I read the registry in 32-bit c# app such that registry redirection works on 64-bit Windows 7

My boss just got Windows 7 and he tried running one of our installers which runs perfectly fine under XP. On Windows 7, the installer runs without giving any errors. However, it does not create registry keys under HKEY_LOCAL_MACHINE\SOFTWARE{Company}{product}. These keys get created correctly under XP.
Has anyone encountered this issue? I suspect it is a rights/security issue but I'm not sure and I don't have Windows 7 to experiment with.
EDIT
The computer in question is a 64-bit machine running 64-bit Windows. It turns out Windows 7 redirects 32-bit applications to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node{Company}{product}. The problem is my application code tries to access the registry using a hardcoded value like this:
var t = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\..., "ValueName", DefaultValue);
So, my new question is how do I access the registry such that the Windows 9 registry redirection will just work?
If you're using .NET 4, you can specifically request that your 32-bit (or 64-bit) process access the 64-bit view of the registry using the RegistryKey.OpenBaseKey method.
Cf. http://msdn.microsoft.com/en-us/library/microsoft.win32.registrykey.openbasekey.aspx
Here's an example that reads a value from the 64-bit view of the registry, even if it runs as part of a 32-bit process:
var hklm64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var key = hklm.OpenSubKey(#"SOFTWARE\AcmeSoft\AnvilMaker 1.0");
var value = (string) key.GetValue("Blacksmith Name");
The RegistryKey.OpenBaseKey method also allows you to explicitly open a 32-bit view of the registry. This is useful if you're trying to go the other way around and access the 32-bit view of the registry from a 64-bit process and you don't want to explicitly add "Wow6432Node" to the registry path.
For example, today I needed to delete a sub-key tree in both the 32-bit and 64-bit views of the registry. Doing this in .NET 4 with a single registry path was easy:
foreach(var view in new[] {RegistryView.Registry32, RegistryView.Registry64})
{
var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
hklm.DeleteSubKeyTree(#"SOFTWARE\AcmeSoft\SomeKeyWeNoLongerWant", throwOnMissingSubKey: false);
}
On a 64-bit version of windows, the above code will remove the following sub-key trees from the registry:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\AcmeSoft\SomeKeyWeNoLongerWant
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\AcmeSoft\SomeKeyWeNoLongerWant
-Adam
After more digging I came across this link which describes the registry access rules for .NET applications. My program had initially been targeted for "AnyCpu" which causes the app to target the 64-bit registry even though Windows installed it under the Wow6432Node. By setting the target to "x86" my program "magically" started accessing the registry under the Wow6432Node. Go figure!
In the C Windows API this is done by setting the samDesired parameter in the RegOpenKeyEx call to KEY_WOW64_64KEY. This means that the lookup of the registry value will map onto the regular 64-bit entry, rather than the WOW32Node one. I can't see how you would achieve this in .Net though as the Registry class doesn't appear to support these operations, but maybe it's provided through a newer class?
Registry Reflection
Code Sample

SHGetSpecialFolderPath, how to access 64bit CSIDL from 32bit application

Is there a way from a 32bit application running on a 64bit system to have access to the default folders for 64bit applications?
For example, using SHGetSpecialFolderPath with CSIDL_PROGRAM_FILES from a 32bit application returns "C:\Program Files (x86)' If the same call was used from a 64bit application, I would get "C:\Program Files". Is there a way of getting that "C:\Program Files" from a 32bit application?
A related question here does not help SHGetFolderPath() 32 bit vs 64 bit nor does supressing the wow64 filesystem redirection before calling SHGetSpecialFolderPath
Answering my own question, it seems it is not possible with SHGetSpecialFolderPath. In Vista and later, using the replacement function SHGetKnownFolderPath allows it with FOLDERID_ProgramFilesX64
I believe the whole reason for having separate folders was to prevent 32 and 64 bit applications from mixing. Therefore, you shouldn't need to see a folder belonging to a different bitness from your application.
You may have a very good reason, but I don't see one in your question as posted.

Resources