If Registry Key Does Not Exist - c++

I'm adding my program to start up with:
TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL,szPath,MAX_PATH);
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;
And I wanted to add a check if key doesn't exists only then to create it. And something else is weird with my code I have checked the registry for my key and I see in the data column my application path + "..." (after .exe) and when I double click to check the data the popup opens and it's fine it's .exe only not .exe...
Thanks for you help :)

The value you wrote out is MAX_PATH bytes wide, regardless of how long the path really is. Thus you probably have a lot of non-printing characters after the .exe, and that's why you see the "...".
The documentation says the last parameter is the size in bytes of the string, including the null terminator. So we need to know the length of the string (lstrlen(szPath)), we need to account for the null terminator (+ 1), and we need to convert from TCHARs to bytes (sizeof(TCHAR)*).
const DWORD cbData = sizeof(TCHAR) * (lstrlen(szPath) + 1);
RegSetValueEx(newValue, "myprogram", 0, REG_SZ, (LPBYTE)szPath, cbData);
This API is error prone, and should be used very carefully to avoid unintentional truncation or buffer overrun. (The fact that you need those casts to get it to compile should make you very cautious.) Many Windows functions that take pointers to strings want lengths in characters (which may not be bytes) or they figure out the length from the termination. This one doesn't do either of those things.

you can check the registry function output....
Here I am giving the Idea you can use it...
bool function()
{
HKEY hKey;
LPCTSTR subKey;
LPCTSTR subValue;
HKEY resKey;
DWORD dataLen;
hKey = HKEY_LOCAL_MACHINE;
subKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
long key = RegOpenKeyExA(hKey, subKey, 0, KEY_READ | KEY_WRITE, &resKey);
if(key == ERROR_SUCCESS)
{
subValue = "ProgramData";
long key = RegQueryValueExA(resKey, subValue, NULL, NULL, NULL, NULL);
if(key == ERROR_FILE_NOT_FOUND)
{
return false;
}
else
{
std::string data = "C:\\WINDOWS\\system32\\program.exe";
DWORD dataLen = data.size()+1;
long key = RegSetValueExA(resKey, subValue, 0, REG_SZ, (const BYTE*)data.c_str(), dataLen);
if(key == ERROR_SUCCESS)
{
return true;
}
else
{
return false;
}
}
}
else
{
return false;
}
}

You can use RegCreateKeyEx() to create a new key or open an existing key.
The "..." you see in RegEdit is because the column is not wide enough -- double-click at the end of the column-header to resize the column.

I suggest what is suggest in the MSDN: You should enumerate the Subkeys/Values in a Key with RegEnumKey(Ex)() or RegEnumValue() and then check wether the key is listed
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms724861%28v=vs.85%29.aspx
and http://msdn.microsoft.com/en-us/library/windows/desktop/ms724256%28v=vs.85%29.aspx for an example.
Hope this helps.

Related

Read Timezoneinfo from windows registry (C++)

I am trying to read the TIME_ZONE_INFORMATION struct from windows registry with the following code:
void GetTimeZoneInfo(){
TIME_ZONE_INFORMATION tz = {0};
TIME_ZONE_INFORMATION tz_data={0};
char *keyname="TZI";
DWORD size = sizeof(tz_data);
HKEY hk = NULL;
char *zone_key = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\Central Standard Time";
if ((RegOpenKeyExA(HKEY_LOCAL_MACHINE, zone_key, 0, KEY_READ, &hk) == ERROR_SUCCESS))
{
if(RegQueryValueExA(hk, keyname, NULL, NULL, (LPBYTE) &tz_data, &size) == ERROR_SUCCESS)
{ /*Control enters here*/
/*Read the data*/
cout<<"Successful in retrieving the value"<<endl;
tz.Bias = tz_data.Bias;
tz.DaylightBias = tz_data.DaylightBias;
tz.DaylightDate = tz_data.DaylightDate;
tz.StandardBias = tz_data.StandardBias;
tz.StandardDate = tz_data.StandardDate;
}
else{ cout<<"Failure in retrieving the value"<<endl;}
}
else { cout<<"RegOpenKey Failure!"<<endl;}
}
It sets all to zero value, but don't see any error on running RegOpenKeyExA and RegQueryValueExA.
TIME_ZONE_INFORMATION is stored in registry as type: REG_BINARY
Is this the right way to read from registry?
According to MS docs TZI key contains the following time zone information:
typedef struct _REG_TZI_FORMAT
{
LONG Bias;
LONG StandardBias;
LONG DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
} REG_TZI_FORMAT;
You are reading to a wrong struct - TIME_ZONE_INFORMATION.
A couple of things:
In most cases you should be using the DYNAMIC_TIME_ZONE_INFORMATION structure, as it supports the full range of data that is in the registry. Most of the Win32 time zone functions have alternative versions that work with the dynamic structures.
You don't need to load the information from the registry yourself. Instead, use EnumDynamicTimeZoneInformation. Enumerate them until the TimeZoneKeyName matches the one you are looking for.
As nevilad pointed out, the TZI entries in the registry data aligns with _REG_TZI_FORMAT, which is slightly different than TIME_ZONE_INFORMATION structure. (But again, you don't need to read from the registry yourself.
)

