Avoid Registry Wow6432Node Redirection - c#

I'm trying to insert some simple registry keys using Microsoft.Win32.RegistryKey in c# but the path automatically changes from:
HKEY_LOCAL_MACHINE\SOFTWARE\Test
to
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Test
I tried google but I only get some vague and confusing results. Has anyone dealt with this issue before? Some example code would be much appereciated.

You can use RegistryKey.OpenBaseKey to solve this problem:
var baseReg = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var reg = baseReg.CreateSubKey("Software\\Test");

Under WOW64, certain registry keys are redirected (SOFTWARE). When a 32-bit or 64-bit application makes a registry call for a redirected key, the registry redirector intercepts the call and maps it to the key's corresponding physical registry location. For more information, see Registry Redirector.
You can use the RegistryView Enumeration on RegistryKey.OpenBaseKey Method to open the 32-bit view explicitly and access HKLM\Software\ directly.

I don't know how to solve it using a .reg file. But only in a BAT file, as follow:
You must add /reg:64 at the end of the command line.
ex:
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background" /v "OEMBackground" /t REG_DWORD /d 0x00000001 /f /reg:64
Source: Wow6432Node and how to Deploy Registry settings to 64 bit systems via Sccm

Here is the working code I have developed to both read and write ONLY the 32-bit registry. It works in both 32-bit and 64-bit applications. The 'read' call updates the registry if the value is not set, but it is very obvious how to remove that. It requires .Net 4.0, and uses the OpenBaseKey/OpenSubKey methods.
I currently use it to allow a 64-bit background service and a 32-bit tray application to access the same registry keys seamlessly.
using Microsoft.Win32;
namespace SimpleSettings
{
public class Settings
{
private static string RegistrySubKey = #"SOFTWARE\BlahCompany\BlahApp";
public static void write(string setting, string value)
{
using (RegistryKey registryView = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
using (RegistryKey registryCreate = registryView.CreateSubKey(RegistrySubKey))
using (RegistryKey registryKey = registryView.OpenSubKey(RegistrySubKey, true))
{
registryKey.SetValue(setting, value, RegistryValueKind.String);
}
}
public static string read(string setting, string def)
{
string output = string.Empty;
using (RegistryKey registryView = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
using (RegistryKey registryCreate = registryView.CreateSubKey(RegistrySubKey))
using (RegistryKey registryKey = registryView.OpenSubKey(RegistrySubKey, false))
{
// Read the registry, but if it is blank, update the registry and return the default.
output = (string)registryKey.GetValue(setting, string.Empty);
if (string.IsNullOrWhiteSpace(output))
{
output = def;
write(setting, def);
}
}
return output;
}
}
}
Usage:
Put this in it's own class file (.cs) and call it as such:
using SimpleSettings;
string mysetting = Settings.read("SETTINGNAME","DEFAULTVALUE");

Related

deletesubkeytree not deleting registry folder

I want to delete a folder named EXAMPLE and all values in it in registry that is found under "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\EXAMPLE"
i have tried this ( with true at the end aswell )
Microsoft.Win32.Registry.LocalMachine.DeleteSubKeyTree(#"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\EXAMPLE");
and tried this
string keyName = #"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyName, true))
{
key.DeleteSubKeyTree("EXAMPLE", true);
}
They either throw me a null exception or argument exception.
How can i just delete an entire folder with all its keys ?
So that i can have the similar effect from batch :
REG DELETE "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\EXAMPLE" /f
The path is incorrect, Registry.LocalMachine doesn't have such a sub key #"HKEY_LOCAL_MACHINE\...". You need to start from "SOFTWARE\..".
string keyName = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
And from your feedback, your program is affected by the Registry Redirector, in which HKEY_LOCAL_MACHINE\Software is redirected to HKEY_LOCAL_MACHINE\Software\Wow6432Node for a 32-bit program, recompile your program from AnyCPU (Prefer 32-bit) to x64 gets rid of the redirection.
The mechanism of Registry Redirector varies on different Windows versions, so I leave this to you for further reading to understand why 64/32 matters in this case.

Using OpenSubKey not finding node that exists

I am using the cookie cutter code to get a registry key object in C#:
RegistryKey reg = Registry.LocalMachine.OpenSubKey("SOFTWARE\\MyNewKeyName\\");
After I run this code reg = null. However, if I switch the value passed to OpenSubKey to be any value in the registry under SOFTWARE that has additional nodes below it reg will now have a value. I've tried multiple keys with this pattern and it works. If I put any any key name that does not have additional child nodes it does not work. Ultimately I'm trying to read a string value inside of MyNewKeyName.
Why does my code not work and reg get populated if my key does not have any additional nodes below it?
Well it turns out that the values in the '32-bit' registry and the '64-bit' registry are not identical. So when viewing the registry via 'regedit' and seeing everything, programatically you may not and that's the issue I was running into. I noticed this by running GetSubKeyNames() and inspecting the keys returned. The quick answer is to check both versions of the registry to find the value sought:
//Check the 64-bit registry for "HKEY_LOCAL_MACHINE\SOFTWARE" 1st:
RegistryKey localMachineRegistry64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey reg64 = localMachineRegistry64.OpenSubKey(registryKeyLocation, false);
if (reg64 != null)
{
return reg64.GetValue(registryKeyName, true).ToString();
}
//Check the 32-bit registry for "HKEY_LOCAL_MACHINE\SOFTWARE" if not found in the 64-bit registry:
RegistryKey localMachineRegistry32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
RegistryKey reg32 = localMachineRegistry32.OpenSubKey(registryKeyLocation, false);
if (reg32 != null)
{
return reg32.GetValue(registryKeyName, true).ToString();
}
I think the problem is you are compiling it as x86 instead of compiling it as an x64 application. Follow the below steps:
Right click on Project
Select Properties
Select the Build tab
Change "Platform Target" to "x64"
Now run the project.

C# Cant Access Some Registry Values

I need to read default value of HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Classes\CLSID{CF2CF428-325B-48d3-8CA8-7633E36E5A32}\InprocServer32
In my Project options "Prefer 32-Bit" is unchecked and Platform target is Any CPU, i'm running on Windows-7 64 Bit operating system.
I tried everything and read A LOT of topics about this issue but i can't still read this value.
Please, can you write the actual code ?
I Tried,
RegistryKey LocalMachine32 = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
RegistryKey location = LocalMachine32.OpenSubKey(#"Software\Wow6432Node\Classes\CLSID\{CF2CF428-325B-48d3-8CA8-7633E36E5A32}\InprocServer32", true);
String myValue = location.GetValue("").ToString();
.
RegistryKey LocalMachine64 = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey location = LocalMachine64.OpenSubKey(#"Software\Wow6432Node\Classes\CLSID\{CF2CF428-325B-48d3-8CA8-7633E36E5A32}\InprocServer32", true);
String myValue = location.GetValue("").ToString();
.
RegistryKey LocalMachine64 = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey location = LocalMachine64.OpenSubKey(#"Software\Classes\CLSID\{CF2CF428-325B-48d3-8CA8-7633E36E5A32}\InprocServer32", true);
String myValue = location.GetValue("").ToString();
.
RegistryKey LocalMachine32 = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
RegistryKey location = LocalMachine32.OpenSubKey(#"Software\Classes\CLSID\{CF2CF428-325B-48d3-8CA8-7633E36E5A32}\InprocServer32", true);
String myValue = location.GetValue("").ToString();
But no luck :(
As far as I'm aware you cannot do this with .NET Framework calls; in the past I've used P/Invoke calls to advapi32.dll's RegOpenKeyEx, RegQueryValueEx, and RegQueryValueEx methods to read from a specific bitness registry.
Here is an article with an example of doing this:
http://blogs.msdn.com/b/cumgranosalis/archive/2005/12/19/win64registrypart2.aspx
Edit:
The reason it doesn't work in Windows 7 (along with other potentially helpful resources) is discussed here:
How to open a WOW64 registry key from a 64-bit .NET application

Unable to return a WOW6432 version of a key from 32bit application

I'm trying to read a registry key from my application. It is a 32-bit process and is running on a 64-bit system(Win7 64-bit). This is my code:
string value64 = string.Empty;
RegistryKey localKeyRegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
localKey = localKey.OpenSubKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
if (localKey != null)
{
value64 = localKey.GetValue("RegisteredOrganization").ToString();
MessageBox.Show(value64, "value64");
}
On my system the value under this key(SOFTWARE\Microsoft\Windows NT\CurrentVersion) is empty, and the value under this(SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion) is "Microsoft". But the value64 in the message box is empty! Shouldn't it be "Microsoft"?
You are specifying RegistryView.Registry64 so it will be retrieving the value from SOFTWARE\Microsoft\Windows NT\CurrentVersion
If you specify RegistryView.Registry32 it will retrieve it from SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion instead (that is, on a 64-bit system; on a 32-bit system the WOW6432Node doesn't exist so it will just use the normal hive instead).
I think that if you specify RegistryView.Default it will select the hive according to the bitness of the calling process.

Writing to registry in a C# application

I'm trying to write to the registry using my C# app.
I'm using the answer given here: Writing values to the registry with C#
However for some reason the key isn't added to the registry.
I'm using the following code:
string Timestamp = DateTime.Now.ToString("dd-MM-yyyy");
string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\"+Application.ProductName+"\\"+Application.ProductVersion;
string valueName = "Trial Period";
Microsoft.Win32.Registry.SetValue(key, valueName, Timestamp, Microsoft.Win32.RegistryValueKind.String);
The Application.name and Application.version 'folders' don't exists yet.
Do I have to create them first?
Also, I'm testing it on a 64b Win version so I think if I want to check the registry for the key added I have to specifically check the 32bit registry in: C:\Windows\SysWOW64\regedit.exe don't I?
First of all if you want to edit key under LocalMachine you must run your application under admin rights (better use CurrentUser it's safer or create the key in installer). You have to open key in edit mode too (OpenSubKey method) to add new subkeys. I've checked the code and it works. Here is the code.
RegistryKey key = Registry.LocalMachine.OpenSubKey("Software",true);
key.CreateSubKey("AppName");
key = key.OpenSubKey("AppName", true);
key.CreateSubKey("AppVersion");
key = key.OpenSubKey("AppVersion", true);
key.SetValue("yourkey", "yourvalue");
You can use the following code to create and open the required registry keys.
RegistryKey SoftwareKey = Registry.LocalMachine.OpenSubKey("Software",true);
RegistryKey AppNameKey = SoftwareKey.CreateSubKey("AppName");
RegistryKey AppVersionKey = AppNameKey.CreateSubKey("AppVersion");
AppVersionKey.SetValue("yourkey", "yourvalue");
You can basically use CreateSubKey for all your application settings, as it will open the key for write access, if it already exists, and create it otherwise. There is no need to create first, and then open. OpenSubKey comes in handy when you are absolutely certain the key already exists, like in this case, with "HKEY_LOCAL_MACHINE\SOFTWARE\"
Also check if your registry calls are getting virtualised. See here for more information.
It can happen if your application is not UAC aware and occurs for compatibility reasons.
Real path
HKEY_LOCAL_MACHINE\Software\FooKey
Virtual path
HKEY_USERS\<User SID>_Classes\VirtualStore\Machine\Software\FooKey
Try to open HKLM\Software first. Then create key for your program, and then create key for version. Howewer, your key could be placed at HKLM\software\WOW6432Node. Check this.
The problem is you don't have enough privileges. Here is a way that works for my:
RegistryKey myKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
myKey = myKey.OpenSubKey(subkey, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.FullControl);
if (myKey != null)
{
myKey.SetValue("DefaultPrinterId", ldiPrinters[e.RowIndex].id, RegistryValueKind.String);
myKey.Close();
}
With RegistryKey.OpenBaseKey you open the correct registry, because when you don't have permissions the registry that you write, it does in another location.
By default, your changes will be written to HKLM\SOFTWARE\WOW6432Node\... because of registry redirection. This can be quite confusing.
In order to write to HKLM\SOFTWARE\..., you need to use RegistryKey.OpenBaseKey to open the 64-bit registry:
var path = #"SOFTWARE\...";
var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var key = baseKey.CreateSubKey(path, RegistryKeyPermissionCheck.ReadWriteSubTree);
key.SetValue(name, value, RegistryValueKind.String);
Also, you need to have permission to write to the specified registry key.
You can get permission either by assigning permissions to specific users or service accounts or by running your app in elevated mode.

Categories

Resources