Value getting changed after end of function - c++

I am trying to set data which needs to be used in another file (layer) of the application. During debugging , I see that the value gets correctly set for the first time . But when I try to use this set variable after the function , the value is changed. I think the memory is getting released causing the variable to reset . Can anyone please help me with what I am trying to do.
void SetExpectedTabsData(_In_ PCWSTR tabUrls[], _In_ PCWSTR tabTitles[], _In_ UINT tabsCount, _In_ FakeCourier* courier)
{
wchar_t jsonPerTab[256];
wchar_t tabsDataJSON[c_jsonTabDataSize];
// tabsDataJSON should be large enough to hold any data.
StringCchPrintf(tabsDataJSON, c_jsonTabDataSize, L"\"tabs\":[");
bool isActiveTab = true;
// tabId starts from 1 and the tabIndex starts with 0. Manipulated the json string generation accordingly.
for (unsigned int i = 1; i <= tabsCount; ++i)
{
StringCchPrintf(jsonPerTab, ARRAYSIZE(jsonPerTab), L"{\"id\":%i,\"index\":%i,\"windowId\":1,\"active\":%s,\"status\":\"complete\",\"title\":\"%s\",\"url\":\"%s\"}", i, (i - 1), isActiveTab ? L"true" : L"false", tabTitles[i - 1], tabUrls[i - 1]);
StringCchCat(tabsDataJSON, c_jsonTabDataSize, jsonPerTab);
isActiveTab = false;
if (i != tabsCount)
{
StringCchCat(tabsDataJSON, c_jsonTabDataSize, L",");
}
}
StringCchCat(tabsDataJSON, c_jsonTabDataSize, L"],");
VERIFY_SUCCEEDED(courier->SetExpectedTabsData(tabsDataJSON));
}
The courier file where the data needs to be set is as
HRESULT FakeCourier::SetExpectedTabsData(_In_ wchar_t* tabsData)
{
m_tabsData = tabsData;
return S_OK;
}
Please suggest the correct approach to do this.

The variable tabsDataJSON is local in the function SetExpectedTabsData, so it can be overwritten after finishing of this function. And since it can happen, it happens.
When you call FakeCourier::SetExpectedTabsData(tabsDataJSON), this function just remembers pointer to that local variable tabsDataJSON. But right after finishing of the function SetExpectedTabsData this pointer becomes invalid.
To fix it you need to modify the function FakeCourier::SetExpectedTabsData: replace copying of the pointer be copying of the pointed data. Since your m_tabsData is a wchar_t*, just allocate this string and copy the data from tabsData into m_tabsData (read about wcsncpy and similar functions).
Try something like this:
HRESULT FakeCourier::SetExpectedTabsData(_In_ wchar_t* tabsData)
{
const size_t len = wcslen(tabsData);
if (m_tabsData)
delete m_tabsData;
m_tabsData = new wchar_t[len + 1];
wcsncpy(m_tabsData, tabsData, len + 1);
return S_OK;
}
And also you need to free this memory in the destructor of the FakeCourier (to avoid memory leak). And to initialize m_tabsData in the constructor (m_tabsData = 0;)

Related

How to directly access to what's in VARIANT variables in C++?