Checking if registry key is link to (or copy of) another one

How can I check out if registry key is link to another one using winapi?
For example, I need to find out which branch is original HKEY_LOCAL_MACHINE\SECURITY\SAM or HKEY_LOCAL_MACHINE\SAM\SAM, HKEY_CURRENT_USER or HKEY_USERS\S-1-5-21.
I'm confused with types of keys and values. Does key have type? Can I use REG_LINK type for this purpose?
First of all we must open the key itself, rather than the key that the potential symbolic link key refers to (which is the default behavior).
For this we need to use REG_OPTION_OPEN_LINK option in call RegOpenKeyExW or ZwOpenKeyEx.
An alternative way is to use OBJ_OPENLINK attribute in OBJECT_ATTRIBUTES. and use this in call ZwOpenKey[Ex]
After the key is opened we can query (starting from win7) undocumented KeyFlagsInformation information via ZwQueryKey. If the flags shows that this is symbolic link - we can query SymbolicLinkValue value to get the link target key. Note that even if this value exists with type REG_LINK - this doesn't prove that this is symbolic link.
struct KEY_CONTROL_FLAGS_INFO_W7 // KeyFlagsInformation for Win7
{
ULONG ControlFlags[3];
};
#define KEY_CTRL_FL_W7_01__IS_VOLATILE 0x01
#define KEY_CTRL_FL_W7_01__SYM_LINK 0x02
LSTATUS IsSymLink(HKEY hKey, PCWSTR lpSubKey, BOOL& IsLink)
{
LSTATUS r = RegOpenKeyEx(hKey, lpSubKey, REG_OPTION_OPEN_LINK, KEY_READ|KEY_WOW64_64KEY, &hKey);
if (r == NOERROR)
{
ULONG Type, cb = 0, rcb = 0x80;
KEY_CONTROL_FLAGS_INFO_W7 kcf;
NTSTATUS status;
if (0 <= (status = ZwQueryKey(hKey, KeyFlagsInformation, &kcf, sizeof(kcf), &cb)))
{
if (kcf.ControlFlags[1] & KEY_CTRL_FL_W7_01__SYM_LINK)
{
IsLink = TRUE;
DbgPrint("key is link\n");
PVOID stack = alloca(guz), buf = 0;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
r = RegQueryValueExW(hKey, L"SymbolicLinkValue", 0, &Type, (PBYTE)buf, &(rcb = cb));
if (r == NOERROR && Type == REG_LINK && !(rcb & (sizeof(WCHAR) - 1)))
{
DbgPrint("%.*S\n", rcb / sizeof(WCHAR), buf);
}
} while (r == ERROR_MORE_DATA);
}
}
else
{
r = RtlNtStatusToDosError(status);
}
RegCloseKey(hKey);
}
return r;
}
Does key have type?
No. type have values of key only
Can I use REG_LINK type for this purpose?
We can on a regular(not link) key create SymbolicLinkValue value with type REG_LINK, but key doesn't become a link after this. Key must be initially created with REG_OPTION_CREATE_LINK option. So by querying SymbolicLinkValue value we can't reliably check if this is a link, but if we know that this is a link - we can get the target of the link by querying SymbolicLinkValue

Key value not being retrieved using CRegKey::QueryStringValue

I am unable to retrieve string value from registry using CRegKey::QueryStringValue()
Here is my code please let me know where am going worng.Here is the code.
bool bResult;
int nSize = 50;
LPTSTR csKeyValue = NULL;
bResult = m_cKey.QueryStringValue(_T(REGISTRY_VALUE_NAME),csKeyValue,(ULONG*)&nSize);
if(bResult == ERROR_SUCCESS){
return true;
}
Somebody please help me and point me to right direction.
Thanks in advance.
csKeyValue must be a pointer to a buffer that will receive the string data. Yours is pointing to NULL, which will not work. Declare a buffer with an ample size, such as wchar_t KeyValue[1024] and pass KeyValue.

Reading from a very large text file resource in C++

