I have a little app which reads registry key string values. It works well but for some reason it fails on this key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId
Despite working on other values of HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\
It also fails on `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid'
I am running as an admin, is this a factor? I'm running W7 64bit, another W7 machine and Vista machine both work fine. My only guesses are some permissioning issue, or related to me running 64-bit.
update:
It appears to be something to do with my system running Windows 64bit, and \Software\Wow6432Node\. I don't know what that is though. I have both \Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\ and \Software\Microsoft\Windows NT\CurrentVersion\ but only the latter contains ProductId value... for some reason when I ask for the key Windows is apparently looking in the Wow6432Node
We're using wxWidgets but could probably use some win32 code directly if needed... our app is a 32bit application but target PCs could be running 32 or 64 bit versions of Windows
It's due to WOW64. This other question focuses on the details.
I got the following code to work on a 32 bit XP box and a 64 bit Win 7 box. I think that should cover most bases.
// start out trying to read machine guid on 32 bit machine
object value = Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography", #"MachineGuid", (object) "defaultValue");
if (value != null && value.ToString() != "defaultValue")
{
return value.ToString();
}
// read machine guid on 64 bit machine
RegistryKey regKeyBase = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey regKey = regKeyBase.OpenSubKey(#"SOFTWARE\Microsoft\Cryptography", RegistryKeyPermissionCheck.ReadSubTree);
value = regKey.GetValue("MachineGuid", (object) "defaultValue");
regKeyBase.Close();
regKey.Close();
if (value != null && value.ToString() != "defaultValue")
{
return value.ToString();
}
return string.Empty;
I just looked at my registry and there's no key at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductId or MachineGuid, this is on Win7 64-bit
Related
I have a problem with this operation only in windows 8.
here is the code which work in other Windwos OS (Win7/Vista/XP)
#ifdef Q_WS_WIN
QSettings bootUpSettings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
if (runOnbootCheckBox->isChecked())
{
bootUpSettings.setValue("AppName","\""+base_dir+"\""+ (startMinimizedCheckBox->isChecked() ? " -m" : ""));
}
else
bootUpSettings.remove("AppName");
#endif
Value from regesty: "C:\Program Files (x86)\Appname\Appname.exe" -m
can any one explain why this code dont work ?
Wow6432 node will be found on a 64 bit windows. This is used to provide a 32 bit environment for your application in 64 bit system. I assume your application is 32 bit. Hence, when it tries to read the Registry values, it will be redirected to the Wow6432 node.
May be, you can add a custom registry key under HKCU to decide whether to run the app or not after starting up from Wow6432 node as mentioned above.
That is add your startup entry here:
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
An then, add a custom entry in HKCU for deciding whether to continue running the app or to close it.
I mean, you can add a separate logic in your application for that.
Include this header QSettings
#include <QSettings>
And add this in your code.
QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
QSettings::NativeFormat);
settings.setValue("YourApplicationName",
QCoreApplication::applicationFilePath().replace('/', '\\'));
I'm running a C++ program (which works great on 32 bit Win XP) on Windows 7 64 bit in debugger under Visual Studio 2010 and I am unable to open an existing registry key with the following code:
#define ACCESS (KEY_WRITE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS)
HKEY hKey;
long dwErrorCode = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\MYTHING", 0, ACCESS|KEY_WOW64_64KEY, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
{
// display error message
}
The error code returned is: 5 with the system message being "Access is Denied".
This does work if I run the Visual Studio 2010 as Admin, however I'd rather not have to do that. Can anybody offer a suggestion?
Update: I forgot to mention, what I am doing here is porting legacy code from Windows XP. As such, I don't have the option of changing the fundamental structure of how this software was written. Since the legacy code uses the registry, that is what the ported code must do also.
Also, I would rather not make changes to my specific computer -- since that means I would have to change every computer that I want to run this on. This could get messy as there are a lot of machines affected. For example, I don't want to turn off UAC for the entire machine.
Further update: I haven't found a solution that I'm happy with. Have decided to ignore error code 5 for purposes of debugging and that seems to be working well enough for now. I'm trying to understand how standard apps like Word, Firefox, etc appear to be using the registry for all kinds of settings and yet are not elevated nor do I have to give them special permissions to make changes to the registry?
Ok, I found the answer to my question so I'll post it here in case anybody else needs it for future reference. This thread turned out to be helpful even though it is actually on the topic of C#:
http://social.msdn.microsoft.com/Forums/da-DK/netfx64bit/thread/92f962d6-7f5e-4e62-ac0a-b8b0c9f552a3
Basically, I needed to change my permission to read the 32 bit registry instead of the 64 bit one like so:
HKEY hKey;
long dwErrorCode = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\MYTHING", 0, ACCESS|KEY_WOW64_32KEY, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
{
// display error message
}
Voila, everything works now! Thanks for your efforts everyone.
Update: it turns out this didn't work as well on my other machine, which led me to discover that someone must have changed access rights to the 32 bit registry on one of my machines. So it is still necessary to give the User access rights to the registry key you want to work with.
You need to run the process in elevated mode, or turn off UAC. You can of course assign access rights to your specific registry key that allows you access.
I have faced same issue. I have solved using following:
LPCTSTR subKey = TEXT("Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\App Paths");
LONG openRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_WOW64_32KEY && KEY_ALL_ACCESS, &hKey);
I have one program that uses API RegCreateKeyEx and that works perfectly fine on WinXP and Vista.
Program is generally launched in elevated privileges .
When I try to use same program in Windows 7 , RegCreateKeyEx API is returning 5 (access denied).
Any idea how to resolve this?
This error occurs when you're trying to create a key in a portion of the registry where you don't have write access. On Windows 7, this is basically everywhere.
To increase compatibility of 32 bit applications between XP/7 it's suggested you create the key in the 32 bit view of the registry. Modify your call to include the mask KEY_WOW64_32KEY so it uses the 32 bit view:
result = RegCreateKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Foo"),
NULL, NULL, NULL, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &hkey, &disposition);
Then create the key first in the registry manually under HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Foo. Edit the permissions and give yourself (or everyone) Full Control.
You should now be able to access the key from a 32 bit application.
My boss just got Windows 7 and he tried running one of our installers which runs perfectly fine under XP. On Windows 7, the installer runs without giving any errors. However, it does not create registry keys under HKEY_LOCAL_MACHINE\SOFTWARE{Company}{product}. These keys get created correctly under XP.
Has anyone encountered this issue? I suspect it is a rights/security issue but I'm not sure and I don't have Windows 7 to experiment with.
EDIT
The computer in question is a 64-bit machine running 64-bit Windows. It turns out Windows 7 redirects 32-bit applications to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node{Company}{product}. The problem is my application code tries to access the registry using a hardcoded value like this:
var t = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\..., "ValueName", DefaultValue);
So, my new question is how do I access the registry such that the Windows 9 registry redirection will just work?
If you're using .NET 4, you can specifically request that your 32-bit (or 64-bit) process access the 64-bit view of the registry using the RegistryKey.OpenBaseKey method.
Cf. http://msdn.microsoft.com/en-us/library/microsoft.win32.registrykey.openbasekey.aspx
Here's an example that reads a value from the 64-bit view of the registry, even if it runs as part of a 32-bit process:
var hklm64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var key = hklm.OpenSubKey(#"SOFTWARE\AcmeSoft\AnvilMaker 1.0");
var value = (string) key.GetValue("Blacksmith Name");
The RegistryKey.OpenBaseKey method also allows you to explicitly open a 32-bit view of the registry. This is useful if you're trying to go the other way around and access the 32-bit view of the registry from a 64-bit process and you don't want to explicitly add "Wow6432Node" to the registry path.
For example, today I needed to delete a sub-key tree in both the 32-bit and 64-bit views of the registry. Doing this in .NET 4 with a single registry path was easy:
foreach(var view in new[] {RegistryView.Registry32, RegistryView.Registry64})
{
var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
hklm.DeleteSubKeyTree(#"SOFTWARE\AcmeSoft\SomeKeyWeNoLongerWant", throwOnMissingSubKey: false);
}
On a 64-bit version of windows, the above code will remove the following sub-key trees from the registry:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\AcmeSoft\SomeKeyWeNoLongerWant
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\AcmeSoft\SomeKeyWeNoLongerWant
-Adam
After more digging I came across this link which describes the registry access rules for .NET applications. My program had initially been targeted for "AnyCpu" which causes the app to target the 64-bit registry even though Windows installed it under the Wow6432Node. By setting the target to "x86" my program "magically" started accessing the registry under the Wow6432Node. Go figure!
In the C Windows API this is done by setting the samDesired parameter in the RegOpenKeyEx call to KEY_WOW64_64KEY. This means that the lookup of the registry value will map onto the regular 64-bit entry, rather than the WOW32Node one. I can't see how you would achieve this in .Net though as the Registry class doesn't appear to support these operations, but maybe it's provided through a newer class?
Registry Reflection
Code Sample
I need to open a html help file from within a legacy windows application written in old version of C++ Builder. HtmlHelp is loaded via HtmlHelp.ocx, which I am loading via LoadLibrary.
This has worked fine for years, but it does not work anymore in Windows 7 x64. It might also fail under Windows7 x86, but I don't have any computer with this OS, so I can't try it out at the moment.
I am loading hhctrl.ocx dynamically as follows:
#define HHPathRegKey "CLSID\\{adb880a6-d8ff-11cf-9377-00aa003b7a11}\\InprocServer32"
bool THTMLHelper::LoadHtmlHelp()
{
HKEY HHKey;
DWORD PathSize = 255;
char Path[255];
bool R = false;
if (::RegOpenKeyExA(HKEY_CLASSES_ROOT, HHPathRegKey, 0, KEY_QUERY_VALUE, (void **)&HHKey) == ERROR_SUCCESS)
{
if (::RegQueryValueExA(HHKey, "", NULL, NULL, (LPBYTE)Path, &PathSize) == ERROR_SUCCESS)
{
//*****************************************
//LOADING FAILS HERE
//PATH IS %SystemRoot%\System32\hhctrl.ocx
//*****************************************
HHLibrary = ::LoadLibrary(Path);
if (HHLibrary != 0)
{
__HtmlHelp = (HTML_HELP_PROC) ::GetProcAddress(HHLibrary, "HtmlHelpA");
R = (__HtmlHelp != NULL);
if (!R)
{
::FreeLibrary(HHLibrary);
HHLibrary = 0;
}
}
}
::RegCloseKey(HHKey);
}
return R;
}
I checked if %SystemRoot%\System32\hhctrl.ocx exists on the Windows 7 system and it does.
Why does loading it via LoadLibrary fail? How can I work around this problem?
EDIT: GetLastError says (in German, so I am just translating): "Could not find file." But I debugged the function and the path is "%SystemRoot%\System32\hhctrl.ocx" and the file does exist.
Also, since two answers point in the direction of 64-bit vs 32-bit problems: My application is a 32 bit executable compiled in C++ Builder 5, so it should be a 32 bit process if I'm not mistaken. Or am I wrong to assume that?
Use ExpandEnvironmentStrings function to expand %SystemRoot%\System32\hhctrl.ocx to real path on user's intallation. 64bit OS will redirect expanded path to 32bit dll correctly.
You can't load 32bit dlls in a 64bit process, and visa versa. ActiveX controls are, of course, Dlls.
You can sometimes work around this by getting the 32bit ActiveX to load as an out-of-process server - its then hosted in a seperate 32bit (or 64bit) process as appropriate. This requires that the ActiveX onlyuses interfaces the system already knows how to marshal, and/or the project built 64bit AND 32bit versions of the proxy stub dll.
Depends is a tool that is very useful when you need to figure out why Dlls wont load. Of course, as a 32 bit application on a 64bit OS you need to know that 32 bit applications do NOT get access to %SYSTEMROOT%\System32 and, also do NOT read and write from HKCR directly. System32 actually contains the 64bit OS binaries, and HKCR contains the registry entries for 64bit apps.
A kernel process called 'reflection' redirects 32bit apps completely transparently to from System32 to %SYSTEMROOT%\SysWow64.
Likewise, registry access to HKEY_CLASSES_ROOT is redirected to `HKEY_CLASSES_ROOT\Wow6432Node'.
You need to know this of course, because explorer and regedit are 64bit processes and will happily show you the 64bit contents of System32 and HKCR. You need to explicitly navigate to the 32bit nodes to double check the view your 32bit process is going to get.
I have the exact same problem right now running W7 (x64).
I got it to work when I changed the "%SystemRoot%\System32\hhctrl.ocx" to "c:\windows\System32\hhctrl.ocx", but I guess I need to figure out why %SystemRoot% resolves wrong.
btw: I'm building a 32bit app on BCB2007.