Windows service reading from virtualized registry - c#

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.

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 !

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.

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

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

Is it OK to manually write Wow6432Node entries from VS2010 Deployment Project?

I have a .NET component written in C# that needs to register some registry values under the HKLM hive. I'm expecting this component to be installed on both x86 (32-bit) and x64 (64-bit) boxes running the appropriate flavour of Windows. On 64-bit systems, I want to make sure the component can be used by both 32- and 64-bit hosting processes. I'm stuck with using Visual Studio's deployment projects for the time being.
What I want is for my installer, when run on 64-bit systems, to put its registry entries under HKLM/Software/Blablah, so that when running in a 64-bit process, my component can find its global configuration settings. However, if my component is hosted by a 32-bit process running on the same machine, then it will read from what it thinks is the same key, but which Wow64 will translate to HKLM/Software/Wow6432Node/Blablah.
Is it OK to author my 64-bit installer so that:
it is marked as a x64 installer
it writes the entries under HKLM/Software/Blablah for the benefit of 64-bit processes
it writes exact copies of those entries under
HKLM/Software/Wow6432Node/Blablah for the benefit of 32-bit processes on the same machine.
I'm guessing that because I've marked the installer as x64, I will be forced to author another separate installer specifically for 32-bit systems, which only writes to HKLM/Software/Blablah.
The normal practise is to have both 32 bit and 64 bit install packages. On the 32 bit machine you just run the 32 bit package, on the 64 bit machine you run both.
Trying to handle all the registry and file redirection yourself is a nightmare and it's much better to install a 32 bit package on a 64 bit machine and let the system do the redirection for you. You've got to produce the 32 bit package anyway for 32 bit machines, so it's no extra work.

Categories

Resources