Key value not being retrieved using CRegKey::QueryStringValue - mfc

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.

Related

Put multiple values in a single attribute of a struct

I need put multiple values ​​in a single attribute of a struct, the attribute that will receive the values ​​is LPSTR, I was trying to pass all this as a vector, compile, but it does not work as I would like.
My struct:
typedef struct _wfs_pin_caps
{
WORD wClass;
WORD fwType;
............More...............
BOOL bIDConnect;
WORD fwIDKey;
WORD fwValidationAlgorithms;
WORD fwKeyCheckModes;
LPSTR lpszExtra; //This attribute must receive more than one value
} WFSPINCAPS, * LPWFSPINCAPS;
As I'm trying to do:
HRESULT WINAPI WFPGetInfo(HSERVICE hService, DWORD dwCategory, LPVOID lpQueryDetails, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID) {
...
result = WFMAllocateMore(sizeof(WFSPINCAPS), lpWFSResult, &lpWFSResult->lpBuffer);
...
//This Values
vector<LPSTR> Tokens;
Tokens[1] = (LPSTR)"Value1";
Tokens[2] = (LPSTR)"Value2";
Tokens[3] = (LPSTR)"Value4";
Tokens[4] = (LPSTR)"Value5";
PinCapabilities.lpszExtra = (LPSTR)&Tokens; //Pass HERE
memcpy(lpWFSResult->lpBuffer,&PinCapabilities,sizeof(WFSPINCAPS));
...
return WFS_SUCCESS;
Your question is very unclear, but if I understand it, the problem is that you are setting lpszExtra to a local vector Tokens (stored in the stack) and that will be destroyed at the end of that function.
One way would be creating the vector in the heap like this:
// Create a new vector in the heap of 5 elements (0..4)
vector<LPSTR> &Tokens = *new vector<LPSTR>(5);
Tokens[1] = (LPSTR) "Value1";
Tokens[2] = (LPSTR) "Value2";
Tokens[3] = (LPSTR) "Value4";
Tokens[4] = (LPSTR) "Value5";
PinCapabilities.lpszExtra = (LPSTR) &Tokens; //Pass HERE
// Assuming that lpBuffer has room for a WFSPINCAPS structure
memcpy(lpWFSResult->lpBuffer, &PinCapabilities, sizeof(WFSPINCAPS));
Now the ((LPWFSPINCAPS)lpWFSResult->lpBuffer)->lpszExtra contains a valid pointer to a vector that can be used in any other function like this:
LPWFSPINCAPS pPinCapabilities = (LPWFSPINCAPS) lpWFSResult->lpBuffer;
vector<LPSTR> &Tokens = *(vector<LPSTR> *) pPinCapabilities->lpszExtra;
LPSTR str = Tokens[3]; // Will get "Value4"
But don't forget that in some point you will have to release the vector's memory:
LPWFSPINCAPS pPinCapabilities2 = (LPWFSPINCAPS) lpWFSResult->lpBuffer;
delete (vector<LPSTR> *) pPinCapabilities2->lpszExtra;
And please next time try to create a Minimal, Complete, and Verifiable example to help us to help you.

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);

If Registry Key Does Not Exist

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.

WIA 2.0 - IWiaDevMgr2::GetImgDlg() - How to declare/init the ppbstrFilePaths parameter

