Put multiple values in a single attribute of a struct - c++

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.

Related

Invalid parameter error using GetDefaultCommConfig

I came up with the same issue,in which I got a LPTSTR portname param as input from a function.I have to convert this into wstring,so that I can fetch the Port paramaters.
below is the code snippet in which am trying to copy lptstr to wstring.
void C_PORT_MONITOR::SetPrinterComPortParam(LPTSTR PortName)
{
#ifdef _UNICODE
std::wstring l_ComPortName;
#else
std::string l_ComPortName;
#endif
DWORD dwSize,le = 0;
dwSize = sizeof(COMMCONFIG);
LPCOMMCONFIG lpCC = (LPCOMMCONFIG) new BYTE[dwSize];
l_ComPortName = PortName;//mPortName;
if(l_ComPortName.length() <= 0 )
return;
bool SetFlag = false;
//Get COMM port params called to get size of config. block
int length = l_ComPortName.length();
int iPos = l_ComPortName.find_first_of(':');
int iChc = length- iPos; //remove the charactrers after :
l_ComPortName = l_ComPortName.substr(0, (length- iChc)); //remove the characters from colon //COM1
//Get COMM port params with defined size
BOOL ret = GetDefaultCommConfig(l_ComPortName.c_str(), lpCC, &dwSize);
_RPT1(_CRT_WARN, "C_PORT_MONITOR::SetPrinterComPortParam length=%x,iPos=%x,iChc=%x,l_ComPortName=%s",length, iPos, iChc, l_ComPortName);
if(!ret)
{
le = GetLastError();
_RPT1(_CRT_WARN ,"C_PORT_MONITOR::SetPrinterComPortParam LastError=%x",le);
}
I need to assign this portname to l_comportname. and I need to create a substring from this l_comportname as COM1 and I have to use this substring in getdafaultcommconfig()
Your error is the second parameter not the first. Your debugging statement is bugged because it doesn't account for wide strings %s is for narrow strings only, you should use %S for a wide string.
Here's the real error
dwSize = sizeof(COMMCONFIG);
LPCOMMCONFIG lpCC = (LPCOMMCONFIG) new BYTE[dwSize];
lpCC->dwSize = sizeof(COMMCONFIG); // this line is needed
You might need this as well (the documentation isn't very clear)
lpCC->wVersion = 1;
It's very common in Windows programming that you have to initialize a struct with the size of the struct.
Ref: https://technet.microsoft.com/en-us/aa363188(v=vs.90)

Access Violation exception before entering into a function

I have this function which simply encrypts a string (this function works fine, and tested).
DWORD SomeObj::Encrypt(string * To_Enc) {
DWORD text_len = (To_Enc->length());
if (!CryptEncrypt(this->hKey,
NULL, // hHash = no hash
1, // Final
0, // dwFlags
(PBYTE)(*To_Enc).c_str(), //*pbData
&text_len, //*pdwDataLen
128)) { //dwBufLen
return SERVER_ERROR;
}
return SERVER_SUCCESS;
}
And I have this piece of code:
string s= "stringTest";
Encrypt(&s);
which simply call the function passing the pointer of a string.
The program is causing an access violation exception right when it calls the function Encrypt(&s), I guess that it's something about the parameter &s being passed but I can't figure this out. Any idea from your experience ?
This answer will reiterate important points already made in the comments, with example code.
Your current code:
DWORD SomeObj::Encrypt(string * To_Enc) {
DWORD text_len = (To_Enc->length());
if (!CryptEncrypt(this->hKey,
NULL, // hHash = no hash
1, // Final
0, // dwFlags
(PBYTE)(*To_Enc).c_str(), //*pbData
&text_len, //*pdwDataLen
128)) { //dwBufLen
return SERVER_ERROR;
}
return SERVER_SUCCESS;
}
On the line:
(PBYTE)(*To_Enc).c_str(), //*pbData
Note that you are casting away const-ness from the pointer value returned from the c_str() method call.
This should immediately be a red flag; there may be times when casting away const-ness is a valid use case, but it is more the exception than the rule.
Untested, but using a temporary, mutable buffer should solve your problem, such as:
#include <cstddef>
#include <vector>
...
DWORD SomeObj::Encrypt(string * To_Enc) {
std::vector<std::string::value_type> vecBuffer(To_Enc->length() * 3, 0); // use the maximum value that could be output, possibly some multiple of the length of 'To_Enc'
std::size_t nIndex = 0;
for (auto it = To_Enc->cbegin(); it != To_End->cend(); ++it)
{
vecBuffer[nIndex++] = *it;
}
DWORD text_len = (To_Enc->length());
if (!CryptEncrypt(this->hKey,
NULL, // hHash = no hash
1, // Final
0, // dwFlags
reinterpret_cast<PBYTE>(&vecBuffer[0]), //*pbData
&text_len, //*pdwDataLen
vecBuffer.size())) { //dwBufLen
return SERVER_ERROR;
}
To_Enc->assign(&vecBuffer[0], text_len); // assumes 'text_len' is returned with the new length of the buffer
return SERVER_SUCCESS;
}

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

Display tooltips on controls on a PropertyPage. Crashes when returning TRUE to ON_NOTIFY_EX( TTN_NEEDTEXT...)

I have a class
class CCfgUserPage : public CPropertyPage
Which also owns various controls, from check boxes to text areas. I would like to add tooltips to each control, and seem to be having issues.
In CCfgUserPage I added this to the message map
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipText )
Which when this object catches that message it calls the function OnToolTipText which looks like this
BOOL CCfgUserPage::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID = pNMHDR->idFrom;
CString ttStr;
int partOrient = GetDlgItem(IDC_PARTORIENT_CHECK)->GetDlgCtrlID();
if (pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if( nID == partOrient ) // Only Display TT for The buttons with these ID's
{
if( nID == partOrient )
ttStr = "Part Orient";
pTTT->lpszText = (LPTSTR)(LPCTSTR)ttStr;
pTTT->hinst = AfxGetResourceHandle();
return TRUE;
}
}
return FALSE;
}
I also enabled tool tips in
CCfgUserPage::OnInitDialog
Whenever OnToolTipText returns TRUE the application crashes and informs me of
Access violation reading location
I am trying to go through the stack frame but it is to far into MFC for me to understand what is going wrong. What might I be missing that would cause this to happen?
Have a look at the hint you have on MSDN:
When you handle the TTN_NEEDTEXT notification message, specify the
string to be displayed in one of the following ways:
Copy the text to the buffer specified by the szText member.
Copy the address of the buffer that contains the text to the lpszText member.
Copy the identifier of a string resource to the lpszText member, and copy the handle of the instance that contains the resource to the
hinst member.
So instead of doing:
CString ttStr;
// ...
if( nID == partOrient )
ttStr = "Part Orient";
// Below is the unsafe part: you initialize lpszText with something
// expected to be valid after you return from the handler
// effectively, this is internal buffer of local ttStr valriable
// which is to be freed and lpszText would keep point to undefined
// memory
pTTT->lpszText = (LPTSTR)(LPCTSTR)ttStr;
pTTT->hinst = AfxGetResourceHandle();
You would rather:
if(nID == partOrient)
{
// NOTE: Here instead you don't create any dynamic instances (strings)
// and the value resides directly in the notification structure
_tcsncpy_s(pTTT->szText, _T("Part Orient"), _TRUNCATE);
pTTT->lpszText = pTTT->szText; // Just a safety, it's already pointing there
}
The issue is that ttStr goes out of scope at the end of the function and you are returning a pointer to it. The pointer is now invalid and the app crashes when trying to reference it.
Use the supplied buffer if the tooltip will always be small (less than 80 characters) or use a member variable to store the tooltip text.