My program uses an external ocx library and receives data through it. The code below shows how it works.
VARIANT varArrItem, varArrData;
ocx_instance.GetItemArr(real, &varArrItem); // the library provides GetItemArr
// 1) receives data
long lLBound, lUBound;
VARIANT varItem, varData;
long index[2];
index[0] = 0;
index[1] = 0;
COleSafeArray* pSafeItemArr = (COleSafeArray*)&varArrItem; // 2) casts varArrItem to COleSafeArray
CString strItem;
CStringArray arrItem;
pSafeItemArr->GetLBound(1, &lLBound);
pSafeItemArr->GetUBound(1, &lUBound);
int nItemCnt = (lUBound - lLBound + 1);
for (int i = 0; i < nItemCnt; i++)
{
index[0] = i;
VariantInit(&varItem);
pSafeItemArr->GetElement(index, (void *)&varItem); // 3) gets its values using GetElement
strItem = varItem.bstrVal;
arrItem.Add(strItem);
VariantClear(&varItem);
}
A big problem of the program is that this code is run whenever new data arrives, which is quite often, and it consumes a lot of resources. So, I'd like to simplify the code and get just contents of varArrItem, as strings or an array of structs of strings, for example.
varArrItem.vt gives me 8204 and it's said that it consists of 8192(VT_ARRAY) and 12(VT_VARIANT). I'm stuck here and don't know what to do after this. How can I simply get what's in them? Is it possible to access to them without using COleSafeArray?
You don't NEED to use COleSafeArray, it is just a wrapper for convenience. You could just extract the SAFEARRAY* pointer directly from varArrItem and then use the SafeArray APIs directly: SafeArrayGet(L|U)Bound(), SafeArrayGetElement(), etc, though if performance is important then consider using SafeArrayAccessData() to access the VARIANT[] array directly, and thus its BSTR pointers. The less copying of data you do, the faster the code will run. The only copy of data this code actually needs to make is the assignment of the initial VARIANT and each CString you add to the CStringArray:
VARIANT varArray;
ocx_instance.GetItemArr(real, &varArray);
LPSAFEARRAY psa = varArrar.parray;
LONG lLBound, lUBound;
SafeArrayGetLBound(psa, 1, &lLBound);
SafeArrayGetUBound(psa, 1, &lUBound);
CStringArray arrItem;
VARIANT *varArrayData;
if (SUCCEEDED(SafeArrayAccessData(psa, (void**) &varArrayData)))
{
int nItemCnt = (lUBound - lLBound + 1);
for (int i = 0; i < nItemCnt; i++)
{
CString strItem = varArrayData[i].bstrVal;
arrItem.Add(strItem);
}
SafeArrayUnaccessData(psa);
}

Allocate multiple structs in memory