I'm trying to implement some WIA 2.0 code in my VS2012 C++ library and have run into a problem with the IWiaDevMgr2::GetImageDlg call, specifically the ppbstrFilePaths paraneter. I'm not quite sure how to declare/initialize it.
From the documentation at http://msdn.microsoft.com/en-us/library/windows/desktop/aa359932(v=vs.85).aspx:
ppbstrFilePaths [in] TYPE - BSTR**
The address of a pointer to an array of paths for the scanned files. Initialize the pointer to point to an array of size zero (0) before IWiaDevMgr2::GetImageDlg is called. See Remarks.
I've tried all sorts of variations on declaring this with no success, for example:
// No scanner selection dialog, hr = E_OUTOFMEMORY
BSTR *files = new BSTR[0];
HRESULT hr = _pWiaDevMgr->GetImageDlg(0, NULL, *_parentHwnd, path, fileTemplate, numFiles, &files, &_pWiaItemRoot);
I've also tried things similar to this:
// No scanner selection dialog, hr = E_OUTOFMEMORY
BSTR **files = (BSTR**)CoTaskMemAlloc(0);
*files = new BSTR[0];
HRESULT hr = _pWiaDevMgr->GetImageDlg(0, NULL, *_parentHwnd, path, fileTemplate, &numFiles, files, &_pWiaItemRoot);
Can anyone point me in the right direction for declaring and initializing this BSTR**? I'm not a big C++ dev and pretty much guessing at this point.
Turns out I was on the right track with my first try:
CComBSTR path("D:\\TestWiaScan");
CComBSTR fileTemplate("FileName");
LONG numFiles = 0L;
BSTR *files = new BSTR[0];
HRESULT hr1 = _pWiaDevMgr->GetImageDlg(0, NULL, _parentHwnd, path, fileTemplate, &numFiles, &files, &_pWiaItemRoot);
if (files)
{
for(int i=0;i < numFiles;i++)
{
SysFreeString(files[i]);
}
}
CoTaskMemFree(files);
if (_pWiaItemRoot)
{
_pWiaItemRoot->Release();
_pWiaItemRoot = NULL;
}
The reason my first try wasn't working was because of issues with the BSTR parameters I was passing in. Using CComBSTR or SysAllocString resolved that.

char* value gets corrupted during assignment

I have the following code , which gets a return value from a function as char*
cDestDrive = ReadFromRegistry(HKEY_CURRENT_USER,NDSPATH,szDestPathRoot);
I am able to read the value inside cDestDrive till the time I am assigning it. The moment I am assigning it:
CString strServerAddress = cDestDrive;
the value of cDestDrive gets changed (corrupted) and I am not able to get the value in CString strServerAddres any Idea why this is happening.
Edit:
Code to Read from Registry
char* CNDSShellExtender::ReadFromRegistry(HKEY hKey,LPCTSTR lpNDS,LPSTR lpRegKey)
{
HKEY hRegKey=NULL;
if(hKey==NULL || lpNDS==""||lpNDS==NULL||lpRegKey==""||lpRegKey==NULL)
MessageBox(NULL,"Reading from Registry Failed!Invalid Path",
_T("Network Drive Solution"),
MB_ICONERROR);
LONG lOpenRes=RegOpenKey(hKey,lpNDS,&hRegKey);
if (lOpenRes!=ERROR_SUCCESS ||lpNDS==NULL)
MessageBox ( NULL, "Can not Find Any Server to Connect",
_T("NDSShellExtension"),
MB_ICONERROR );
if(lOpenRes==ERROR_SUCCESS && lpNDS!=NULL)
{
TCHAR tSZValue[MAX_PATH] = {0};
DWORD dwBufSize=MAX_PATH;
LONG lCloseOut;
LPBYTE lpStorage = reinterpret_cast<LPBYTE>(tSZValue);
char* cpRegKeyVal=tSZValue;
if (ERROR_SUCCESS == RegQueryValueEx(hRegKey,lpRegKey , 0, 0, (BYTE*)tSZValue, &dwBufSize))
{
lCloseOut= RegCloseKey(hRegKey);
if (lCloseOut != ERROR_SUCCESS)
MessageBox (NULL, "Registry Not Closed",
_T("NDSShellExtension"),
MB_ICONERROR );
return cpRegKeyVal;
}
else
{
lCloseOut= RegCloseKey(hRegKey);
if (lCloseOut != ERROR_SUCCESS)
MessageBox (NULL, "Registry Not Closed",
_T("NDSShellExtension"),
MB_ICONERROR );
return "";
}
}
return "";
}
I believe you are returning a char* pointing to a an array that is allocated on the stack, i.e. this line:
TCHAR tSZValue[MAX_PATH] = {0};
followed by:
char* cpRegKeyVal=tSZValue;
This is dangerous, and you are experiencing first hand the end result!
EDIT: why don't you directly assign to a CString in the function and return that?
The function returns a pointer to tSZValue which is a local variable, so ceases to exist when it goes out of scope.
You are returning a pointer to tSZValue, which is a temp variable and will be overwritten sometime after the function exits.
The simplest solution: have ReadFromRegistry() return a CString instead of a char *.
It looks like ReadFromRegistry doesn't allocate memory to return the value (or it does, but it's on the stack and is destroyed before the function returns).
Instead of returning a char *, maybe you could pass in a reference to a char * as a parameter, and allocate your memory outside of ReadFromRegistry.