Delete key from registry HKEY_LOCAL_MACHINE - c++

I want to make uninstaller which should delete registry key from HKEY_LOCAL_MACHINE. Problem is that every time when i try delete location get LASTERROR 2, which is usually wrong name.
HKEY hKey = HKEY_LOCAL_MACHINE;
LSTATUS deletes = SHDeleteKey(hKey, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\NameOfApp\\");
if (deletes == ERROR_SUCCESS)
{
return true;
}
I have same code in C# which work, but C++ not. Also try as administrator, still nothing (with C# didn't put any special privileges and work).
OS: Windows 7, 64 bit.
Do you have any idea, what is happening?

On 64-bit Windows there are two separated registry trees. One for 32-bit applications and the other for 64-bit ones. It depends on your application (32-bit vs 64-bit) which tree is used when calling SHDeleteKey and that could be why it is working with c# but not with c++.
You can use RegDeleteKeyEx to explicitly define the tree you want to access.

Related

Cannot read Registry entry in C++

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.

Accessing 64 bit registry from 32 bit application

I need to open a registry entry "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{26A24AE4-039D-4CA4-87B4-2F86416024FF}" in c++. It contains the java 64 bit application. The full path of that registry entry is "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{26A24AE4-039D-4CA4-87B4-2F86416024FF}".
We can view this path through regedit. I use
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{26A24AE4-039D-4CA4-87B4-2F86416024FF}"),
0, KEY_ALL_ACCESS, &hKey)
for open the registry; But it returns error value (2).
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall")...
returns a success result. What can i do?
The registry keys for 32 bit and 64 applications are separated, you can't access (directly) the 64 bit registry from your 32 bit application. In your case the required hive doesn't exist in the 32 bit part of the registry then you can access the parent folder only.
From MSDN:
On 64-bit Windows, portions of the registry entries are stored separately for 32-bit application and 64-bit applications and mapped into separate logical registry views using the registry redirector and registry reflection, because the 64-bit version of an application may use different registry keys and values than the 32-bit version. There are also shared registry keys that are not redirected or reflected.
You can read the list on MSDN: Registry Keys Affected by WOW64. Unfortunately the SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall is not mentioned but it's affected too.
Solution
What you have to do is to explicitly ask RegOpenKeyEx to access the 64 bit part of the registry. This can be done adding the KEY_WOW64_64KEY flag to your call (you can access the 32 bit registry from a 64 bit application using KEY_WOW64_32KEY). Please note that this flag is not supported on Windows 2000 then if your application must be compatible with that (old) version you have to manage the case.
See this link on MSDN for further details: Accessing an Alternate Registry View.
To make it easy, simply change your call from:
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{26A24AE4-039D-4CA4-87B4-2F86416024FF}"),
0, KEY_ALL_ACCESS, &hKey);
to:
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{26A24AE4-039D-4CA4-87B4-2F86416024FF}"),
0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKey);
Note
Note that you may access the key only via its path without any flags using this HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall.
Because the Wow6432 node is the virtualized node used by WOW64 but you shouldn't rely on this, it's stable but it should be considered an implementation detail subject to change.
References
- Registry Virtualization on MSDN.
- Readers my find interesting tips on this post: http://poshcode.org/2470, it's for the PowerShell but it explains how to access WMI data (relative to the 64 bit registry part) from a 32 bit application.
Error 2 means the registry path does not exist.
Make sure that the key {26A24AE4-039D-4CA4-87B4-2F86416024FF} actually exists under SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

RegOpenKey / RegOpenKeyEx returns 2 (file not found) on Windows 7, while key exists

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.

Is a Program Running in Compatibility Mode