i need pass multiple values to memory, i need make various country to CEN/XFS.
This api: CashDispenser - CDM
Struct reference: WFSCDMCURRENCYEXP
How am i trying to do:
HRESULT WINAPI WFPGetInfo(HSERVICE hService, DWORD dwCategory, LPVOID lpQueryDetails, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID) {
WFSRESULT * lpWFSResult;
WFSCDMSTATUS CdmStatus;
WFSCDMCAPS CdmCapabilities;
WFSCDMCASHUNIT CdmCash;
WFSCDMCURRENCYEXP CdmCurrency;
HRESULT result;
result = WFMAllocateBuffer(sizeof(WFSRESULT), WFS_MEM_ZEROINIT | WFS_MEM_SHARE, (void**)&lpWFSResult);
if(result != WFS_SUCCESS){
return WFS_ERR_INTERNAL_ERROR;
}
if(dwCategory == WFS_INF_CDM_CURRENCY_EXP){
const int countCurrencies = 2;
WFSCDMCURRENCYEXP** ppCdmCurrencies;
result = WFMAllocateMore(sizeof(WFSCDMCURRENCYEXP*) * (countCurrencies+1), lpWFSResult, (void**)&ppCdmCurrencies);
lpWFSResult->hService=hService;
lpWFSResult->RequestID=ReqID;
lpWFSResult->u.dwEventID=WFS_INF_CDM_CURRENCY_EXP;
lpWFSResult->hResult=WFS_SUCCESS;
result = WFMAllocateMore(sizeof(WFSCDMCURRENCYEXP), lpWFSResult, (void**)&ppCdmCurrencies[0]);
WFSCDMCURRENCYEXP& cmdCurrency0(*ppCdmCurrencies[0]);
memcpy(cmdCurrency0.cCurrencyID, "AED", 3);
cmdCurrency0.sExponent = 0;
WFSCDMCURRENCYEXP& cmdCurrency1(*ppCdmCurrencies[1]);
memcpy(cmdCurrency1.cCurrencyID, "AFA", 3);
cmdCurrency1.sExponent = 0;
lpWFSResult->lpBuffer = ppCdmCurrencies;
logFile.close();
}
}
Your code looks very C-ish.
An idiomatic way to do this in c++ would be:
struct WFSCDMCURRENCYEXP
{
std::string cCurrencyID;
SHORT sExponent;
};
std::vector<WFSCDMCURRENCYEXP> CdmCurrencies {
{ "ARG", 3 } ,
{ "EUA", 3 } ,
// lots more countries
};
Update:
I just noticed you apparently interact with a c-style API, and using that struct might be required in its original form.
Though in c++ you still can use a std::vector to manage a dynamically allocated, contiguous array of that struct:
typedef struct _wfs_cdm_currency_exp
{
CHAR cCurrencyID[3];
SHORT sExponent;
} WFSCDMCURRENCYEXP, * LPWFSCDMCURRENCYEXP;
std::vector<WFSCDMCURRENCYEXP> CdmCurrencies {
{ { 'A', 'R', 'G' }, 3 } , // Note that the cCurrencyID is a non null terminated
// array here
{ { 'E', 'U', 'A' }, 3 } ,
// lots more countries
};
LPWFSCDMCURRENCYEXP pCdmCurrencies = &CdmCurrencies[0];
Declare an array:
WFSCDMCURRENCYEXP CdmCurrency[2];
memcpy( CdmCurrency[0].cCurrencyID, "ARG", 3);
CdmCurrency[0].sExponent = 0;
memcpy( CdmCurrency[1].cCurrencyID, "EUA", 3);
CdmCurrency[1].sExponent = 0;
memcpy(lpWFSResult->lpBuffer, CdmCurrency, 2*sizeof(WFSCDMCURRENCYEXP));
// ^^
Don't forget you will need to copy more memory.
Also note I have fixed the setting of .cCurrencyID - a character literal (with single quotes) can only contain a single character. To move multiple characters, you will need to call memcpy from a string. Normally I would suggest using std::string rather than char [3], but you can't use memcpy if you do, and it probably wouldn't be a good idea to pass a std::string across a DLL boundary.
I think you try to handle WFS_INF_CDM_CURRENCY_EXP message to get information about currencies in your CDM.
Read XFS specification carefully:
Output Param LPWFSCDMCURRENCYEXP *lppCurrencyExp; Pointer to a NULL-terminated array of pointers to WFSCDMCURRENCYEXP structures
This means that you must allocate an array of pointers to WFSCDMCURRENCYEXP with size N+1 and set last item to null.
In CEN/XFS you cannot use standard new or malloc for memory allocation.
You need to use WFMAllocateBuffer and WFMAllocateMore to allocate memory for XFS structures that you return to caller.
For you task yo need something like this:
HRESULT WINAPI WFPGetInfo(HSERVICE hService, DWORD dwCategory, LPVOID lpQueryDetails, DWORD dwTimeOut, HWND hWnd, REQUESTID ReqID) {
WFSRESULT * lpWFSResult;
WFSCDMSTATUS CdmStatus;
WFSCDMCAPS CdmCapabilities;
WFSCDMCASHUNIT CdmCash;
WFSCDMCURRENCYEXP CdmCurrency;
HRESULT result;
result = WFMAllocateBuffer(sizeof(WFSRESULT), WFS_MEM_ZEROINIT | WFS_MEM_SHARE, (void**)&lpWFSResult);
if(result != WFS_SUCCESS){
return WFS_ERR_INTERNAL_ERROR;
}
if(dwCategory == WFS_INF_CDM_CURRENCY_EXP){
const int countCurrencies = 2;
WFSCDMCURRENCYEXP** ppCdmCurrencies;
result = WFMAllocateBuffer(sizeof(WFSCDMCURRENCYEXP*) * (countCurrencies+1), WFS_MEM_ZEROINIT | WFS_MEM_SHARE, (void**)&ppCdmCurrencies);
lpWFSResult->hService=hService;
lpWFSResult->RequestID=ReqID;
lpWFSResult->u.dwEventID=WFS_INF_CDM_CURRENCY_EXP;
lpWFSResult->hResult=WFS_SUCCESS;
result = WFMAllocateMore(sizeof(WFSCDMCURRENCYEXP), lpWFSResult, (void**)&ppCdmCurrencies[0]);
WFSCDMCURRENCYEXP& cmdCurrency0(*ppCdmCurrencies[0]);
memcpy(cmdCurrency0.cCurrencyID, "AED", 3);
cmdCurrency0.sExponent = 0;
result = WFMAllocateMore(sizeof(WFSCDMCURRENCYEXP), lpWFSResult, (void**)&ppCdmCurrencies[1]);
WFSCDMCURRENCYEXP& cmdCurrency1(*ppCdmCurrencies[1]);
memcpy(cmdCurrency1.cCurrencyID, "AFA", 3);
cmdCurrency1.sExponent = 0;
lpWFSResult->lpBuffer = ppCdmCurrencies;
logFile.close();
return WFS_SUCCESS;
}
}
That's not so simple to manipulate with XFS. It's too many complex API structures with different rules of allocation and data representation. Please read carefully XFS manuals. In the first book ftp://ftp.cen.eu/CWA/CEN/WS-XFS/CWA16926/CWA%2016926-1.pdf many conceptual things is described. About configuration, memory mangement and so on.
You can call malloc to allocate multiple structs, if they are what is called POD - plain old data - or structures with no destructors, member functions, or member classes with these characteristics.
The only reason for doing that is to be compatible with C, however, or for writing very low level code.
As a general rule, you want to create an std::vector. The vector handles all the memory for you, and you can push_back as many members as you require. Use reserve (or resize) if efficiency is important. There's also a member called data() which is there for C compatibility (however C can't call your vector, at least not easily).
your code keeps throwing WFS_ERR_INTERNAL_ERROR because you havent got a fully functional XFS environment setup, setup a proper configuration, or emulate one (registry keys, sdk, dlls, etc) and then test it again, make sure your code includes the proper headers and make sure you are linking to msxfs.lib, xfs_conf.lib and xfs_supp.lib

