Enumerating all subkeys and values in a Windows registry key - c++

I am trying to write a Windows application that gives me back all the subkeys and values given a certain key. I've written code that appears to work as far as providing subkeys within the given key, but doesn't work at properly enumerating the values; it successfully enumerates subkeys without values and returns the results in kind of tabbed tree arrangement. However, when enumerating values, the program gives back a random value for each value present (the same random value each time), and then crashes afterwards with a debug error.
It's intended output is basically:
(1) KEY
(1) SUBKEY
(1) SUBKEYWITHINSUBKEY
Code: value1data
Code: value2data
Code: value3data
(2) SUBKEY
(1) SUBKEYWITHINSUBKEY
(3) SUBKEY
...and so on.
The output I get instead is something like:
(1) KEY
(1) SUBKEY
(1) SUBKEYWITHINSUBKEY
Code: someValue
Code: someValue
Code: someValue
(...and then the crash)
This is followed with the following error:
"Debug Error! "Run-Time Check Failure #2 - Stack around the variable 'valNameLen' was corrupted."
The code is a bit messy currently (I'm a Windows API newbie), but if anyone could show me what I'm doing wrong, or critique my coding style in anyway they feel fit, that would be great.
Thanks!
-R
/*
Windows Registry Subkey Enumeration Example
Based on example found at code-blue.org
*/
#include <windows.h>
#include <stdio.h>
void EnumerateValues(HKEY hKey, DWORD numValues)
{
DWORD dwIndex = 0;
LPSTR valueName = new CHAR[64];
DWORD valNameLen;
DWORD dataType;
DWORD data;
DWORD dataSize;
for (int i = 0; i < numValues; i++)
{
RegEnumValue(hKey,
dwIndex,
valueName,
&valNameLen,
NULL,
&dataType,
(BYTE*)&data,
&dataSize);
dwIndex++;
printf("Code: 0x%08X\n", data);
}
}
void EnumerateSubKeys(HKEY RootKey, char* subKey, unsigned int tabs = 0)
{
HKEY hKey;
DWORD cSubKeys; //Used to store the number of Subkeys
DWORD maxSubkeyLen; //Longest Subkey name length
DWORD cValues; //Used to store the number of Subkeys
DWORD maxValueLen; //Longest Subkey name length
DWORD retCode; //Return values of calls
RegOpenKeyEx(RootKey, subKey, 0, KEY_ALL_ACCESS, &hKey);
RegQueryInfoKey(hKey, // key handle
NULL, // buffer for class name
NULL, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&maxSubkeyLen, // longest subkey length
NULL, // longest class string
&cValues, // number of values for this key
&maxValueLen, // longest value name
NULL, // longest value data
NULL, // security descriptor
NULL); // last write time
if(cSubKeys>0)
{
char currentSubkey[MAX_PATH];
for(int i=0;i < cSubKeys;i++){
DWORD currentSubLen=MAX_PATH;
retCode=RegEnumKeyEx(hKey, // Handle to an open/predefined key
i, // Index of the subkey to retrieve.
currentSubkey, // buffer to receives the name of the subkey
&currentSubLen, // size of that buffer
NULL, // Reserved
NULL, // buffer for class string
NULL, // size of that buffer
NULL); // last write time
if(retCode==ERROR_SUCCESS)
{
for (int i = 0; i < tabs; i++)
printf("\t");
printf("(%d) %s\n", i+1, currentSubkey);
char* subKeyPath = new char[currentSubLen + strlen(subKey)];
sprintf(subKeyPath, "%s\\%s", subKey, currentSubkey);
EnumerateSubKeys(RootKey, subKeyPath, (tabs + 1));
}
}
}
else
{
EnumerateValues(hKey, cValues);
}
RegCloseKey(hKey);
}
int main()
{
EnumerateSubKeys(HKEY_CURRENT_USER,"SOFTWARE\\MyKeyToSearchIn");
return 0;
}

Enumerating the keys this way is overkill. This would simply waste the system resources, memory, call-stack and put pressure on registry sub-system. Do not do unless needed.
Are you going to have "search registry" in your application? If yes, enumerate only when user demands so. Or, if you are developing "Registry Viewer/Editor", do expand and open sub-keys only when needed.
If you absolutely need to retrieve and store all keys/values, you can use multiple threads to enumerate the keys. The number of threads would initially be the HKEY-major-keys, and then you can have more threads, depending on number of sub keys and runtime heuristics you perform while enumerating the keys.
Recursion may or may not be good approach for "recursive-enumeration" of sub-keys - you must keep number of arguments to recursive implementation minimum - put the arguments into one struct or put them in class. You may also like to use std::stack for the same.

It appears that you are calling RegEnumValue() without setting the lpcchValueName parameter to a proper value. This parameter is an [in] parameter as well as an [out] parameter. Try this:
for (int i = 0; i < numValues; i++)
 {
DWORD valNameLen = 64; //added this line to match valueName buffer size
  RegEnumValue(hKey,
     dwIndex,
     valueName,
     &valNameLen,
     NULL,
     &dataType,
     (BYTE*)&data,
     &dataSize);
Documentation for RegEnumValue() : http://msdn.microsoft.com/en-us/library/ms724865(v=vs.85).aspx

I tried your code on a key with a very small number of subkeys.
In the function EnumerateValues after calling RegEnumValue once, the value of numValues is getting filled with some random junk.
The solution is to change the parameters of RegEnumValue to
RegEnumValueA(hKey,
dwIndex,
valueName,
&valNameLen,
nullptr,
nullptr,
nullptr,
nullptr);
This is the function finally,
void EnumerateValues(HKEY hKey, DWORD numValues)
{
DWORD dwIndex = 0;
LPSTR valueName = new CHAR[64];
DWORD valNameLen;
DWORD numback = numValues;
for (int i = 0; i < numValues; i++)
{
// printf("%lu, %d\n", numValues, i);
RegEnumValueA(hKey,
dwIndex,
valueName,
&valNameLen,
nullptr,
nullptr,
nullptr,
nullptr);
dwIndex++;
if (i > numback)
{
RegCloseKey(hKey);
printf("Inf loop exiting...\n");
exit(-1);
}
// printf("Code: 0x%08X, %lu, %d\n", data, numValues, i);
// printf("Code: %lu, %d\n", numValues, i);
}
RegCloseKey(hKey);
}

I fixed your code and posted it on github.
Main problem was that you need to make your own buffer and point data to it, and it is also required that dataSize is set before calling RegEnumValue. Among other things, the program won't run without user elevation(admin) if you call RegOpenKeyEx with all permissions, so I changed them to read only. I bet this detail gave many people a headache.

Related

Getting the value of OpenSavePidlMRU in the registry

I'm trying to get the last opened directory by an open file dialog, and it seems that we can get it by first retrieving the key's name that contains the path using the first BYTE of the MRUListEx key, then the path can be obtained by reading the value of this key's name.
MRUListEx key can be find at: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedPidlMRU.
The problem is that I don't know how to properly fill the "SHITEMID" structure. (it doesn't let me access the index, and it throws a Memory access violation). I don't even know if the code below is valid in any points.
Sorry, the code is very dirty for the moment but I'll revamps it when I finally find what causes these errors.
void MyClass::OnDocumentSave(bool showSaveDlg)
{
// Do something that is not relevant here...
try {
HKEY hKey = NULL;
std::wstring regPath = LR"(Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedPidlMRU\)";
LSTATUS statusCode = RegOpenKeyExW(HKEY_CURRENT_USER, regPath.data(), 0, KEY_QUERY_VALUE, &hKey);
if (statusCode != ERROR_SUCCESS)
throw std::exception(std::string("Unable to open the specified registry key, sys err code: ") + std::to_string(statusCode));
BYTE data[MAX_PATH];
DWORD bufferSize = MAX_PATH;
statusCode = RegGetValueW(hKey, L"", L"MRUListEx", RRF_RT_REG_BINARY, NULL, &data, &bufferSize);
if (statusCode != ERROR_SUCCESS)
throw std::runtime_error(std::string("Failed at RegGetValue() Sys error code: ") + std::to_string(statusCode));
// Please note that the buffer has intentionally a fixed size here and everything is
// simplified for readability, but it uses dynamic memory allocation in the real code to
// handle errors such as ERROR_MORE_DATA
BYTE* pathData[512];
bufferSize = 512;
DWORD type = 0; // In case it matters, the returned value is 3
statusCode = RegGetValueW(hKey, L"", std::to_wstring(data[0]).c_str(), RRF_RT_REG_BINARY, &type, &pathData, &bufferSize);
if (statusCode != ERROR_SUCCESS)
throw std::runtime_error(std::string("Failed at RegGetValue() Sys error code: ") + std::to_string(statusCode));
// I don't know how to fill this structure, the documentation is very minimal,
// and I don't understand it.
int offset = sizeof(APPNAME);
SHITEMID shellIDList[2]{
// Throw a memory access violation at 0x*****, the debugger can't seems to
// get anything in pathData.
{ sizeof(USHORT) + sizeof(pathData), *pathData[0 + offset] },
{ 0, 0 } };
ITEMIDLIST idl{ shellIDList[0] };
// This is supposed give me the last path that was opened by a File Picker.
SHGetPathFromIDListW(&idl, initialDir.data());
}
catch (std::exception& e) {
// Silently set the initial directory to a hard-coded path instead of getting the registry value.
}
}
You don't seem to understand how types and simple arrays work! BYTE* pathData[512]; is not a 512 byte buffer. Use BYTE pathData[512];.
After reading into pathData, call SHGetPathFromIDList((PCIDLIST_ABSOLUTE) pathData, ...);.
That being said, that ComDlg32 key is undocumented and I don't think it stores a pidl so even if your code is corrected it is not going to work.
EnumMRUListW is a documented function you can call but it is not going to help you decode the data.
It looks to me like the location might be prefixed with the name of the .exe so as a minimum you would have to skip (lstrlenW(pathData)+1)*2 bytes before you find the real data...
If you're going for undocumented stuff, here is a code that can dump an MRU list like the LastVisitedPidlMRU one:
// the Shell object that can read MRU lists
static GUID CLSID_MruLongList = { 0x53bd6b4e,0x3780,0x4693,{0xaf,0xc3,0x71,0x61,0xc2,0xf3,0xee,0x9c} };
typedef enum MRULISTF
{
MRULISTF_USE_MEMCMP = 0x0,
MRULISTF_USE_STRCMPIW = 0x1,
MRULISTF_USE_STRCMPW = 0x2,
MRULISTF_USE_ILISEQUAL = 0x3,
};
typedef int (__stdcall *MRUDATALISTCOMPARE)(const BYTE*, const BYTE*, int);
MIDL_INTERFACE("00000000-0000-0000-0000-000000000000") // unknown guid but we don't care
IMruDataCompare : public IUnknown
{
public:
virtual HRESULT CompareItems(const BYTE*, int, const BYTE*, int) = 0;
};
MIDL_INTERFACE("d2c22919-91f5-4284-8807-58a2d64e561c")
IMruDataList2 : public IUnknown
{
public:
virtual HRESULT InitData(UINT uMax, MRULISTF flags, HKEY hKey, LPCWSTR pszSubKey, MRUDATALISTCOMPARE pfnCompare) = 0;
virtual HRESULT AddData(const BYTE* pData, DWORD cbData, DWORD* pdwSlot) = 0;
virtual HRESULT InsertData(const BYTE*, DWORD cbData, int* piIndex, DWORD* pdwSlot) = 0;
virtual HRESULT FindData(const BYTE* pData, DWORD cbData, int* piIndex) = 0;
virtual HRESULT GetData(int iIndex, BYTE* pData, DWORD cbData) = 0;
virtual HRESULT QueryInfo(int iIndex, DWORD* pdwSlot, DWORD* pcbData) = 0;
virtual HRESULT Delete(int iIndex) = 0;
virtual HRESULT InitData2(UINT uMax, MRULISTF flags, HKEY hKey, LPCWSTR pszSubKey, IMruDataCompare* pfnCompare) = 0;
};
int main()
{
CoInitialize(NULL);
{
CComPtr<IMruDataList2> mru;
if (SUCCEEDED(mru.CoCreateInstance(CLSID_MruLongList)))
{
const int max = 100; // get max 100 entries
mru->InitData(max, MRULISTF_USE_MEMCMP, HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU\\", nullptr);
for (auto i = 0; i < max; i++)
{
DWORD slot;
DWORD size;
// get size
if (FAILED(mru->QueryInfo(i, &slot, &size)))
continue;
// get data
// note beginning is a LPWSTR containing exe data
auto data = (LPBYTE)_alloca(size);
if (FAILED(mru->GetData(i, data, size)))
continue;
// the rest is a PIDL
auto pidl = (LPCITEMIDLIST)(data + (lstrlen((LPWSTR)data) + 1) * 2);
// get the shell item
CComPtr<IShellItem> item;
if (SUCCEEDED(SHCreateItemFromIDList(pidl, IID_PPV_ARGS(&item))))
{
// get its path
CComHeapPtr<WCHAR> path;
item->GetDisplayName(SIGDN::SIGDN_DESKTOPABSOLUTEPARSING, &path);
wprintf(L"Executable: %s LastVisited: %s\n", data, path);
}
}
}
}
CoUninitialize();
}
PS: I'm using ATL's smart classes
I finally figured out how to create an ITEMIDLIST structure, and it all works well.
Explanations:
After some test, I've concluded that this value is not necessarily updated. The application that uses a file picker needs to write to the registry to reflect changes.
For example, VS Community 2022 / VS Code updates this value, but the new Microsoft Notepad does not (not sure for the old one). Apparently, .NET applications seem to be updated automatically, though.
First, we obviously must open the key at Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedPidlMRU.
The stored data value we need is on one of the values, which has a number as a name.
The first byte of the MRUListEx value lies the last path.
HKEY hKey = NULL;
std::wstring regMRUPath = LR"(Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedPidlMRU\)";
LSTATUS statusCode = RegOpenKeyExW(HKEY_CURRENT_USER, regMRUPath.data(), 0, KEY_QUERY_VALUE, &hKey);
if (statusCode != ERROR_SUCCESS)
// Handle error
BYTE data[MAX_PATH];
DWORD bufferSize = MAX_PATH;
statusCode = RegGetValueW(hKey, L"", L"MRUListEx", RRF_RT_REG_BINARY, NULL, &data, &bufferSize);
if (statusCode != ERROR_SUCCESS)
// Handle error
std::wstring keyName = std::to_wstring(data[0]);
Now that we have the value, we can get its data.
DWORD reqBuffSize = 0;
statusCode = RegQueryValueExW(hKey, keyName.data(), NULL, NULL, NULL, &reqBuffSize);
if (statusCode != ERROR_SUCCESS)
// maybe the specified key is invalid or missing.
BYTE pathData[reqBuffSize];
statusCode = RegGetValueW(hKey, L"", keyName.data(), RRF_RT_REG_BINARY, NULL, &pathData, &reqBuffSize);
if (statusCode != ERROR_SUCCESS)
// maybe the specified key is invalid or missing.
We have another problem: The path is not directly accessible. The executable name is prefixed from the real path, so we must remove it.
Actually, it's very easy. The delimiter between the executable name and the real path is \0\0\0.
const size_t offset = (lstrlenW(reinterpret_cast<LPCWSTR>(pathData)) * sizeof(wchar_t))
+ (2 * sizeof(wchar_t));
The obtained value is not human-readable, but it actually stores a PIDL, so we can get it with SHGetPathFromIDList. The ITEMIDList is not very well documented on the Microsoft's website, but here's a way to create one of these things:
IMalloc* pMalloc;
if (FAILED(SHGetMalloc(&pMalloc)))
// handle error, failed to get a pointer to the IMalloc interface.
PIDLIST_ABSOLUTE pIdl = (PIDLIST_ABSOLUTE)pMalloc->Alloc((reqBuffSize - offset) + 1);
pIdl->mkid.cb = (sizeof(USHORT) + (reqBuffSize - offset));
memcpy_s(pIdl->mkid.abID, (reqBuffSize - offset) + 1, pathData + offset, (reqBuffSize - offset) + 1);
PIDLIST_ABSOLUTE pNext = ILGetNext(pIdl);
if (!pNext)
// handle error, failed to get a pointer to the next item
pNext->mkid.cb = 0;
initialDir.reserve(MAX_PATH * 2);
The ITEMIDList structure has two members: cb and abID. cb is the size of a USHORT + the size of the data, and abID is a pointer to the data itself.
The last ITEMIDList struct must have cb set to zero to mark the end. ILGetNext gives us a pointer to the next element.
// Finally, return the path!
std::wstring retValue;
retValue.reserve(MAX_PATH);
if (FALSE == SHGetPathFromIDList(pIdl, initialDir.data())) {
// oh no! free the allocated memory and throw an exception
}
pMalloc->Free(pIdl);
It's not as hard as it seems to be at the beginning, but if you want to get this value for use with a file picker, it's recommended to use COM instead since it's easier and less error-prone. Thank tou all for tour response and have a good day!
If you want to get the path from a specified extension, see the OpenSavePidlMRU key. It works the same, but it requires some little adjustments.

wxWidgets iterate through registry entries

I am making a simple Application to collect and represent data over bluetooth serial COM port and I don't want to hard-code the COM ports. So I want to enumerate the COM ports by looking up HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM. However I'm fairly new to both wxWidgets and win32 registry terminology(I still don't understand what's supposed to be the "name" and "value" in wxWidgets documentation, they don't work as expected). What I want is to iterate through all the COMM ports and add them to a drop down list. This doesn't work:
wxRegKey regKey(wxRegKey::HKLM,"HARDWARE\\DEVICEMAP\\SERIALCOMM");
size_t subkeys;
long k = 1;
regKey.Open(wxRegKey::Read);
regKey.GetKeyInfo(&subkeys, NULL, NULL, NULL);
wxString key_name;
regKey.GetFirstValue(key_name, k);
m_drop_down->Append(key_name);
for (int i = 0; i < subkeys; i++) {
regKey.GetNextValue(key_name, k);
m_drop_down->Append(key_name);
}
regKey.Close();
It only appends one \Device\BthModem2 to the dropdown list. I would be grateful if someone cleared the terminologies up and tell me how I should go about making it work. For reference, here's what that registry entry looks to me, I want COM3, COM4, COM5, COM6 appended to the drop down list:
If you want to get the "value" (the thing in the right column), you can declare a function like this:
wxString GetStringData(const wxRegKey& regKey, const wxString& valueName)
{
wxRegKey::ValueType vtype = regKey.GetValueType(valueName);
wxString data;
if ( vtype == wxRegKey::Type_String )
{
regKey.QueryValue(valueName, data, true);
}
return data;
}
To get the complete list of them from the registry entry, you can iterate over the values in the registry entry like this:
while(regKey.GetNextValue(key_name, k)) {
wxString data = GetStringData(regKey,valueName);
if ( !data.IsEmpty() )
{
m_drop_down->Append(key_name);
}
}
GetNextValue will return false when there are no more values to be fetched breaking out of the loop.
This isn't really complete since this won't distinguish between a registry value whose type isn't string and a registy value whose type is a string but with empty data, but it should be clear how to modify the function and/or the iteration if it's necessary to make that distinction.
According to MSDN:Enumerating Registry Subkeys and RegGetValue, RegGetValue retrieves the type and data for the specified registry value.
Code:
int main()
{
long ret;
unsigned long reg_index = 0;
DWORD dwValSize = MAX_VALUE_NAME;
DWORD dwDataSize = MAX_VALUE_NAME;
LPTSTR lpValname = new TCHAR[MAX_VALUE_NAME]{};
LPTSTR lpDataname = new TCHAR[MAX_VALUE_NAME]{};
HKEY hkey;
int result = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft"), 0, KEY_READ, &hkey);
if (result == ERROR_SUCCESS) {
while ((ret = RegEnumValue(hkey, reg_index++, lpValname, &dwValSize, NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS)
{
if ((ret == ERROR_SUCCESS) || (ret == ERROR_MORE_DATA)) {
_tprintf(TEXT("(%d) %s"), reg_index, lpValname);
DWORD type = 0;
if (RegGetValue(hkey, 0,lpValname, RRF_RT_ANY, &type, lpDataname, &dwDataSize) == ERROR_SUCCESS)
{
_tprintf(TEXT("(Value data %s)\n"), lpDataname);
}
}
dwValSize = MAX_VALUE_NAME;
dwDataSize = MAX_VALUE_NAME;
ZeroMemory(lpDataname,sizeof(TCHAR)* dwDataSize);
ZeroMemory(lpValname,sizeof(TCHAR)* dwValSize);
}
RegCloseKey(hkey);
}
return TRUE;
}

Creating a file with the same name as registry

I want to create a text file with the same name as a registry.
Say, I get the variable valueName, and I want it's value to be the name of a .txt file in C:\ How can I do that?
Almost final code:
void EnumerateValues(HKEY hKey, DWORD numValues)
{
for (DWORD dwIndex = 0; dwIndex < numValues; dwIndex++)
{BOOL bErrorFlag = FALSE;
char valueName[64];
DWORD valNameLen = sizeof(valueName);
DWORD dataType;
DWORD dataSize = 0;
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, &dataType, NULL, &dataSize);
if (retval == ERROR_SUCCESS)
{//pregatesc calea
char* val = new char[strlen(valueName)];
sprintf(val, "C:\\%s.txt", valueName);
printf("S-a creat fisierul: %s\n", val);
//creez/suprascriu fisierul
HANDLE hFile;
hFile=CreateFile(val,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{ printf("Eroare la creat fisierul %s!\n",val);
}
//sciru in fisier
char str[] = "Example text testing WriteFile";
DWORD bytesWritten=0;
DWORD dwBytesToWrite = (DWORD)strlen(str);
bErrorFlag=WriteFile(hFile, str, dwBytesToWrite, &bytesWritten, NULL);
if (FALSE == bErrorFlag)
{
printf("Eroare la scriere in fisier\n");
}
//inchid fisierul
CloseHandle(hFile);
}
//eroare regenumv
else printf("\nError RegEnumValue");
}
}
The fundamental problem is that you seem to want to convert a registry key, HKEY into a path. And there's no API to do that. You will need to keep track of the path and pass it to the function in the question, along with the HKEY.
You are passing uninitialized values to RegEnumValue, specifically dataSize. Since you don't care about the data, don't ask for it. Pass NULL for the data pointer, and zero for data size.
Your call to new is not allocating enough memory. You need space for the directory name, the file extension, and the null-terminator.
These problems are exacerbated by your complete neglect for error checking. That might sound harsh, but frankly you need some shock treatment. In order to be able to fail gracefully you need to check for errors. More pressing for you, in order to be able to debug code, you need to check for errors.
You've tagged the code C++ but write as if it were C. If you really are using C++ then you can use standard containers, std::string, avoid raw memory allocation and the result leaks. Yes, you code leaks as it stands.
first of all your program is more C like than C++, but if you want to solve this in C++ you can use stringstream in the following way:
std::stringstream stream;
stream << "C:\\";
stream << valueName;
stream << ".txt";
std::string filename(stream.str());
HANDLE hFile=CreateFile(filename.c_str() ,GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_NEW , FILE_ATTRIBUTE_NORMAL,NULL);
Also you need a include:
#include <sstream>

cannot display the receive byte

I have to do serial communication in win32.
I can read no of bytes but cannot display the read data.
I have used following function to read the data
DWORD serial::ReadTest()
{
char inBuffer[BUF_SIZE];
DWORD nBytesToRead = BUF_SIZE;
DWORD dwBytesRead = 0;
ReadFile(serialHandle,
inBuffer,
nBytesToRead,
&dwBytesRead,
NULL);
MessageBox(NULL,"ReadFile completed", _T("Read"), NULL);
return dwBytesRead;
}
I have done following things that displays the number of read bytes
{
DWORD dwReturnValue;
dwReturnValue = serialObj.ReadTest();
printf( "\nRead complete. Bytes read: %d\n", dwReturnValue);
char temp[255];
sprintf(temp,_T("%X"),dwReturnValue);
//to display in the static text
HWND hWnd = GetDlgItem(hDlg, IDC_STATIC_READ); //
if ( hWnd )
{
SetWindowText(hWnd, temp);
}
}
I have to display the actual read data. I have searched and tried different options like char* but it is not working . Can someone suggest me the appropriate way of displaying the actual data. I am using hex mode for sending in other side and i should receive hex data here in this program.
First you need to change the ReadTest function, to have the buffer and buffer length as arguments:
WORD serial::ReadTest(char* inBuffer, const DWORD nBytesToRead)
{
DWORD dwBytesRead = 0;
...
}
Then you declare the buffer in the code calling the ReadTest function:
char inBuffer[BUF_SIZE];
DWORD nBytesRead = serialObj.ReadTest(inBuffer, sizeof(inBuffer));
Now the inBuffer array contains nBytesRead bytes.
for example if
inBuffer[BUF_SIZE] = {0x24, 0x21, 0x23, 0x24}
I am trying to send hex value from the other side.
then i can print these values one by one using:
for (int i=0; i<nBytesRead; i++)
{
char temp[255];
sprintf(temp,_T("%X"),inBuffer[i]);
//to display in the static text
HWND hWnd = GetDlgItem(hDlg, IDC_STATIC_READ); //
if ( hWnd )
{
SetWindowText(hWnd, temp);
}
}
here i have printed each item. how to print it as a single block.

Enumerating Registry Keys C++

I want to show all registry keys, subkeys, and values in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run to see what programs run at startup.
I'm using this code from MS.
void QueryKey(HKEY hKey)
{
TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
DWORD cbName; // size of name string
TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
DWORD cchClassName = MAX_PATH; // size of class string
DWORD cSubKeys=0; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i, retCode;
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
// Get the class name and the value count.
retCode = RegQueryInfoKey(
hKey, // key handle
achClass, // buffer for class name
&cchClassName, // size of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
// Enumerate the subkeys, until RegEnumKeyEx fails.
if (cSubKeys == 0)
{
printf("No values found\n");
}
if (cSubKeys)
{
printf( "\nNumber of subkeys: %d\n", cSubKeys);
for (i=0; i<cSubKeys; i++)
{
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKey, i,
achKey,
&cbName,
NULL,
NULL,
NULL,
&ftLastWriteTime);
if (retCode == ERROR_SUCCESS)
{
_tprintf(TEXT("(%d) %s\n"), i+1, achKey);
}
}
}
// Enumerate the key values.
if (cValues)
{
printf( "\nNumber of values: %d\n", cValues);
for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
{
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
retCode = RegEnumValue(hKey, i,
achValue,
&cchValue,
NULL,
NULL,
NULL,
NULL);
if (retCode == ERROR_SUCCESS )
{
_tprintf(TEXT("(%d) %s\n"), i+1, achValue);
}
}
}
}
int RegKeyCount = 0;
int main(int argc, char *argv[])
{
HKEY hTestKey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows \\CurrentVersion\\Run"), 0, KEY_READ, &hTestKey) == ERROR_SUCCESS)
{
QueryKey(hTestKey);
}
}
I am confused in that if I run this code for "SOFTWARE\Microsoft\Windows \CurrentVersion" it will show me all subkeys and values (I can see that Run is a subkey of CurrentVersion), however when I try to get it to show me the subkeys and values for Run it says nothing is found even though entries are there.
I should also say I do not know the names of the values of the subkeys/values, they could be anything.
Is this indeed what RegEnumValue is supposed to do or do I need to use another Registry Function?
The only problem I found was the spaces in your parameter to RegOpenKeyEx(), the program runs ok if you take out the embedded spaces so that it reads TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run").
Your printf in the beginning is a bit confusing, maybe you should change "No values found\n" to "No keys found\n"?
if (cSubKeys == 0)
printf("No keys found\n");
Also: if you build/run this code as a 32-bit program in a 64-bit OS, be aware that you will get the contents of HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run, not HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run!