I need to open up and modify a user's registry key from a 32-bit service (note that the user is not logged in at the time.) I do the following:
//For simplicity error checks are not shown
//I also made sure to enable the following privileges:
// SE_RESTORE_NAME, SE_BACKUP_NAME
//"ntuser.dat" = is the file OS uses to load user's profile
if(RegLoadKey(HKEY_LOCAL_MACHINE, L"Test123", L"C:\\Users\\UserA\\ntuser.dat") == ERROR_SUCCESS)
{
HKEY hKey;
DWORD dwRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"Test123\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\TrayNotify"),
NULL, KEY_READ | KEY_WOW64_64KEY, &hKey);
//'dwRes' = is returned as 2, or ERROR_FILE_NOT_FOUND
RegUnLoadKey(HKEY_LOCAL_MACHINE, L"Test123");
}
The problem is that the Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify key isn't loaded, even though I know that it exists in the actual user profile. I can verify that by loading the user account and by using 64-bit regedit.
I suspect that this has something to do with the Wow64 redirection but I can't seem to understand what am I doing wrong?
EDIT: Added error check for the first API.
I think I got it. Two corrections to my original code:
First off, since Vista I need to load Usrclass.dat file for the classes hive and not ntuser.dat. It kinda makes sense because ntuser.dat is a part of a user's roaming profile and Classes\Local Settings does not fit into the picture well. So here's the location of the Usrclass.dat file, which contains non-roaming user data (mostly COM stuff, but some other settings as well):
%LocalAppData%\Microsoft\Windows\Usrclass.dat
The key to open after the user hive loads is:
Test123\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify
that is because the original HKCU\Software\Classes is redirected to HKU\<UserSID>_Classes that is stored in the Usrclass.dat file.
Related
In Windows 7 (32 bit), I consistently get error 5 (access denied) when I call ::RegOpenKeyEx on HKEY_LOCAL_MACHINE if I am not running in Administrator mode.
This is my code:
result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\MyCompany\\MyApp"), 0, KEY_QUERY_VALUE, &keySoftware)
I am trying to build an app that can be installed for an entire machine as opposed to a specific user. Therefore my installer (which does run in Administrator mode) writes to HKEY_LOCAL_MACHINE, and the installer works fine.
I'd like my app to be able to read the data that my installer has put into the registry. I don't want to change any of the registry data. I have also tried using KEY_READ and KEY_EXECUTE instead of KEY_QUERY_VALUE. But it seems that no matter what I do, I cannot read from HKEY_LOCAL_MACHINE without using an elevated status. What am I missing here?
Your installer needs to adjust the security permissions on your Registry key so that non-admin users are allowed to access it. Have a look at RegSetKeySecurity(), or your installer's equivalent, or any number of command-line tools that are available. You can create a DACL that enables read-only access for the Everyone user group, or for specific user accounts.
Update: since you are using Inno Setup, try this in your Registry setup:
[Registry]
Root: HKLM; Subkey: "Software\MyCompany\MyApp"; Permissions: everyone-read
Or:
[Registry]
Root: HKLM; Subkey: "Software\MyCompany\MyApp"; Permissions: users-read
Your code as I was writing this answer:
result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\MyCompany\\MyApp"), 0, KEY_QUERY_VALUE, &keySoftware)
RegOpenKeyEx doesn't support general paths, just direct key names.
To use it you would have to iterate your way down the hierarchy.
SHRegOpenUSKey is one alternative that does support general paths:
HUSKEY keySoftware;
LSTATUS const result = ::SHRegOpenUSKey(
L"Software\\Microsoft\\MediaPlayer", KEY_QUERY_VALUE, 0, &keySoftware, TRUE
);
I want to get all the CLSIDs keys that are under the HKEY_CLASSES_ROOT\\SOFTWARE\\Classes\\CLSID key.
I know that that key is mirror for merged HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID and HKEY_CURRENT_USER\\SOFTWARE\\Classes\\CLSID keys.
So far I can enumerate all HKEY_CLASSES_ROOT\\SOFTWARE\\Classes\\CLSID (HKEY_LOCAL_MACHINE\\... and HKEY_CURRENT_USER\\... as well) and get that key's names into std::wstring[]. But when I try to open that keys:
//CLSID = e.g. L"{CAFEEFAC-0013-0001-0001-ABCDEFFEDCBB}"
firstKey = HKEY_LOCAL_MACHINE;
keysPath = L"\\SOFTWARE\\Classes\\CLSID\\"+CLSID;
if(x64System)
regsam = KEY_ALL_ACCESS|KEY_WOW64_64KEY; //on my system
else
regsam = KEY_ALL_ACCESS;
result = RegOpenKeyEx(firstKey, keysPath.c_str(), 0, regsam, &outputKey);
It works only for HKEY_CURRENT_USER, for HKEY_LOCAL_MACHINE it returns ERROR_ACCESS_DENIED. Even when I run my program as administrator (in regedit.exe I can see that key's name is good, if it wouldn't error message would be not found, not ERROR_ACCESS_DENIED anyway).
So what should I do to access that keys? I'm sure that some programs can access that keys. Or at least how to get their default value (it is all I want from them)?
In my program I can only list their names with RegQueryInfoKey but cannot access them with RegOpenKeyEx.
Even as an admin you don't have KEY_ALL_ACCESS on HKLM when UAC is enabled. If you want or need KEY_ALL_ACCESS you Need to run your program elevated.
Reduce your rights to the needed Level. If you only want to read just use KEY_READ!
And take care that you have an embedded manifest, without a manifest you might get access, but tis access is virtualized and you don't get access to the real key.
I have a registry entry I can't seem to read in C++, but it shows up in Regedit.
Using the following C++ snippet:
openResult=RegOpenKeyEx( HKEY_LOCAL_MACHINE, _TEXT("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full"), 0, KEY_READ, &root);
readResult1=RegQueryValueEx(root, _TEXT("InstallPath"), NULL, NULL, data1, &size);
readResult2=RegQueryValueEx(root, _TEXT("fake_entry"), NULL, NULL, data2, &size);
I get Error 2, ERROR_FILE_NOT_FOUND for my second RegQueryValueEx() call.
As you can see in the image below, my fake_entry exists.
I created this entry via Regedit.
Microsoft's Registry Keys Affected by WOW64 does not include the location I'm trying to read, and as you can see in the picture below, my fake_entry is not in the Wow6432Node location.
Yes, I understand this isn't a registry location I should be changing. I stumbled upon this as I was debugging my code and am curious why my added fake_entry doesn't work.
Yes, I've read about Registry Redirector.
Yes, I've read this question.
Yes, I tried reading fake_entry at SOFTWARE\\Wow6432Node\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full with the same error.
Running Windows 7, 64 bit, C++ in Visual Studio 2010, using ASCII character encoding.
Am I misunderstanding the Registry Redirector?
Is there a problem with my code?
Are there some sort of permission settings on certain portions of the Registry? I'm obviously missing something. Please point me in the right direction.
Try
openResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _TEXT("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full"), 0, KEY_READ|KEY_WOW64_64KEY, &root);
according to MSDN you should use either KEY_WOW64_64KEY or KEY_WOW64_32KEY for WOW64 access
You are misreading the table of keys affected by WOW64. From the very top of that page:
The following table lists registry keys that are redirected, shared by both 32-bit and 64-bit applications, or redirected and reflected on 64-bit Windows. Subkeys of the keys in this table inherit the parent key's behavior unless otherwise specified. If a key has no parent listed in this table, the key is shared.
The parent of your key is HKLM\Software which is redirected. So your key is also redirected. It inherits that from its parent, as the documentation that I quoted explains.
You'll need to read the 64 bit view using KEY_WOW64_64KEY.
I am trying to read a value from HKEY_CURRENT_USER\Software\Classes on Windows 7 as a standard user, and although the key exists, I get an error. Both codes below don't success:
l = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Classes", 0, KEY_READ, &hKey);
// RegOpenKeyEx doesn't success either
l = RegOpenKey(HKEY_CURRENT_USER, L"Software\\Classes", &hKey);
This code is located in a dll called by an application doing many things (I don't know all that it does).
However, a simple app with just RegOpenKey on the same computer with the same account works perfectly...
Can anyone tell me what could cause the problem and the differences between the two?
The test app is written in c++, while the dll is written in c.
EDIT: Problem solved, by just removing the "L" before L"Software\Classes"...
Likely, the code is running as a different user or its current user isn't in synch with the cached registry key for the process. See RegOpenCurrentUser.
I solved the problem by passing "Software\Classes" instead of L"Software\Classes" to the function.
I want to change the registry values on the pocketPC. I ran the following code:
if(enabled)
{
dwData = 120;
}
if(RegSetValueEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\Power\\Timeouts\\BattSuspendTimeout"), 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD)))
{
return FALSE;
}
but it doesn't shange the registry entry. Does anyone know how to set registry key values with c++?
Thanks!
There are a two problems with what you are doing:
1: RegSetValueEx does not take a path, only a valuename. So you need to open the key path first.
e.g.
HKEY key;
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\Power\\Timeouts", 0, 0, &key))
{
if(RegSetValueEx(key, _T("BattSuspendTimeout"), 0, REG_DWORD, (LPBYTE)&dwData, sizeof(DWORD)))
{
RegCloseKey(key);
return FALSE;
}
RegCloseKey(key);
}
2: That area of the registry requires Privileged code signing to work on all Windows Mobile devices. You can get away with it on most current touch-screen windows mobile devices if the user says "yes" to the unknown publisher question when the application is first run or installed. If you get a "Access Denied" error on the set, then you really need to be Privileged code signed for the set to work.
RegSetValueEx returns a descriptive error code. You can get a human-readable message out of this error code using FormatMessage and possibly via the Error Lookup tool, or the #ERR facility in VS. The code you have looks correct so see what the error message tells you.
How are you verifying the change? Keep in mind that making this change will not be reflected automatically in the device behavior and it probably won't show up in the Control Panel either (depends on if the CPL has already been loaded or not). The shell is unaware that you made the change and it doesn't poll the value - you have to tell it to go out and re-read. How to do it is documented in MSDN (basically you set a named system event).
Check out [VORegistry][1], it makes working with the registry so much easier.
[1]: http://www.voscorp.com/products/developer/winmobile/voregistry/index.htm VORegistry
Assuming that your looking with RegEdit, did you refresh (F5) the registry view?