C++ - CORBA::LongSeq to long*

I'm new to C++ (I usually work on Java), and I'm trying to convert a ::CORBA::LongSeq object to a long * in C++, in order to perform operations on it afterwards.
So basically, what I tried is to do that :
long * Sample (const ::CORBA::LongSeq& lKeys) {
long nbElts = lKeys.length();
long * lCles = NULL;
for(int iIndex = 0; iIndex < nbElts; iIndex++) {
lCles[iIndex] = (long) lFCKey[iIndex];
}
return lCles;
}
And what happens is that I can retrieve the length of lKeys (so it should be looking at the right location, as far as I can tell), but then I get an access violation exception when I enter inside the for loop.
0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF
I'm not sure of what I'm doing wrong though... Anyone has an idea ?
Here is one solution, and you don't get into the mess with pointers:
#include <vector>
std::vector<long> Sample (const ::CORBA::LongSeq& lKeys)
{
long nbElts = lKeys.length();
std::vector<long> lCles(nbElts);
for(int iIndex = 0; iIndex < nbElts; ++iIndex)
lCles[iIndex] = (long) lFCKey[iIndex];
return lCles;
}
This is guaranteed to work correctly, if the number of elements is correct.
Since you say you know Java, then a std::vector<long> would be the equivalent to a few of the Java containers that store sequences of values. For example, you can get the return value and call the vector's data() function to get you a long * that points to the vector's internal buffer.
But overall, get out of the pointer business (or try to limit their usage).
Edit: The comment stated to use CORBA::Long. So here it is:
std::vector<CORBA::Long> Sample (const ::CORBA::LongSeq& lKeys)
{
long nbElts = lKeys.length();
std::vector<CORBA::Long> lCles(nbElts);
for(int iIndex = 0; iIndex < nbElts; ++iIndex)
lCles[iIndex] = lFCKey[iIndex];
return lCles;
}
The difference between Java and C++ is that you have to manage your memory yourself (in most cases).
The error you get is that you try to assign things to an uninitialized variable (lCles), and returning a local variable. The local variable lCles which is stored on the stack will be "destroyed" once you leave the method.
One suggestion of how to do this could be something like this:
long* lCles = new long[lKeys.length()];
for(int iIndex = 0; iIndex < nbElts; iIndex++) {
lCles[iIndex] = (long) lFCKey[iIndex];
}
return lCles;
The important part in the method calling this code is to then release the memory held by this lCles by doing a
delete [] lCles; // or whatever the name of the variable is.
when done.
Like this:
long * l = Sample(lkeys);
// Do your stuff here
delete [] l;
(Using std::vector as suggested in another answer is actually preferred, since you don't have to do memory management by yourself.)
There are two things wrong here.
1) You attempt to use lCles before you have initialised it:
long * lCles = NULL;
..
lCles[iIndex]
This causes the access violation inside the for loop.
2) You return a pointer, lCles which is only declared locally:
return lCles;
This means that it goes out of scope when the function exits, and it then becomes invalid.

Asisgn LPCWSTR array from std::wstring