How do you open a resource string in Visual C++ 2010?

I created a basic stringtable resource in Visual C++. I am trying to access that resource. However, my program can't seem to find the resource. Here:
int main(int argc, char* argv[])
{
HRSRC hRsrc;
hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDS_STRING102), RT_STRING);
if (hRsrc == NULL) {
printf("Not found\n");
} else {
printf("Found\n");
}
}
This program can't find the resource and always returns null.
I created a simple bitmap resource and this new program identifies that just fine. Here:
int main(int argc, char* argv[])
{
HRSRC hRsrc;
hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDB_BITMAP1), RT_BITMAP);
if (hRsrc == NULL) {
printf("Not found\n");
} else {
printf("Found\n");
}
}
This finds the bitmap.
Do stringtable resources get handled somehow differently?
Assuming you do not want to use LoadString() this should help...
Strings and string tables are indeed treated differently when using FindResource() and FindResourceEx(). From this KB article:
String resources are stored as blocks of strings. Each block can have
up to sixteen strings and represents the smallest granularity of
string resource that can be loaded/updated. Each block is identified
by an identifier (ID), starting with one (1). We use this ID when
calling the FindResource, LoadResource and UpdateResource functions.
A string with ID, nStringID, is located in the block with ID,
nBlockID, given by the following formula:
nBlockID = (nStringID / 16) + 1; // Note integer division.
The lower 4 bits of nStringID indicates which entry in the block contains the actual string. Once you have calculated the block ID to pass to FindResource() and the index in the block where the string exists you have to scan through it's contents to find the string you are looking for.
The following code should get you started.
const WCHAR *stringPtr;
WCHAR stringLen;
// Get the id of the string table block containing the target string
const DWORD blockID = (nID >> 4) + 1;
// Get the offset of teh target string in the block
const DWORD itemID = nID % 0x10;
// Find the resource
HRSRC hRes = FindResourceEx(
hInst,
RT_STRING,
MAKEINTRESOURCE(blockID),
wLanguage);
if (hRes)
{
HGLOBAL hBlock = LoadResource(hInst, hRes);
const WCHAR *tableDataBlock = reinterpret_cast<LPCWSTR>(LockResource(hBlock));
const DWORD tableBlockSize = SizeofResource(hInst, hRes);
DWORD searchOffset = 0;
DWORD stringIndex = 0;
// Search through the section for the appropriate entry.
// The first two bytes of each entry is the length of the string
// followed by the Unicode string itself. All strings entries
// are stored one after another with no padding.
while(searchOffset < tableBlockSize)
{
if (stringIndex == itemID)
{
// If the string has size. use it!
if (tableDataBlock[searchOffset] != 0x0000)
{
stringPtr = &tableDataBlock[searchOffset + 1];
stringLen = tableDataBlock[searchOffset];
}
// Nothing there -
else
{
stringPtr = NULL;
stringLen = 0;
}
// Done
break;
}
// Go to the next string in the table
searchOffset += tableDataBlock[searchOffset] + 1;
// Bump the index
stringIndex++;
}
}
You could use LoadString directly instead. Here's some text from the MSDN FindResource documentation...
An application can use FindResource to find any type of resource, but this function should be used only if the application must access the binary resource data by making subsequent calls to LoadResource and then to LockResource.
To use a resource immediately...
...use LoadString!
After 2 days of research I found this(it works!):
#include <atlstr.h>
......
ATL::CString str;
WORD LangID = MAKELANGID(LANG_ENGLISH,SUBLANG_DEFAULT);
str.LoadString(NULL,IDS_STRING101, LangID);