Error writing to Windows 10 registry with WindowsAPI/C (strange situation) - c++

I am trying to write to my Windows 10 registry, to include a program in Startup.
At the moment I have written the following code, which is not wroking:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winnt.h>
#include <winreg.h>
int main()
{
const TCHAR* path = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
LPDWORD holdResult;
PHKEY hKey;
int lResult;
//lResult = RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_READ, &hKey);
lResult = RegCreateKeyExA(HKEY_CURRENT_USER, "myprogram", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &holdResult);
if (lResult != ERROR_SUCCESS)
{
if (lResult == ERROR_FILE_NOT_FOUND) {
printf("Key not found.\n");
return TRUE;
}
else {
printf("Error opening key.\n");
return FALSE;
}
}
printf("Key already existed or not: %p\n", holdResult);
char* szPath = "C:\\Users\\Myname\\Documents\\coolprogram.exe";
lResult = RegSetValueExA(hKey, "program", 0, REG_SZ,(LPBYTE)szPath, sizeof(wchar_t)*(wcslen(szPath)+1));
printf("Key successfully set or not: %d\n", lResult);
RegCloseKey(hKey);
return 0;
}
The strange thing is, although the code does not write anything to the registry, I get no error message, and the program executes as successful!
This is what gets printed to the terminal when I run the code:
Key already existed or not: 0000000000000002
Key successfully set or not: 0
So, the key had already been previously created, and was succesfully set, which did not happen, there is nothing in my registry.
I believe this is a permissions problem, because for some reason I cannot alter my registry permissions manually, even after setting myself as owner, it is impossible for me to allow "Full Control" to myself.
But I expected some sort of error, such as "ACCESS DENIED: INSUFFICIENT PERMISSIONS", but I am getting a success. Strange.

You are passing the wrong key path to RegCreateKeyEx(). You are trying to write your program value to HKCU\myprogram rather than to HKCU\SOFTWARE\Microsoft\...\Run.
You are also passing invalid pointers to RegCreateKeyEx(). Its last 2 parameters expect pointers to HKEY and DWORD variables, but you are passing in pointers to HKEY* and DWORD* variables instead.
You are also passing an incorrect parameter to RegSetValueExA(), too. You are giving it an ANSI string (OK, since it is an ANSI function), but are passing in a Unicode string length that is 2x the byte size of the actual ANSI string (bad).
In fact, your code shouldn't even compile as shown.
Try this instead:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winnt.h>
#include <winreg.h>
int main()
{
const char* szKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
const char* szPath = "C:\\Users\\Myname\\Documents\\coolprogram.exe";
DWORD dwDisposition;
HKEY hKey;
LSTATUS lResult;
//lResult = RegOpenKeyExA(HKEY_CURRENT_USER, szKey, 0, KEY_QUERY_VALUE, &hKey);
lResult = RegCreateKeyExA(HKEY_CURRENT_USER, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, &dwDisposition);
if (lResult != ERROR_SUCCESS)
{
printf("Error creating key: %ld\n", lResult);
return 0;
}
printf("Key already existed or not: %lu\n", dwDisposition);
lResult = RegSetValueExA(hKey, "program", 0, REG_SZ, (LPBYTE)szPath, sizeof(TCHAR)*(strlen(szPath)+1));
printf("Key successfully set or not: %ld\n", lResult);
RegCloseKey(hKey);
return 0;
}

Related

How to save a persistent value for application access across multiple runs?

