I am trying to fetch MachineGuid
from the registry, to create some level of binding with the OS for my license system. From the documentation I can use
string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography";
string r = (string)Registry.GetValue(key, "MachineGuid", (object)"default");
to get it. Also, the docs tell me that I get "default"
when the name is not found, or null
if the key doesn't exist. I should get a security exception if I have no access.
The above code gives me "default"
, which means the name isn't found. However, if I look in the registry with RegEdit, it's there. How do I get the MachineGuid
value from an application without administrator privileges?
Update: when using reg.exe
I have no problems getting the value.
Update: I updated the title, so people looking for a unique way of determining the Windows install get here as well.
which is probably why it doesn't work reliably among different versions of Windows
No, that's not the reason. This problem is caused by the platform target selection for your EXE project. Project + Properties, Build tab, Platform target combobox. You have it set to x86 instead of AnyCPU. On VS2012, the "Prefer 32-bit" checkbox matters. This setting forces your program to run in 32-bit mode on a 64-bit version of Windows. Which has a number of side effects, the one that matters here is that access to registry keys are redirected. Your program is actually reading the value of HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Cryptography\MachineGuid. Which doesn't exist.
The x86 selection is the default for VS2010 and up, previously AnyCPU was the default. Microsoft prefers x86, Visual Studio works better with 32-bit mode processes. Particularly when debugging, VS is a 32-bit process itself so requires the remote debugger if your program executes in 64-bit mode. Which has a few limitations like not supported mixed-mode debugging. And the Edit + Continue feature only works for 32-bit code. Your program itself however works "better" if you have the setting at AnyCPU, including not getting bitten by the file system and registry redirection appcompat features built into Windows.
If you are really stuck with x86 mode, typically because you have a dependency on 32-bit native code that you can't update then the next workaround is to use the .NET 4+ RegistryKey.OpenBaseKey() method. Which allows you to pass RegistryView.Registry64, ensuring that you'll read the non-redirected keys.
Sure, using WMI is a workaround. Just keep in mind that you are not reading the same information when you use Win32_OperatingSystem.SerialNumber. To what degree that key is reliably random on different machines isn't that clear to me, let's just say that this value is a pretty attractive target for the kind of users that are not very interested in paying the license fee for your product either.
Last but not least, do consider that it is pretty easy to generate your own unique id that doesn't depend at all on Windows. With the considerable advantage that you won't piss off your customer when he updates Windows on his machine. Just use Guid.NewGuid() once and store the value in a file. That will be lost when the drive goes bad, but that usually takes out your product as well.