I am creating a dynamic array of LPCWSTR, and want to assign values at run time.
I have following code :
cin>>count
LPCWSTR * lpwcstrArray = new LPCWSTR[count]();
for (int i = 0; i < count; i++)
{
// some logic to create different wstring on each iteration
wstring tempWString = L"somerandomstuff";
lpwcstrArray[i] = reinterpret_cast<LPSWSTR>tempWString.c_str();
}
Now if i access lpwcstrArray - all the indexs point at data of last string that was assigned.
I know this is not correct way to assign values, but i do not know the correct way.
wstring tempWString is created and destroyed with each iteration of the loop.
You have dangling pointers in your lpwcstrArray and are experiencing undefined behaviour when you access one of them.
You need to allocate the space yourself or use a std::wstring as the array type instead of a LPCWSTR.
You are storing pointers that point at the internals of temporary std::wstring objects. When those objects are destroyed on each loop iteration, your array is left with danging pointers. You need to dynamically allocate the individual strings instead, eg:
std::cin >> count
LPWSTR *lpwstrArray = new LPWSTR[count];
for (int i = 0; i < count; i++)
{
// some logic to create different wstring on each iteration
std::wstring tempWString = L"somerandomstuff";
LPWSTR str = new WCHAR[tempWString.length()+1];
const wchar_t *p = tempWString.c_str();
std::copy(p, p+tempWString.length(), str);
lpwstrArray[i] = str;
}
// use lpwstrArray as needed...
// don't forget to free the memory when you are done using it...
for (int i = 0; i < count; i++)
delete[] lpwstrArray[i];
delete[] lpwstrArray;
Depending on what you are really trying to accomplish, something more like the following would be safer, at least if you just need read-only access to the strings (which you likely do, as the C in LPCWSTR stands for const, so the user of the array is not going to be modifying them):
std::cin >> count
std::vector<std::wstring> wstrArray(count);
for (int i = 0; i < count; i++)
{
// some logic to create different wstring on each iteration
wstrArray[i] = L"somerandomstuff";
}
std::vector<LPWSTR> lpwstrArray(count);
for (int i = 0; i < count; i++)
lpwstrArray[i] = const_cast<wchar_t*>(wstrArray[i].c_str());
// use lpwstrArray as needed. if you need to pass it where an
// LPWSTR* is expected, you can use &lpwstrArray[0] for that...
// lpwstrArray and wstrArray will be freed automatically
// when they go out of scope...
Try the approach
std::wstring ws(_T("Hello"));
LPCTSTR lps= (LPCTSTR)(ws.c_str());
TRACE(lps);
Notes:
You should not use the W types directly (ex: LPCWSTR). Use the T types instead (ex: LPCTSTR). Why? Because they will automatically translate to the version they should be (LPCSTR for non-Unicode / ASCII; LPCWSTR for Unicode), depending on your project.
For the same reason you should surround your strings with _T() or precede them with an L.
Try to dive deep using "Go To Definition" successively beginning on LPCTSTR
See also the _tcscpy_s function documentation

Passing pointer array as void pointer to new thread in c++

I am currently working on a project where I have to build a shell for a C++ dll, so a new C# GUI can use its functions.
However I got the following problem, in the C++ portion I have to create a new thread for specific reasons, and I want to pass an int array to the new thread.
Note that the values assigned to the array in the function in which this happens are gained from the C# portion of the code.
__declspec( dllexport ) void CreateReportPane(int &id, int &what)
{
DWORD threadId;
int iArray[2] = { id, what};
HANDLE hThread = CreateThread( NULL, 0, CreateReportPaneThread, iArray, 0, &threadId);
if (hThread == NULL)
{
ExitProcess(3);
}
}
The problem arises in the new thread, I can reliably fetch the first value out of the array, but the 2nd value seems to be released, here is the code on the other side.
DWORD WINAPI CreateReportPaneThread(LPVOID lparam)
{
int id, what;
id = *(( int * )lparam);
what = *(((int *)lparam)+1) ;
CreateReportPaneOriginal(id, what);
return 0;
}
Is there any way to prevent the values in the array from getting released while not holding the original thread captive?
A big thank you in advance
int iArray[2] = { id, what};
HANDLE hThread = CreateThread(...,CreateReportPaneThread, iArray, ...);
The problem is that iArray is a local array which means this gets destroyed when the function CreateReportPane() returns. So what CreateReportPaneThread() refers to doesn't exist. You get the first value just by chance. There is no such guarantee that you would get even the first value.
Use dynamic array:
int * iArray = new int[2];
iArray[0] = id;
iArray[1] = what;
HANDLE hThread = CreateThread(...,CreateReportPaneThread, iArray, ...);
Remember to write deallocate the array once you're done with it in CreateReportPaneThread:
DWORD WINAPI CreateReportPaneThread(PVOID *data)
{
int *array = static_cast<int*>(data);
int id = array[0], what = array[1];
delete []array; //MUST DO IT to avoid memory leak!
//rest of your code
}
Dynamically allocate the array to prevent the array going out of scope when CreateReportPane() exits:
int* iArray = new int[2];
iArray[0] = id;
iArray[1] = what;
otherwise the thread is accessing an array that is no longer valid, which is undefined behaviour. The thread routine CreateReportPaneThread() must then delete[] the array when it is no longer required (note the use of delete[] and not delete).