As the title states, I would like to store a variable (which will always be an positive integer < 10,000) for my application to access and process as needed across multiple runs.
My current implementation simply saves the value to a file, in the current directory, and then reads it in when needed.
#include<fstream>
int x = 5;
std::ofstream write_file(file_handle);
write_file << value;
write_file.close();
However, I'm not too keen on the idea of having an orphaned text file if the user decides to place the .exe on their desktop.
So, what other options do I have to store the value?
I'm primarily concerned with Windows 8+.
There is nothing wrong with using a file, but you don't have to (and should not) store it in the same folder as the .exe file, as it may not work depending on where the .exe is located (for instance, non-admins can't write to Program Files).
Windows sets aside special folders in the user's profile just for application-generated data, so you should store the file in one of those folders instead. Use the Win32 SHGetFolderPath() or SHGetKnownFolderPath() function to discover where those special folders are located, and then you should create a sub-folder for your application's use (you can even use SHGetFolderPathAndSubDir() for that purpose).
For example:
#include <fstream>
#include <filesystem>
#include <windows.h>
#include <shlobj.h>
namespace fs = std::filesystem;
fs::path pathToMyValueFile()
{
WCHAR szPath[MAX_PATH];
if (SHGetFolderPathAndSubDirW(NULL, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, L"MyApp", szPath) != S_OK) {
throw ...;
}
return fs::path(szPath) / L"value.dat";
/* alternatively:
if (SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, szPath) != S_OK)
throw ...;
fs::path folder = fs::path(szPath) / L"MyApp";
fs::create_directory(folder);
return folder / L"value.dat";
*/
}
...
int value = 0;
std::ifstream read_file(pathToMyValueFile());
if (read_file.is_open()) {
read_file >> value;
read_file.close();
}
...
int value = 5;
std::ofstream write_file(pathToMyValueFile());
if (write_file.is_open()) {
write_file << value;
write_file.close();
}
In the future, if the user ever uninstalls your app, be sure to delete that subfolder.
Otherwise, you can store the value in the Windows Registry instead. Create a new key for your application under HKEY_CURRENT_USER\Software or HKEY_LOCAL_MACHINE\Software as needed, and then you can create values inside that key.
For example:
#include <fstream>
#include <windows.h>
int readMyValue()
{
int value;
HKEY hKey;
LSTATUS lRes = RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\MyApp", 0, KEY_QUERY_VALUE, &hKey);
if (lRes == ERROR_SUCCESS)
{
DWORD size = sizeof(value);
lRes = RegQueryValueExA(hKey, "Value", NULL, NULL, (LPBYTE)&value, size);
RegCloseKey(hKey);
}
if (lRes != ERROR_SUCCESS)
{
if (lRes != ERROR_FILE_NOT_FOUND)
throw ...;
value = 0;
}
return value;
}
void saveMyValue(int value)
{
HKEY hKey;
LSTATUS lRes = RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\MyApp", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL);
if (lRes == ERROR_SUCCESS)
{
DWORD size = sizeof(value);
lRes = RegSetValueExA(hKey, "Value", 0, REG_DWORD, (BYTE*)&value, sizeof(value));
RegCloseKey(hKey);
}
if (lRes != ERROR_SUCCESS)
throw ...;
/* alternatively:
if (RegSetKeyValueA(HKEY_CURRENT_USER, "Software\\MyApp", "Value", REG_DWORD, &value, sizeof(value)) != ERROR_SUCCESS)
throw ...;
*/
}
...
int value = readMyValue();
...
int value = 5;
saveMyValue(value);
If your app is uninstalled later, be sure to delete the Registry key.

How to add a String Value/ Name Data pair in Windows Registry Editor key using C++ and Windows Registry API's

I want to add a string name and its value to the Windows Registry using C++ code, to stop browsers other than Firefox stop running. I plan to do the Windows Registry editing in a loop for all browsers, but for now I am implementing it for Chrome only.
My current code below is adding a value to the Default string, and it is not working, but I want to create a Debugger string and set it to "ntsd -c q" in the chrome.exe subkey, as shown in the picture below.
Here is my code, which is adding "ntsd -c q" for the Default string and not creating a new Debugger string. I am not able to clearly understand from Microsoft's documentation about how to achieve this using C/C++. I have seen some solutions that do it via the command line, but co-workers are very ethical and they don't prefer that way.
#include <Windows.h>
#include <iostream>
int main()
{
HKEY hkey;
LSTATUS ReturnValue = 0;
LPCTSTR Directory = TEXT("SOFTWARE\\Microsoft\\Windows\ NT\\CurrentVersion\\Image\ File\ Execution\ Options\\chrome.exe");
ReturnValue = RegOpenKeyEx(HKEY_LOCAL_MACHINE, Directory, 0, KEY_ALL_ACCESS, &hkey);
if (ERROR_SUCCESS != ReturnValue)
{
printf("RegOpenKeyEx failed\n");
printf("%d\n", GetLastError());
return -1;
}
//LPCSTR value = "Debugger";
//ReturnValue = RegQueryValueEx(HKEY_LOCAL_MACHINE, Directory, NULL, NULL, value, sizeof(value));
LPCSTR Value = "ntsd\ -c\ q\0";
ReturnValue = RegSetValueA(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows\ NT\\CurrentVersion\\Image\ File\ Execution\ Options\\chrome.exe",REG_SZ, Value, sizeof(Value));
if (ERROR_SUCCESS != ReturnValue)
{
printf("RegStatusValueA failed\n");
printf("%d\n", GetLastError());
return -1;
}
ReturnValue = RegCloseKey(hkey);
if (ERROR_SUCCESS != ReturnValue)
{
printf("RegCloseKey failed\n");
printf("%d\n", GetLastError());
return -1;
}
return 0;
}
KEY_ALL_ACCESS requires admin rights. All you really need in this situation is KEY_SET_VALUE instead. Don't ask for more permissions than you actually need. But, you do still need admin rights to write to HKEY_LOCAL_MACHINE to begin with. So make sure you are running your code as an elevated user.
In any case, your string literals have a few \ that don't belong. But more importantly, your use of RegSetValueA() is completely wrong for this task. It is a deprecated API that can only write to the (Default) string and nothing else (and, you are not even calling it correctly anyway, you would need strlen(Value)+1 instead of sizeof(Value) - not that it matters because that parameter is ignored anyway).
In order to create your Debugger string value, you need to use RegSetValueEx() instead, eg:
#include <Windows.h>
#include <iostream>
int main()
{
HKEY hkey;
LPCTSTR Directory = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\chrome.exe");
LSTATUS ReturnValue = RegOpenKeyEx(HKEY_LOCAL_MACHINE, Directory, 0, KEY_SET_VALUE, &hkey);
if (ERROR_SUCCESS != ReturnValue)
{
printf("RegOpenKeyEx failed: %u\n", GetLastError());
return -1;
}
LPCTSTR Value = TEXT("ntsd -c q");
ReturnValue = RegSetValueEx(hkey, TEXT("Debugger"), 0, REG_SZ, (const BYTE*)Value, (lstrlen(Value)+1) * sizeof(TCHAR));
if (ERROR_SUCCESS != ReturnValue)
{
printf("RegSetValueExA failed: %u\n", GetLastError());
RegCloseKey(hkey);
return -1;
}
ReturnValue = RegCloseKey(hkey);
if (ERROR_SUCCESS != ReturnValue)
{
printf("RegCloseKey failed: %u\n", GetLastError());
return -1;
}
return 0;
}

How to write a 32 Bit D-Word to Windows registry in C++

I am trying to disable the Windows Defender using a C++ Win32API application.
To do that I need to write a D Word into the registry (DisableAntiSpyware = 1).
I always do that manually after installing a new Windows.
So here is my code, but its not working.
Maybe someone could tell me why or what is wrong with it. Thank you!
OK I've changed the code a bit, still not working...
case 1:
//::MessageBeep(MB_ICONERROR);
::MessageBox(hWnd, L"Button was Pressed",L"Button was clicked?",MB_OK);
LONG
SetRegValue
(
const wchar_t* path
, const wchar_t *name
, const BYTE *value
);
{
LONG status;
HKEY hKey;
DWORD value = 0x00000001;
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"\\SOFTWARE\\Policies\\Microsoft\\Windows Defender", 0, KEY_ALL_ACCESS, &hKey);
if ((status == ERROR_SUCCESS) && (hKey != NULL))
{
status = RegSetValueEx(hKey, L"test", 0, REG_DWORD, (const BYTE*)&value,sizeof(value));
RegCloseKey(hKey);
}
return status;
::MessageBeep(MB_ICONERROR);
}
}
}
break;
When opening a Registry key, you should request only the rights you actually need. So replace KEY_ALL_ACCESS with KEY_SET_VALUE instead, since all you are doing is writing a value. But even then, you might still need to run your app with elevated permissions in order to write to HKEY_LOCAL_MAHCINE, unless you give your user account write access to the Windows Defender key beforehand.
Also, if your code is compiled as 32bit and runs on a 64bit system, and it needs to write to the 64bit Registry, then you have to include the KEY_WOW64_64KEY flag otherwise you may be subject to Registry Reflection/Registry Redirection.
Try something more like this instead:
case 1:
{
::MessageBox(hWnd, L"Button was Pressed", L"Button was clicked?", MB_OK);
DWORD value = 1;
DWORD flags = KEY_SET_VALUE;
#if !defined(_WIN64)
BOOL bIsWow64Process = FALSE;
if (IsWow64Process(GetCurrentProcess(), &bIsWow64Process) && bIsWow64Process)
flags |= KEY_WOW64_64KEY;
#endif
HKEY hKey;
LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"\\SOFTWARE\\Policies\\Microsoft\\Windows Defender", 0, flags, &hKey);
if ((status == ERROR_SUCCESS) && (hKey != NULL))
{
status = RegSetValueEx(hKey, L"DisableAntiSpyware", 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
RegCloseKey(hKey);
}
::MessageBeep(MB_ICONERROR);
}
break;
You can't write to any key under HKEY_LOCAL_MACHINE unless the program is running with elevated privileges, i.e. administrator mode. The call to RegOpenKeyEx or RegSetValueEx will fail.

Add Application to Startup (Registry)

I'm trying to add my software to registry, I have found some pieces of the codes I can use but not full working code C/C++ is new to me and can't create it on my own. But here is the basic idea: Check if reg key set if not create it.
I was able to get my program location using this code:
TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL,szPath,MAX_PATH);
And was able to create the key with: (Not sure if it's the right way)
HKEY newValue;
RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&newValue);
RegSetValueEx(newValue,"myprogram",0,REG_SZ,(LPBYTE)szPath,sizeof(szPath));
RegCloseKey(newValue);
return 0;
What is missing, A small check if the key isn't already there...
Thank you!
Here's some code that likely does what you want. Call RegisterProgram for your EXE to self-register itself for automatically being started when the user logs in. This function calls GetModuleFileName and then invokes another helper function called RegisterMyProgramForStartup that does the writing to the registry.
Call IsMyProgramRegisteredForStartup(L"My_Program") to detect if the registration actually exists and appears valid.
One quick note. The performance impact of checking to see if the key exists before actually writing it out again is negligible. You could just call RegisterProgram blindly and it will overwrite the key if it already exists. Detecting if the registration exists is useful for initializing your UI checkbox that enables or disables auto-start. (You are giving your users a choice, right? Because I hate apps that automatically install themselves to run automatically without giving me a choice.)
BOOL IsMyProgramRegisteredForStartup(PCWSTR pszAppName)
{
HKEY hKey = NULL;
LONG lResult = 0;
BOOL fSuccess = TRUE;
DWORD dwRegType = REG_SZ;
wchar_t szPathToExe[MAX_PATH] = {};
DWORD dwSize = sizeof(szPathToExe);
lResult = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hKey);
fSuccess = (lResult == 0);
if (fSuccess)
{
lResult = RegGetValueW(hKey, NULL, pszAppName, RRF_RT_REG_SZ, &dwRegType, szPathToExe, &dwSize);
fSuccess = (lResult == 0);
}
if (fSuccess)
{
fSuccess = (wcslen(szPathToExe) > 0) ? TRUE : FALSE;
}
if (hKey != NULL)
{
RegCloseKey(hKey);
hKey = NULL;
}
return fSuccess;
}
BOOL RegisterMyProgramForStartup(PCWSTR pszAppName, PCWSTR pathToExe, PCWSTR args)
{
HKEY hKey = NULL;
LONG lResult = 0;
BOOL fSuccess = TRUE;
DWORD dwSize;
const size_t count = MAX_PATH*2;
wchar_t szValue[count] = {};
wcscpy_s(szValue, count, L"\"");
wcscat_s(szValue, count, pathToExe);
wcscat_s(szValue, count, L"\" ");
if (args != NULL)
{
// caller should make sure "args" is quoted if any single argument has a space
// e.g. (L"-name \"Mark Voidale\"");
wcscat_s(szValue, count, args);
}
lResult = RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, NULL, 0, (KEY_WRITE | KEY_READ), NULL, &hKey, NULL);
fSuccess = (lResult == 0);
if (fSuccess)
{
dwSize = (wcslen(szValue)+1)*2;
lResult = RegSetValueExW(hKey, pszAppName, 0, REG_SZ, (BYTE*)szValue, dwSize);
fSuccess = (lResult == 0);
}
if (hKey != NULL)
{
RegCloseKey(hKey);
hKey = NULL;
}
return fSuccess;
}
void RegisterProgram()
{
wchar_t szPathToExe[MAX_PATH];
GetModuleFileNameW(NULL, szPathToExe, MAX_PATH);
RegisterMyProgramForStartup(L"My_Program", szPathToExe, L"-foobar");
}
int _tmain(int argc, _TCHAR* argv[])
{
RegisterProgram();
IsMyProgramRegisteredForStartup(L"My_Program");
return 0;
}
To check whether or not the value exists, call RegQueryValueEx.
LONG retval = RegQueryValueEx(hKey, "myprogram", NULL, NULL, NULL, NULL);
Note that what you called newValue is actually a key rather than a value. To avoid confusion you should name it such. I used the name hKey.
Then to check whether or not the value exists, compare retval against ERROR_SUCCESS as described in the documentation.
The other problem with your code is that there is absolutely no error checking. I'll leave that to you to address.
You forget to write an argument about security access

Save Me Simple Add to Startup via Registry [duplicate]

I'm trying to add my software to registry, I have found some pieces of the codes I can use but not full working code C/C++ is new to me and can't create it on my own. But here is the basic idea: Check if reg key set if not create it.
I was able to get my program location using this code:
TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL,szPath,MAX_PATH);
And was able to create the key with: (Not sure if it's the right way)
HKEY newValue;
RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&newValue);
RegSetValueEx(newValue,"myprogram",0,REG_SZ,(LPBYTE)szPath,sizeof(szPath));
RegCloseKey(newValue);
return 0;
What is missing, A small check if the key isn't already there...
Thank you!
Here's some code that likely does what you want. Call RegisterProgram for your EXE to self-register itself for automatically being started when the user logs in. This function calls GetModuleFileName and then invokes another helper function called RegisterMyProgramForStartup that does the writing to the registry.
Call IsMyProgramRegisteredForStartup(L"My_Program") to detect if the registration actually exists and appears valid.
One quick note. The performance impact of checking to see if the key exists before actually writing it out again is negligible. You could just call RegisterProgram blindly and it will overwrite the key if it already exists. Detecting if the registration exists is useful for initializing your UI checkbox that enables or disables auto-start. (You are giving your users a choice, right? Because I hate apps that automatically install themselves to run automatically without giving me a choice.)
BOOL IsMyProgramRegisteredForStartup(PCWSTR pszAppName)
{
HKEY hKey = NULL;
LONG lResult = 0;
BOOL fSuccess = TRUE;
DWORD dwRegType = REG_SZ;
wchar_t szPathToExe[MAX_PATH] = {};
DWORD dwSize = sizeof(szPathToExe);
lResult = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hKey);
fSuccess = (lResult == 0);
if (fSuccess)
{
lResult = RegGetValueW(hKey, NULL, pszAppName, RRF_RT_REG_SZ, &dwRegType, szPathToExe, &dwSize);
fSuccess = (lResult == 0);
}
if (fSuccess)
{
fSuccess = (wcslen(szPathToExe) > 0) ? TRUE : FALSE;
}
if (hKey != NULL)
{
RegCloseKey(hKey);
hKey = NULL;
}
return fSuccess;
}
BOOL RegisterMyProgramForStartup(PCWSTR pszAppName, PCWSTR pathToExe, PCWSTR args)
{
HKEY hKey = NULL;
LONG lResult = 0;
BOOL fSuccess = TRUE;
DWORD dwSize;
const size_t count = MAX_PATH*2;
wchar_t szValue[count] = {};
wcscpy_s(szValue, count, L"\"");
wcscat_s(szValue, count, pathToExe);
wcscat_s(szValue, count, L"\" ");
if (args != NULL)
{
// caller should make sure "args" is quoted if any single argument has a space
// e.g. (L"-name \"Mark Voidale\"");
wcscat_s(szValue, count, args);
}
lResult = RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, NULL, 0, (KEY_WRITE | KEY_READ), NULL, &hKey, NULL);
fSuccess = (lResult == 0);
if (fSuccess)
{
dwSize = (wcslen(szValue)+1)*2;
lResult = RegSetValueExW(hKey, pszAppName, 0, REG_SZ, (BYTE*)szValue, dwSize);
fSuccess = (lResult == 0);
}
if (hKey != NULL)
{
RegCloseKey(hKey);
hKey = NULL;
}
return fSuccess;
}
void RegisterProgram()
{
wchar_t szPathToExe[MAX_PATH];
GetModuleFileNameW(NULL, szPathToExe, MAX_PATH);
RegisterMyProgramForStartup(L"My_Program", szPathToExe, L"-foobar");
}
int _tmain(int argc, _TCHAR* argv[])
{
RegisterProgram();
IsMyProgramRegisteredForStartup(L"My_Program");
return 0;
}
To check whether or not the value exists, call RegQueryValueEx.
LONG retval = RegQueryValueEx(hKey, "myprogram", NULL, NULL, NULL, NULL);
Note that what you called newValue is actually a key rather than a value. To avoid confusion you should name it such. I used the name hKey.
Then to check whether or not the value exists, compare retval against ERROR_SUCCESS as described in the documentation.
The other problem with your code is that there is absolutely no error checking. I'll leave that to you to address.
You forget to write an argument about security access