Is there a C++ .NET function that I can call that will detect if my program is running in compatibility mode? If there is not one, could someone show me the code for one? Thanks.
For example:
Program loads up
Compatibility Mode check
if true then exit
else run
From another forum
After a few google searches went in
vain, I decided to experiment myself.
I found that the compatibility
settings for each executable are
stored - as I thought it would be - in
the windows registry.
The key where the settings are stored
is
HKEY_CURRENT_USER\Software\Microsoft\Windows
NT\CurrentVersion\AppCompatFlags\Layers
For each application that has its
compatibility settings specified,
there exists a value under that key
whose name is the path to the
executable and the data is a string
consisting of the compatibility
settings.
The keywords in the string that
specify the compatibility settings
are: WIN95 WIN98 NT4SP5
WIN2000 256COLOR 640X480
DISABLETHEMES DISABLECICERO
If multiple settings are specified (or
are to be specified), the data
consists of the settings above
separated by a space each. The first
four settings are mutually exclusive,
i.e. only one of them is to be
specified (if at all). I haven't
tested the consequences of specifying
multiple operating systems.
So, back to addressing your problem.
To check if an executable (let's say,
"C:\path\executable.exe") is set to
run in 256 color mode, there would be
a value named "C:\path\executable.exe"
(without the quotes, even if the path
contains spaces) under the key
[HKEY_CURRENT_USER\Software\Microsoft\Windows
NT\CurrentVersion\AppCompatFlags\Layers],
and the data associated with the value
would contain the string "256COLOR".
If it is also set to run in
compatibility mode under Windows
98/ME, the data would be "WIN98
256COLOR".
So, the approach is simple. Test if
there is a value with the full path of
the executable under the key I
mentioned above. If there isn't, the
executable has not been specified any
compatibility settings. If the value
exists, retrieve its data and check
for the presence of "256COLOR" in the
data. Accordingly, the presence of
"WIN95" or "WIN98" or "NT4SP5" or
"WIN2000" would mean that the
executable is set to run in
compatibility mode for that particular
operating system.
Get the version of the operation system that is returned from GetVersionEx and compare it to the file version on kernel32.dll. When in application compatibility mode GetVersionEx will always return the version of the operating system that is being 'emulated'. If both versions are different then you are in application compatibility mode.
The answer above helped me to get a "solution" for the question at hand. It is probably not the most elegant, but seems to work. Obviously you can get a bit more creative on the return type. Booleon does not suffice here. I think a native API would be good.
typedef VOID (NTAPI* TRtlGetNtVersionNumbers)(LPDWORD pdwMajorVersion, LPDWORD pdwMinorVersion, LPDWORD pdwBuildNumber);
bool IsRunningCompatMode()
{
TRtlGetNtVersionNumbers RtlGetNtVersionNumbers = (TRtlGetNtVersionNumbers)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetNtVersionNumbers");
assert(RtlGetNtVersionNumbers);
if(RtlGetNtVersionNumbers)
{
OSVERSIONINFO osInfo = {0};
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osInfo);
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
RtlGetNtVersionNumbers(&dwMajorVersion, &dwMinorVersion, &dwBuildNumber);
dwBuildNumber &= 0x0000FFFF;
if(osInfo.dwBuildNumber != dwBuildNumber)
{
return true;
}
}
return false;
};

How to allow 32 bit apps on 64 bit windows to execute 64 bit apps provided in Windows\System32

Say you have an app, that you want to provide users ability to browse the system32 directory and execute programs in (like telnet).
What is the best method for supporting this when you need to support XP onwards as a client and 2k onwards for server?
Having written all this up I wonder if it's just too much time/effort in providing a browse to do this, where they could just copy it from explorer. Still requires ability to launch.
I have found some discussion on Nynaeve.
So far it seems there are the following options
Create a sysnative folder in windows which will allow you to browse/execute 64 bit. Issues are:
only available in Vista/Longhorn, so no support for XP 64
leads to different path naming, can't use same path on multiple versions.
will be active for whole of windows, not just our app
may not (probably is not) appropriate to do when installing the app
allows to specify explicitly through path only which version of the app to launch if there is a 32 bit and 64 bit version
Use the windows API to temporarily disable the redirection when showing file lists or executing users run commands. Issues are:
Only available on 64 bit - have to mess with GetProcAddress
available only under certain service packs
must individually identify all locations that this should be implemented
user will need to provide seperate information about whether this is a 64 bit app or 32 bit.
If anybody had some example code which displayed a Windows OpenFile dialog (say using MFC CFileDialog) showing nativly for XP/Vista and allowing the viewing of 64 bit system32 directory, that would be awesome.
If anybody had an example of launching the named app, that would also be great!
Edit:
Currently we use CreateProcess for launching the app (which is failing).
err = CreateProcess((wchar_t*)exeName.c_str(), (wchar_t*)cmdLine.c_str(), NULL, NULL, FALSE, CREATE_SEPARATE_WOW_VDM, NULL, workingDir.c_str(), &startupInfo, &processInfo);
I've gone with option 2,
For those who might be interested; here is my quick hack at a scoped version of managing the disabling of Wow64 redirection based on notes from MS. Will redirect if the API is available, expects that kernel32.dll is already available.
class Wow64RedirectOff {
typedef BOOL (WINAPI *FN_Wow64DisableWow64FsRedirection) ( __out PVOID *OldValue );
typedef BOOL (WINAPI *FN_Wow64RevertWow64FsRedirection) ( __in PVOID OldValue );
public:
Wow64RedirectOff() {
LPFN_Disable = (FN_Wow64DisableWow64FsRedirection)GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"Wow64DisableWow64FsRedirection");
if( LPFN_Disable ) {
LPFN_Disable(&OldValue);
}
}
~Wow64RedirectOff() {
if( LPFN_Disable ) {
FN_Wow64RevertWow64FsRedirection LPFN_Revert = (FN_Wow64RevertWow64FsRedirection)GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"Wow64RevertWow64FsRedirection");
if( LPFN_Revert ) {
LPFN_Revert(OldValue);
}
}
}
private:
FN_Wow64DisableWow64FsRedirection LPFN_Disable;
PVOID OldValue;
};
And thus usage would be
Wow64RedirectOff scopedRedirect;
//CFileOpen
//CreateProcess
Are you getting redirected to Windows/SysWoW64? I can launch 64-bit apps from Windows/System32 from an OpenFile in a 32-bit managed executable.