Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Friday, February 14, 2014 4:34 AM
This is my code that works fine on 32 bit computers:
public static string GetRegistryKeyValue(string keyPath)
{
using (var shell = AutomationFactory.CreateObject("WScript.Shell"))
{
var keyValue = (string)shell.RegRead(keyPath);
return keyValue;
}
}
This is the key that I need to get:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid
But, the code errors with this key on 64 bit machines. I read something about this over here. I know this something to do with that WOW64 rubbish.
http://msdn.microsoft.com/en-us/library/aa384129%28v=VS.85%29.aspx
But, I can't find an example to do this correctly. I just need to know how to get the value "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid" from the registry on 64 bit machines. Just a code sample or something would be great.
All replies (21)
Friday, February 14, 2014 6:54 AM
Although I haven't tested it for your context specifically, the Registry.GetValue method should work: http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.getvalue(v=vs.110).aspx. Basically, just add the reference/using statement to 'Microsoft.Win32' and call it with the path and name. The docs have usage examples at the bottom of the page.
Wasabi Fan
Friday, February 14, 2014 7:01 AM
Hi, please try:
Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography", "MachineGuid", null)
It works well in 64bit machines
Friday, February 14, 2014 7:12 AM | 2 votes
Hi,
Try the below code to get the required key from the 64bit registry, i tried and was able to get the MAchineGuid from my 64bit system.
RegistryKey localMachineX64View = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey sqlsrvKey = localMachineX64View.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography");
string sqlExpressKeyName = (string)sqlsrvKey.GetValue("MachineGuid");
Hope this helps
SRIRAM
Friday, February 14, 2014 10:10 PM
Oops. I should have been clearer. I'm actually using Silverlight. I was going to post this in the Silverlight forum, but 99% of Silverlight programmers never touch the registry so I posted it here.
Actually, I need to use either winapi calls directly, or to automate a COM/Active X object. The Microsoft.Win32 references are not available in Silverlight. That's why I posted here. But, thanks for the replies so far.
Monday, February 17, 2014 12:30 AM
Any WinAPI calls I can make to do this?
Monday, February 17, 2014 2:12 AM
So, I've been trying to understand how this Wow6432Node stuff supposedly works. The exact key I'm trying to get is:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid
The crazy thing is that this key exists. I can see it in Regedit, and Regedit32. Which brings me to the question: is Regedit 64bit, or 32bit on Windows 7 64bit? I would have assumed that Regedit was 64bit and Regedit32 was 32bit, but they both show me the same key in the same place.
I can not however find the same key under:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography
So, what the hell is going on? I'm completely left in the dark here.
Monday, February 17, 2014 2:18 AM
So, the question is: how can I use the low level Windows API calls to get 32 bit registry values in a 64 bit app?
Monday, February 17, 2014 3:37 AM
Alright, so I think I'm on the right path. Here is a class I created based on an example I found:
public static class Registry
{
#region Enums
public enum RegistryRoot : uint
{
HKEY_LOCAL_MACHINE = 0x80000002,
HKEY_CURRENT_USER = 0x80000001
}
public enum SamDesiredFlag : int
{
KEY_ALL_ACCESS = 0x3F,
KEY_WOW64_64KEY = 0x0100,
KEY_WOW64_32KEY = 0x0200
}
#endregion
#region Imports
[DllImport("advapi32.dll", EntryPoint = "RegOpenKeyEx")]
private static extern int RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out UIntPtr phkResult);
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
private static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName, int lpReserved, out uint lpType, StringBuilder lpData, ref int lpcbData);
#endregion
#region Public Static Methods
public static string GetRegistryValue(RegistryRoot rootFolder, string path, string keyName, SamDesiredFlag samDesired)
{
//Variables
UIntPtr hKeyVal;
int errorCode;
uint lpType;
StringBuilder retVal = new StringBuilder(100);
int lpcbData = retVal.Capacity;
//The full path of the value
var pathString = rootFolder.ToString() + "\\" + path;
//Attempt to open the registry key
errorCode = RegOpenKeyEx((UIntPtr)RegistryRoot.HKEY_LOCAL_MACHINE, path, 0, (int)samDesired, out hKeyVal);
if (errorCode != 0)
{
//Display error code of failed attempt to open registry key
throw new Exception(string.Format("Opening path {0} failed with error code {1}", pathString, errorCode));
}
//Attempt to load the value frpm the registry
errorCode = RegQueryValueEx(hKeyVal, keyName, 0, out lpType, retVal, ref lpcbData);
if (errorCode != 0)
{
//Display the error code of failed attempt to open registry key
throw new Exception(string.Format("Opening value {0} from {1} failed with error code {2}", keyName, pathString, errorCode));
}
//Returned the tostring'd version of the string builder
return retVal.ToString();
}
The example is from here: http://forums.codeguru.com/showthread.php?351034-How-to-run-a-very-long-SQL-statement
Now according to this article:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129(v=vs.85).aspx
I should be able to simply pass in KEY_WOW64_32KEY to the samDesired flag in order to get 32bit values from the registry but it is failing.
This is what I tried:
var regValue = Registry.GetRegistryValue(Registry.RegistryRoot.HKEY_LOCAL_MACHINE, @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography", "MachineGuid", Registry.SamDesiredFlag.KEY_WOW64_32KEY);
It fails with error code 2. But, this works fine:
var regValue = Registry.GetRegistryValue(Registry.RegistryRoot.HKEY_LOCAL_MACHINE, @"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString", Registry.SamDesiredFlag.KEY_ALL_ACCESS);
Monday, February 17, 2014 11:40 PM
Bump.
Tuesday, February 18, 2014 12:15 AM
Just because a machine is 64 bit doesn't mean the program is 64bit. The program uses the registry key it wants to use regardless of the machine configuration. As for your Silverlight issue you are really better off working with that forum because there are too many quirks to it that trip us up. Thus the reason perhaps for having to dive to the win32 layer (which make no sense to me)...
JP Cowboy Coders Unite!
Tuesday, February 18, 2014 12:17 AM
I assume you've already been down the full trust route and it's still not working?
JP Cowboy Coders Unite!
Tuesday, February 18, 2014 12:27 AM
Thanks for your reply.
Yes, I am working in elevated trust mode. And, yes, I already have gotten the API calls to work as I pointed out. It just doesn't work for the particular key I need. I'm not making any assumptions about bit versions. All, I'm saying is that I've tried every possible recommend way to use the API call RegOpenKeyEx to get at the key I need, but this particular key can't be accessed, and other people are complaining about the same thing.
I didn't post this on the Silverlight forum because I would get 0 response there. As I said, 99% of Silverlight coders will have never needed to touch the registry.
This is a purely Windows API question. Just to nail that point home, I will convert my code sample to WPF so as to prove the Silverlight thing is not the issue.
To reiterate. The key is:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid
As far as I can tell, it simply does not exist under the Wow6432Node
Thursday, February 20, 2014 7:42 AM
Hi
Try this code to access the registry from a 64bit machine.
//For getting the 64bit registry view.
RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey crypto = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Cryptography");
string mac_guid = Convert.ToString(crypto.GetValue("MachineGuid"));
Console.WriteLine(mac_guid);
Hope this help.
Thursday, February 20, 2014 9:22 PM
I can't use these methods. I need to use Windows API calls. Please see the code I have posted.
Thursday, February 20, 2014 10:46 PM
OK. Just to make things a lot clearer and remove Silverlight from the equation. I have created a WPF app with exactly the same code. To reiterate, this is a Windows API issue. I am not going to use the wrapper classes for the registry. So, again, here is my code which works for some registry entries and compiles under .Net.
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Adapt.Utilities.Common
{
public static class Registry
{
#region Enums
public enum RegistryRoot : uint
{
HKEY_LOCAL_MACHINE = 0x80000002,
HKEY_CURRENT_USER = 0x80000001
}
public enum SamDesiredFlag : int
{
KEY_ALL_ACCESS = 0x3F,
KEY_WOW64_64KEY = 0x0100,
KEY_WOW64_32KEY = 0x0200
}
#endregion
#region Imports
[DllImport("advapi32.dll", EntryPoint = "RegOpenKeyEx")]
private static extern int RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out UIntPtr phkResult);
[DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
private static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName, int lpReserved, out uint lpType, StringBuilder lpData, ref int lpcbData);
#endregion
#region Public Static Methods
public static string GetRegistryValue(RegistryRoot rootFolder, string path, string keyName, SamDesiredFlag samDesired)
{
//Variables
UIntPtr hKeyVal;
int errorCode;
uint lpType;
StringBuilder retVal = new StringBuilder(100);
int lpcbData = retVal.Capacity;
//The full path of the value
var pathString = rootFolder.ToString() + "\\" + path;
//Attempt to open the registry key
errorCode = RegOpenKeyEx((UIntPtr)RegistryRoot.HKEY_LOCAL_MACHINE, path, 0, (int)samDesired, out hKeyVal);
if (errorCode != 0)
{
//Display error code of failed attempt to open registry key
throw new Exception(string.Format("Opening path {0} failed with error code {1}", pathString, errorCode));
}
//Attempt to load the value frpm the registry
errorCode = RegQueryValueEx(hKeyVal, keyName, 0, out lpType, retVal, ref lpcbData);
if (errorCode != 0)
{
//Display the error code of failed attempt to open registry key
throw new Exception(string.Format("Opening value {0} from {1} failed with error code {2}", keyName, pathString, errorCode));
}
//Returned the tostring'd version of the string builder
return retVal.ToString();
}
#endregion
}
}
Now this is the Code Behind for my WPF app MainWindow:
using Adapt.Utilities.Common;
using System.Windows;
namespace RegistryTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var regValue = Registry.GetRegistryValue(Registry.RegistryRoot.HKEY_LOCAL_MACHINE, @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography", "MachineGuid", Registry.SamDesiredFlag.KEY_WOW64_32KEY);
//var regValue = Registry.GetRegistryValue(Registry.RegistryRoot.HKEY_LOCAL_MACHINE, @"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString", Registry.SamDesiredFlag.KEY_ALL_ACCESS);
}
}
}
The first line fails because the key can not be opened. The call to RegOpenKeyEx fails with an error code of 2. The second (commented) line works fine and returns the correct value.
Can someone please help to get the first line working?
Friday, February 21, 2014 12:08 AM
OK. Scrap what I just said. The error with the first line above is blatantly obvious and I should have picked it up. So, I set the WPF app to build for a x64 chip. It works in both Debug, and Release modes. But, it does not work when built for an x86 chip. I ran it with this line of code:
var regValue = Registry.GetRegistryValue(Registry.RegistryRoot.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Cryptography", "MachineGuid", Registry.SamDesiredFlag.KEY_ALL_ACCESS);
However, this code does not run in Silverlight. Which means 1 of two things. Silverlight is not running in 64 bit mode, or there is some inherent problem with getting this registry key from within Silverlight. But, this is weird seeing that I was able to get this registry key on 32 bit machines. Anyway, it looking like this thread should be moved to Silverlight after all, please don't move it just yet. I just want to confirm whether this is a Silverlight specific problem, or a CPU Bit version specific problem.
Monday, February 24, 2014 10:06 PM
Caillen Zhong - I realise that your bosses give you "points" when you close down threads, but I am relying on this thread to get information so I can solve a technical problem.
How would you like it I just closed down support tickets or whatever when you were trying to solve a problem?
Always ask before you mark posts as answered. Its common courtesy.
Monday, February 24, 2014 10:32 PM
MSDN discusses how registry virtualization works in a 64-bit app so I recommend you refer to it for the full details about how this works. The key does exist in x64 and if you request read access you will get that key. There aren't 64 and 32-bit versions of the registry, just 1. With virtualization requests to certain keys will be silently redirected to subkeys, that's the only difference. In the few cases where a 32/64-bit app needs to access the portion of the registry that would normally be redirected (ie. installers) then you can use the special API outlined earlier. In normal code you don't need this.
The problem you're running into is Silverlight. Silverlight apps do not have access to the registry out of the box. This is by design and a security feature. Here's an article that discusses the one scenario where you can do it. In theory if you've done everything the article says then you should have read access to HKLM and it should work. But since you're having issues then I recommend that you post this question over in the SL forums where they can help you out.
Monday, February 24, 2014 11:06 PM
Thanks CoolDadTx. You've made some things clearer, but still I'm a bit in the dark about what "Registry Virtualisation" means in this case. I will read up more and try to understand it - and why it is different between .Net and Silverlight.
I know that out of the box, Silverlight does not support reading the registry - that is why I am working in elevated trust mode and am accessing API calls directly.
I will start a new thread on the Silverlight forum, but I need to be careful about how I go about it. Silverlight developers are a different breed so I need to be able explain the problem carefully before I post it.
Monday, March 3, 2014 2:03 AM
The plot thickens once again. So, again - we are back to talking about the WPF app only.
So, I have come realise that this is not only a 64x vs. x86 issue. It is also about registry permissions.
I attempted to run my WPF test app today, and it failed. I wondered why because I was running it in 64 bit mode. Then, I realised that I had not run VS with "Run As Administrator" as I normally do. So, the app failed. What this probably means is that the test WPF app is inheriting permissions from the DEVENV process itself and this particular registry value requires administrative privileges. That is probably the key to getting this to work in Silverlight as well: enabling administrative privileges.
Monday, March 3, 2014 3:09 AM
Even though I am convinced this is not a Silverlight issue because I am now able to open this value in Silverlight 64bit, I have moved this question here: