I'm not sure where problem is occur.
I have demo code get value from an registry:
using namespace std;
typedef struct REGKEYS
{
HKEY hKey;
LPCTSTR subKey;
LPCTSTR value;
LPCTSTR name;
LPCTSTR file;
LPCTSTR tag;
} REGKEYS;
REGKEYS regkeys = {HKEY_LOCAL_MACHINE,"Software\\Internet Download Manager", "Serial", "IDM", NULL, NULL};
HKEY hKey;
LPBYTE szDataBuf;
DWORD dwSize;
int _tmain(int argc, _TCHAR* argv[])
{
RegOpenKeyEx(regkeys.hKey, regkeys.subKey, 0, KEY_READ, &hKey);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, szDataBuf, &dwSize);
int lerr = GetLastError();
system("pause");
return 0;
}
When debug, I see regkeys.hKey not point to anything (it need point to "HKEY_LOCAL_MACHINE", is it?).
And szDataBuf is empty.
(GetLastError() not help me - it return 0)
Anyone tell me where is problem and how to fix it?
EDIT2:
I edited my code to :
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwSize = 0;
RegOpenKeyEx(regkeys.hKey, regkeys.subKey, 0, KEY_READ, &hKey);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, NULL, &dwSize);
char *szDataBuf = new char(dwSize);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, (LPBYTE)szDataBuf, &dwSize);
delete[] szDataBuf;
system("pause");
return 0;
}
I debug and see szDataBuf get right value, but my program break and get warning: warning C4244: 'initializing' : conversion from 'DWORD' to 'char', possible loss of data.
First of all, your error checking code is not correct. The registry functions all return Win32 error codes. You need to take notice of them and check for errors.
To be clear, GetLastError is no use because these functions do not call SetLastError. They return the error code directly. You must read the documentation carefully. There are often subtle differences in the way different parts of Win32 do error handling.
The code in your updated question is better, but it still fails to check for errors in the call to RegOpenKeyEx.
Now, beyond that you are not actually calling RegQueryValueEx correctly. You have not initialized dwSize, and you have not allocated szDataBuf. Since these are global variables, they will be zero initialised. So your call to RegQueryValueEx will indeed succeed if the value exists. But you cannot expect any value to arrive in the buffer since you did not allocate a buffer. You are passing NULL to the lpData parameter.
So, allocate a buffer. For instance:
char szDataBuf[128];
Initialise dwSize:
DWORD dwSize = sizeof(szDataBuf);
Then your call to RegQueryValueEx should be
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL,
(LPBYTE)szDataBuf, &dwSize);
Although you may wish to allocate the buffer dynamically:
dwSize = 0;
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL, NULL, &dwSize);
// check lerr here
vector<char> szDataBuf(dwSize);
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL,
(LPBYTE)&szDataBuf[0], &dwSize);
// check lerr here
You might also consider avoiding the use of global variables here. All of the variables you use would be make more sense as locals.
Related
I need to implement a wrapper class around Winreg.h library.
Problem: All functions work correctly except RegCreateKeyEx, when I try to pass the parameters it returns Error 87.
Example:
When I hardcode the subkey inside the function it works just fine.
HKEY hKey = NULL;
DWORD dc;
int rc = RegCreateKeyEx(HKEY_USERS, L"AppUser\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dc);
But when I parameterized the function like this so I can make the subkey variable and make resursive calls to it it produces Error 87.
HKEY hKey = NULL;
DWORD dc;
const std::wstring szSub = L"AppUser\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
LPCWSTR lpszSub = szSub.c_str();
int rc = RegCreateKeyEx(HKEY_USERS, lpszSub, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dc);
I'm just starting with this library so I don't know what I'm missing, maybe a formatting error or something else. I would appreciate any help or suggestion.
i try to read the Registry in my NPAPI-Plugin:
bool ScriptablePluginObject::Invoke(NPObject* obj, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result) {
ScriptablePluginObject *thisObj = (ScriptablePluginObject*) obj;
char* name = npnfuncs->utf8fromidentifier(methodName);
LPCWSTR game_path = getRegKey(L"SOFTWARE\\World of RPG", L"Path");
MessageBox(NULL, game_path, L"Debugging", MB_TOPMOST);
/* ... */
}
LPCWSTR ScriptablePluginObject::getRegKey(LPCWSTR location, LPCWSTR name) {
HKEY hKey;
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
long registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, location, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
long entry = RegQueryValueEx(hKey, name, NULL, REG_NONE, folder, &dwSize);
if(registry != ERROR_SUCCESS) {
return L"Error1";
}
if(entry != ERROR_SUCCESS) {
return L"Error2";
}
RegCloseKey(hKey);
folder[dwSize / sizeof(folder[0])] = '\0';
return (LPCWSTR) folder;
}
But it's returned every call Error2. I've tried a lot of changes:
change the Path (with Start and/or Ending \\)
change parameters
I Want to get the Path of HKEY_LOCAL_MACHINE\SOFTWARE\World of RPG\Path:
Anyone can help me? What i'm doing wrong?
Here's the sample I mentioned in the comments above:
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, DWORD *pBufferSize );
int _tmain(int argc, _TCHAR* argv[])
{
const int BUFFER_SIZE = 1024;
WCHAR sBuffer[BUFFER_SIZE]; // 2048 bytes
DWORD nBufferSize = BUFFER_SIZE * sizeof ( WCHAR );
ZeroMemory ( sBuffer, nBufferSize );
LSTATUS nResult = ReadRegistry ( L"SOFTWARE\\7-Zip", L"Path64",
sBuffer, &nBufferSize );
// check nResult for ERROR_SUCCESS to know if the call succeeded or not
return 0;
}
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, LPDWORD pBufferSize )
{
HKEY hKey;
LSTATUS nResult = ::RegOpenKeyEx ( HKEY_LOCAL_MACHINE, sPath,
0, KEY_READ | KEY_WOW64_64KEY, &hKey );
if ( nResult == ERROR_SUCCESS )
{
nResult = ::RegQueryValueEx ( hKey, sKey, NULL, NULL,
(LPBYTE) pBuffer, pBufferSize );
RegCloseKey ( hKey );
}
return ( nResult );
}
Notice how the ReadRegistry function doesn't allocate memory - it takes a buffer and fills it with data. It's a lot easier to deal with memory if you always have the caller allocate memory. If the callee allocates memory, the caller may not know how memory was allocated and it may not know how to free it. (Of course, you can always assume the use of new and delete but things are simpler if only one side does this consistently. If the caller allocates memory, it'll know how to free it. The callee only needs to put data in the allocated space.
Also, notice how the return value of the API functions is checked before proceeding to the next call - this is important because this tells you if you got a useful registry handle back or not and whether you need to close it or not.
(This sample is really just C, not C++ but it still applies.)
In getRegKey(), your folder variable is a pointer, so sizeof(folder) is 4 (if compiling for 32bit) or 8 (if compiling for 64bit). Thus RegQueryValueEx() fails with an ERROR_MORE_DATA error code.
You are also using the wrong data type for the array. You need to use WCHAR instead of BYTE.
Change this:
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
To this:
LPWSTR folder = new WCHAR[MAX_PATH];
DWORD dwSize = sizeof(WCHAR) * MAX_PATH;
With that said, you are leaking the memory pointed to by folder, since you never delete[] it.
I would like to detect, and if possible read to a CString, a registry key starting with "HKEY_LOCAL_MACHINE\SOFTWARE\blah\SetupPath".
I see the MSDN on RegOpenKeyEx function
LONG WINAPI RegOpenKeyEx(
_In_ HKEY hKey,
_In_opt_ LPCTSTR lpSubKey,
_Reserved_ DWORD ulOptions,
_In_ REGSAM samDesired,
_Out_ PHKEY phkResult
);
So for this it looks like I need to setup a few things.
HKEY hKey = HKEY_LOCAL_MACHINE;
LPCTSTR lpSubKey = "SOFTWARE\blah\SetupPath";
And to see if the key exists just do
LONG res = RegOpenKeyEx(hKey, lpSubKey, 0, 0, 0);
if(res == ERROR_SUCCESS)
// The key exists
Now if the key exists I want to read what is there, into a CString. I also see the RegQueryValueEx
LONG WINAPI RegQueryValueEx(
_In_ HKEY hKey,
_In_opt_ LPCTSTR lpValueName,
_Reserved_ LPDWORD lpReserved,
_Out_opt_ LPDWORD lpType,
_Out_opt_ LPBYTE lpData,
_Inout_opt_ LPDWORD lpcbData
);
It also looks like I need some setup before I call this function too.
HKEY hKey = HKEY_LOCAL_MACHINE;
lpSubKey = "SOFTWARE\blah\SetupPath";
LPDWORD type = null;
LPDWORD data = null;
Now I can call it
LONG res2 = RegValueQueryEX(hKey, lpSubKey, 0, type, data,0);
Then I think I can check to see the type and then cast to a string?
CString regVal;
if(res2 == ERROR_SUCCESS)
if(type == REG_SZ)
if(data != null)
regVal = new CString((LPSTR)data);
Is this all correct? What might I be missing or need to do?
No that's not correct. Your main misunderstanding is how pointers work in C++. It's not enough to supply NULL for a pointer argument, you must supply a pointer to a variable so that the RegOpenKeyEx or RegValueQueryEx routine can return a value to that variable. You also seem to be misunderstanding how to assign to a CString (no need for new). Finally although it's not an error you don't need to do 'setup' you just pass the values directly to the function.
First open the key
HKEY key;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\blah", 0, 0, &key);
then get the value
DWORD type, size;
char data[99];
size = sizeof(data);
RegQueryValueEx(key, "SetupPath", 0, &type, (BYTE*)data, &size);
then assign the value to your CString
CString regval(data);
finally close the key
RegCloseKey(key);
No error checking in that code, you should add it. Also I'm assuming that any value you could get will fit in 99 bytes, that might not be true.
Note how I pass a pointer to the key variable, so that RegOpenKeyEx can return the key. I then use that key in the call to RegValueQueryEx and RegCloseKey. Same for the type and size variables. Also note that I've split the path between the calls to RegOpenKeyEx and RegValueQueryEx. I think that is correct.
Not 100% sure that is correct, I haven't tested it but should be quite a bit closer.
Is this all correct? What might I be missing or need to do?
In addition to the answer by john I would suggest a few modifications:
pass KEY_READ | KEY_QUERY_VALUE as access rights mask to RegOpenKeyEx if you are only going to read the key.
RegQueryValueEx may return ERROR_MORE_DATA if the buffer size is too small. Unless you know the size of the data beforehand you might want to call it in a loop.
simple way to enabled javascript execution in internet explorer using the registry:
HKEY hKey;
RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3"),
NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE,
NULL, &hKey, NULL);
DWORD byte = 0x0;
RegSetValueEx(hKey, L"1400", NULL, REG_DWORD, (BYTE*)&byte, sizeof(byte));
RegCloseKey(hKey);
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
I'm creating a NPAPI dll file and I need to get some information from the registry, but when I use RegQueryValueEx, I get some strange characters.
For instance, my computer model is "N310", but I get "Nfb1fb1" or "N$(".
I'm pretty sure that it's a charset issue, but I'm new with C++ and I need some help.
I'm using Visual Studio 2010 and my project is using the UNICODE charset.
Here is my code:
char lszValue[255];
std::string cadena;
HKEY hKey;
LONG returnStatus;
DWORD dwType=REG_SZ;
DWORD dwSize=255;
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", NULL, KEY_READ, &hKey);
if (returnStatus == ERROR_SUCCESS) {
returnStatus = RegQueryValueEx(hKey, L"SystemProductName", NULL, &dwType,(LPBYTE)&lszValue, &dwSize);
lszValue[dwSize] = 0;
cadena.assign(lszValue, dwSize);
return cadena;
}
Thank you very much and thanks for advance.
If your project uses UNICODE charset, then probably all WINAPI functions are bound to unicode strings, that is, RegQueryValueEx is actually RegQueryValueExW that takes wchar_t array, not char array.
When using non-Unicode, single-byte projects, the function would be RegQueryValueExA and it would work with char[].
To make your project (non)unicode-safe, use TCHAR macro instead of char.
try this code:
DWORD const dwSize=255;
TCHAR lszValue[dwSize];
std::wstring cadena;
HKEY hKey;
LONG returnStatus;
DWORD dwType=REG_SZ;
returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", NULL, KEY_READ, &hKey);
if (returnStatus == ERROR_SUCCESS)
{
returnStatus = RegQueryValueEx(hKey, L"SystemProductName", NULL, &dwType, (LPBYTE)&lszValue, &dwSize);
lszValue[dwSize] = 0;
cadena.assign(lszValue, dwSize);
return cadena;
}
I've changed just the types. There may be other errors/typos. Just remember that std::wstring is for wchar_t