Registry access with C# and "BUILD x86" on a 64bit machine - c#

I have an application (written in C#), which runs on an Windows Server 2008 (64bit). In this application I must check some registry keys regarding the IIS. Among others I want to access the key HKEY_LOCAL_MACHINE\Software\Microsoft\InetStp\Components\WMICompatibility"
to check if the IIS 6 compatibility mode is enabled or not. For this I use Registry.GetValue of Microsoft.Win32.
For some reasons the solution must be compiled with x86. The consequence is, that it is no longer possible to access HKEY_LOCAL_MACHINE\Software\Microsoft\InetStp\Components but it is still possible to read key from HKEY_LOCAL_MACHINE\Software\Microsoft\InetStp. When compiling it with "AnyCPU"-flag the registry-access works fine.
So what is the reason for this behavior? Is there a solution or workaround for this problem?

You are falling foul of registry redirection.
The best solution is to open a 64 bit view of the registry, like this:
using Microsoft.Win32;
...
RegistryKey registryKey =
RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).
OpenSubKey(#"Software\Microsoft\InetStp\Components");
object value = registryKey.GetValue(#"WMICompatibility");
If you want your code to work on both 32 and 64 bit machines then you'll need to code some switching between registry views.
Note: The capability of accessing 64 bit views from 32 bit processes was only added to the .net libraries in .net 4. It seems that prior to that you needed to use native APIs, e.g. with P/Invoke.

Windows x64 has a separate node for x86 programs (not the brightest idea)
All registry keys will be under HKEY_LOCAL_MACHINE\Software\WOW6432Node
More about this issue:
How to view the system registry by using 64-bit versions of Windows
The program still "thinks" it's writing to the same path.
I'd suggest you fix your setup (dispatch) program to write the initial settings in the right place.
Edit, Some "information" from MSDN:
Registry Keys Affected by WOW64

Related

32bit dll not work on 64bit Server C#

I have compiled a c natives 32bit DLL with Dev-C++, create the reference on my asp.net project, write a dllImport directives and use my new DLL. When launch my DEBUG session all work very well but when deploy my project on Web Server the runtime not load my DLL.
My IIS 7.0 w3wp.exe runs as a 64 bit process (to check if your process running as a 32 bit process under WOW64, open the task manager's Process tab and see if the process name contains "*32").
I believe that a 64 bit process can only load 64 bit native DLLs (and managed DLLs built for "Any CPU" or "X64"). Perhaps your debug session is a 32 bit session? If this is the cause, take a look at Using a 32bit or 64bit dll in C# DllImport .
For those of you who still cannot find a proper way to use a 32-bit DLL under a 64-bit IIS Application Pool, either by tweaking the registry, or by trying how to deal with the "COM+ Components Services", I have found a perfectly working solution : "Encapsulating" the 32-bit component into a new COM object as described on this page did the job perfectly, and I think that a lot of you will be interested to solve the problem this way ;)
http://www.chestysoft.com/component-services.asp
In my case, that allowed me to use the "XStandard.Zip" free Component from XStandard, which is sadly only available as a 32-bit ASP component, and that have an "InProcServer32" Key in the registry apparently preventing it to work by tweaking the registry, as described here : https://techtalk.gfi.com/32bit-object-64bit-environment/
In this post, a lot of comments reported that "InProcServer32-IDs are not reflected because Microsoft assumes that these are only InProc-Calls and not Out-Of-Proc-Calls".
And that was my case too, leading me to the situation where the registry tweaking solution described in the previous post was not working in my case, as other users.
Hoping having saved some days... or nights !

Windows service reading from virtualized registry

Please correct me if I'm wrong on this, as I'm certain I read it somewhere: Registry virtualization is disabled for Windows Services. Also, virtualization is disabled for x64 binaries.
I have a windows service written in C# that needs to load a value from HKEY_LOCAL_MACHINE\SOFTWARE. When I compile the service as x86 and start it, it fails to read the value. When I compile the same code as x64 and start it, it reads the value just fine. I want my service to be able to run on x86 machines in addition to x64 machines, but it needs to also be able to read this value. How do I get my windows service to read the value non-virtualized?
Registry virtualization is disabled for Windows Services. Also, virtualization is disabled for x64 binaries.
Yes, you're right, it's disabled for 64 bit processes and for "processes that are not interactive, such as services".
Take a look to my previous post here on SO for some details about registry views. Please do not confuse views with virtualization. They're different. Views are needed to isolate 32-bit application from 64-bit applications.
In C# you can do the same simply asking the OS to open the 64 bit version of the registry:
RegistryKey baseKey = RegistryKey.OpenBaseKey(
RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey key = baseKey.OpenSubKey("Software", false);
object value = key.GetValue("");
If your application/service will run in a 32-bit machine you'll always get the normal registry even if you ask for RegistryView.Registry64. When running in a 64-bit machine you'll always get the normal version of the registry (= 64-bit version).
Side question: why do you need to compile your application as X86 or X64? Can't simply keep AnyCPU?
Virtualization has a different purpose and it's not intended to separate the registry from 32 bit applications but to increase compatibility with legacy applications, we all hope that a 64 bit native application will use the registry in the correct way. To access the non-virtualized version of the registry you have to open the registry key using REG_KEY_DONT_VIRTUALIZE flag. It's not possible to use this flag with Microsoft.Win32 classes so you have to DllImport them and P/Invoke.

Working with the registry on 64 bit system. framework 2.0

How to get a list of subkeys in the HKLM\SOFTWARE in the 64 bit system?
P.S. If I use
Registry.LocalMachine.OpenSubKey("SOFTWARE\\", false)
then I get in HKLM\SOFTWARE\Wow6432Node
I can use the .NET Framework is not higher than 2.0
The answer seems quite involved, and probably too much code to put here on Stack Overflow.
The summary is that you need to P/Invoke to access the native Windows API Calls for RegOpenKeyEx, and make sure to pass in the flag KEY_WOW64_64KEY to always access the 64bit registry. (KEY_WOW64_32KEY being the flag to always access the 32bit one)
A partial solution has been posted on this blog entry.
For anyone that can run .NET 4.0, then you can use the new support for this: RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
You will get the registry for whichever architcture your app is running on or compiled for.
If you target x86 then you will always get the 32-bit registry ("Wow6432Node") on a 64-bit machine.
If you target AnyCPU, then you will get the real Software node for the machine's architecture.

Registry redirection on 64-bit Windows

I am running 64-bit Windows, and I want to create the registry key HKCU\Software\Classes\Wow6432Node\CLSID\{myguid}\InprocServer32 using C#.
What registry key should I tell it to write, so that it will be redirected to the above key? This should also work on 32-bit Windows.
I am compiling my app to target x86.
If you are using .net 4 you should make use of the RegistryView enumeration.
Pass RegistryView.Registry32 when you call OpenBaseKey. Use HKCU\Software\Classes\CLSID{myguid}\InprocServer32 as your key and let the redirector do the work.
If you are using an older version of .net then I am afraid you will need to p/invoke the native Win32 API.
If you happen to be targetting x86 then you don't need to do anything. The registry redirector will do the right thing and redirect your registry access to the 32 bit view of the registry. You only need to take the steps outline above from a 64 bit process.
64-bit versions of Windows emulate 32-bit functionality through the "Windows on Windows" (WoW) subsystem.
In the case of the registry, they move the 32-bit keys over to a special subkey for compatibility reasons. It will automatically redirect 32-bit registry operations to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node. More details can be found on the MSDN topic about the Registry Redirector.
You can use the RegistryView enum on RegistryKey.OpenBaseKey to open the 32-bit view explicitly and access HKCU\Software\Classes\CLSID{myguid}\InprocServer32 directly. This will automatically access the WOW64 node on 64-bit systems and the normal key on 32-bit systems.
Since you are targetting x86, simply using HKCU\Software\Classes\CLSID\{myguid}\InprocServer32 will work on all platforms.
By default your C# application is compiled using "Any CPU" (this is the default -- it means that your program will run as a x86 exe on x86 machine, and x64 on x64 machines). What you want to do is change the setting to Win32.
Now your program will always run as an x86 exe, so it will be automatically redirected by windows the WOW6432Node. When you access the HKCU\Software\Classes\CLSID{myguid}\InprocServer32 on an x64 machine you will be redirected to the desired key.

OpenSubKey under HKLM\Software returning null

Here's my code:
Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(#"SOFTWARE\ADM");
The registry entry exists on the machine. key is always null.
I don't think that this is a security issue. I'm running as Administrator. (I've even explicitly ran the assembly under Administrator mode).
I'm using Visual Studio 2010 running on Windows 7 64bit.
The problem is that I'm running 64bit and my app is compiled as 32bit.
The key being read by:
Microsoft.Win32.RegistryKey key =
Microsoft.Win32.Registry.LocalMachine.OpenSubKey(#"SOFTWARE");
Is not HKLM\SOFTWARE but instead HKLM\SOFTWARE\Wow6432Node\. Compiling the application as x64 solves the problem.
Try opening each registry key individually like this
Microsoft.Win32.RegistryKey key1 = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(#"SOFTWARE");
Microsoft.Win32.RegistryKey key2 = key1.OpenSubKey(#"ADM");
Instead of using the string #"SOFTWARE\ADM";
I've run your code with a different application name (one I have a key for) and everything was ok, so the code is ok, but I tested this on Win XP.
When studying writing to the registry, I found this article about registry virtualization in Windows 7 that might cause your problems:
Windows Vista and later versions of Windows improve application compatibility for these applications by automatically redirecting these operations. For example, registry operations to the global store (HKEY_LOCAL_MACHINE\Software) are redirected to a per-user location within the user's profile known as the virtual store (HKEY_USERS\_Classes\VirtualStore\Machine\Software).

Categories

Resources