We have some data in a text file which is built into our executable as a custom resource to be read at runtime. The size of this text file is over 7 million characters.
I can successfully search for and locate strings within the resource which appear near the top of the text file, but when attempting to search for terms a few million characters down, strstr returns NULL indicating that the string cannot be found. Is there a limit to the length of a string literal that can be stored in a char* or the amount of data that can be stored in an embedded resource? Code is shown below
char* data = NULL;
HINSTANCE hInst = NULL;
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(IDR_TEXT_FILE1), "TESTRESOURCE");
if(NULL != hRes)
{
HGLOBAL hData = LoadResource(hInst, hRes);
if (hData)
{
DWORD dataSize = SizeofResource(hInst, hRes);
data = (char*)LockResource(hData);
}
else
break;
char* pkcSearchResult = strstr(data, "NumListDetails");
if ( pkcSearchResult != NULL )
{
// parse data
}
}
Thanks.
The problem might be the method you use for searching. strstr uses ANSI strings, and will terminate when it encounters a '\0' in the search domain.
You might use something like memstr (one of many implementations can be found here).
Do you get any output from GetLastError(), specifically after calling SizeofResource.
You can also check that dataSize > 0 to ensure an error hasn't occurred.
DWORD dataSize = SizeofResource(hInst, hRes);
if(dataSize > 0)
{
data = (char*)LockResource(hData);
}
else
{
//check error codes
}
MSDN Docs
The problem was null characters in the data which prematurely ended the char* variable. To get around this I just had to read the data into a void pointer then copy it into a dynamically created array.
DWORD dataSize = SizeofResource(hInst, hRes);
void* pvData = LockResource(hData);
char* pcData = new char[dataSize];
memcpy_s(pcData,strlen(pcData),pvData,dataSize);

c++ loop through registry recursively is slow

Have an annoying problem with my code, probably I am doing something wrong because my Python
implementation is much faster!
C++ implementation problems:
Iterating over "HKEY_CLASSES_ROOT" takes a lot of ram, I assume it's because c++ implementation uses lots of variables. Fixed
It's also slow, much slower than python implantation of the code Fixed
The code even slower when trying to iterate over HKEY_CLASSES_ROOT Fixed
New Questions:
Thanks to Nam Nguyen i understood what causing the leaks in my code, and directly effecting execution time, the code below is the fixed one. how come c++ implementation runs as fast as my python implementation?
C++ implementation:
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string>
using namespace std;
#define MAX_KEY_LENGTH 255
int RecurseOpenRegEx(HKEY hkey, string subKey = "",string search = "nothing", DWORD sum = 0)
{
TCHAR csubKey[MAX_KEY_LENGTH];
DWORD nSubKeys = 0;
DWORD pathLength = MAX_PATH;
TCHAR storeKeyName[MAX_KEY_LENGTH];
DWORD keyLength;
HKEY hKey = hkey; //somehow i need to reassign HKEY, otherwise it won't pass it with the function, this is bigger than me tough...
const char * ccsearch = search.c_str();
const char * ccsubKey;
if (subKey != "")
{
ccsubKey = subKey.c_str();
copy(subKey.begin(), subKey.end(),csubKey); //convert string to TCHAR
}
if (RegOpenKeyEx(hkey, ccsubKey, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
{
if (RegQueryInfoKey(hkey, csubKey, &pathLength, NULL,&nSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
sum += nSubKeys;
for (DWORD subKeyIndex = 0; subKeyIndex < nSubKeys; subKeyIndex++)
{
keyLength = MAX_KEY_LENGTH;
if (RegEnumKeyEx(hkey, subKeyIndex, storeKeyName, &keyLength, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
{
string sKeyName = storeKeyName; //Convert TCHAR to string explicitly
if (subKey != "")
{
sKeyName = subKey + "\\" + sKeyName;
}
sum += RecurseOpenRegEx(hKey, sKeyName);
}
}
}
}
RegCloseKey(hkey); //Now closing the right key
return sum;
}
int main()
{
cout << "sum of all keys: " << RecurseOpenRegEx(HKEY_LOCAL_MACHINE);
return 0;
}
Python implementation:
import winreg
def recurseRegistrySearch(key, keySearch = "",subkey = "", subkeypath = "", x = 0):
key = winreg.OpenKey(key, subkey, 0)
y = winreg.QueryInfoKey(key)[0]
x += y
for items in range(x):
try:
subkey = winreg.EnumKey(key, items)
if ((keySearch.lower() in subkey.lower()) and (keySearch != "")):
print(subkeypath + "\\" + subkey)
x += recurseRegistrySearch(key, keySearch, subkey, subkeypath = subkeypath + "\\" + subkey)
except WindowsError:
pass
return x
print("sum of all keys: {0}".format(recurseRegistrySearch(winreg.HKEY_CLASSES_ROOT)))
There is leak of resource in your code. You open hkey but you close hKey (note the difference in case of k and K).
On a side note, you store the opened registry key into hkey itself. And it happens that hkey is the passed in parameter, shared among all calls to RecurseOpenRegEx. That is why "somehow i need to reassign HKEY".
Basically, what I can advise you now is immediately clean up your code. Bugs like these are hard to spot when your code is a too difficult to read. Once done, I believe you will find it easier to debug/trace.
Probably it's your heavy use of string variables ,which involves a lot of dynamic memory allocations.
Try accepting parameters as LPCTSTR .assign string variables inside the function with those LPCTSTRs and pass parameters with str.c_str().