riteshtonk
asked on
Problems with VT_BYREF and VARIANTS
Hi,
I have a method inside a COM+ DLL which I invoke from a C++ application.
This is a stripped down version of the code.
The parameter repeatData is an out parameter which is an array of structures.
The VARIANT in the structure contains a SAFEARRAY of BSTRs.
-------------------------- ---------- --
//Just FYI. This declaration is in IDL file
typedef _BstrStruct
{
int i;
VARIANT name;
} BstrStruct;
STDMETHODIMP CTestVariant::GetData(SAFE ARRAY** repeatData)
{
ITypeLib* pTypelib = NULL;
ITypeInfo *pTypeInfo;
HRESULT hr = LoadTypeLib(L".\\DllData.t lb", &pTypelib);
pTypelib->GetTypeInfoOfGui d(ID_MYBST RSTRUCT, &pTypeInfo);
IRecordInfo* pRecInfo = NULL;
::GetRecordInfoFromTypeInf o(pTypeInf o, &pRecInfo);
//Allocate memory for the safe data
*repeatData = ::SafeArrayCreateEx(VT_REC ORD, 1, &bound, pRecInfo);
BstrStruct *pBstrR = NULL;
SafeArrayAccessData(*repea tData, (void HUGEP**)&pBstrR);
int count = 0;
for(int i=0; i<1; i++)
{
LPSAFEARRAY lpsa;
lpsa = SafeArrayCreate(VT_BSTR, 1, &bound);
pBstrR[i].i = i;
for(int j=0; j<COUNT; j++)
{
long tempL = j;
BSTR pBstrTemp = ::SysAllocString(L"Test");
lpsa->fFeatures ^= FADF_BSTR;
SafeArrayPutElement(lpsa, &tempL, &pBstrTemp);
lpsa->fFeatures |= FADF_BSTR;
}
//PROBLEM CODE
pBstrR[i].name.vt = VT_ARRAY|VT_RECORD;
pBstrR[i].name.parray = lpsa;
}
SafeArrayUnaccessData(*rep eatData);
}
The code works fine but when I change the lines with the following:
pBstrR[i].name.vt = VT_ARRAY|VT_RECORD|VT_BYRE F;
pBstrR[i].name.pparray = &lpsa;
I get the following error:
First-chance exception at 0x771399ca in DllData.exe: 0xC0000005: Access violation reading location 0x00000003.
First-chance exception at 0x7c812a5b in DllData.exe: 0x000003E6: Invalid access to memory location.
HEAP[DllData.exe]: Invalid Address specified to RtlFreeHeap( 00150000, 0012EFF8 )
Any idea on what am I doing wrong here?
Any help regarding this will be highly appreciated!
I have a method inside a COM+ DLL which I invoke from a C++ application.
This is a stripped down version of the code.
The parameter repeatData is an out parameter which is an array of structures.
The VARIANT in the structure contains a SAFEARRAY of BSTRs.
--------------------------
//Just FYI. This declaration is in IDL file
typedef _BstrStruct
{
int i;
VARIANT name;
} BstrStruct;
STDMETHODIMP CTestVariant::GetData(SAFE
{
ITypeLib* pTypelib = NULL;
ITypeInfo *pTypeInfo;
HRESULT hr = LoadTypeLib(L".\\DllData.t
pTypelib->GetTypeInfoOfGui
IRecordInfo* pRecInfo = NULL;
::GetRecordInfoFromTypeInf
//Allocate memory for the safe data
*repeatData = ::SafeArrayCreateEx(VT_REC
BstrStruct *pBstrR = NULL;
SafeArrayAccessData(*repea
int count = 0;
for(int i=0; i<1; i++)
{
LPSAFEARRAY lpsa;
lpsa = SafeArrayCreate(VT_BSTR, 1, &bound);
pBstrR[i].i = i;
for(int j=0; j<COUNT; j++)
{
long tempL = j;
BSTR pBstrTemp = ::SysAllocString(L"Test");
lpsa->fFeatures ^= FADF_BSTR;
SafeArrayPutElement(lpsa, &tempL, &pBstrTemp);
lpsa->fFeatures |= FADF_BSTR;
}
//PROBLEM CODE
pBstrR[i].name.vt = VT_ARRAY|VT_RECORD;
pBstrR[i].name.parray = lpsa;
}
SafeArrayUnaccessData(*rep
}
The code works fine but when I change the lines with the following:
pBstrR[i].name.vt = VT_ARRAY|VT_RECORD|VT_BYRE
pBstrR[i].name.pparray = &lpsa;
I get the following error:
First-chance exception at 0x771399ca in DllData.exe: 0xC0000005: Access violation reading location 0x00000003.
First-chance exception at 0x7c812a5b in DllData.exe: 0x000003E6: Invalid access to memory location.
HEAP[DllData.exe]: Invalid Address specified to RtlFreeHeap( 00150000, 0012EFF8 )
Any idea on what am I doing wrong here?
Any help regarding this will be highly appreciated!
ASKER
lpsa is a pointer to a SAFEARRAY which has been allocated from the Heap.
Here, since pparray is a pointer to a pointer of SAFEARRY, I am assigning the address of lpsa.
Had this been the case, even the previous solution would not have worked where I am doing
pBstrR[i].name.parray = lpsa;
Thanks,
Ritesh
Here, since pparray is a pointer to a pointer of SAFEARRY, I am assigning the address of lpsa.
Had this been the case, even the previous solution would not have worked where I am doing
pBstrR[i].name.parray = lpsa;
Thanks,
Ritesh
No. The previous version using
pBstrR[i].name.parray = lpsa;
is OK, since you are storing the allocated *content*
Using
pBstrR[i].name.parray = &lpsa;
you are storing the *address* of the allocated memory, which makes little sense, since it is local.
pBstrR[i].name.parray = lpsa;
is OK, since you are storing the allocated *content*
Using
pBstrR[i].name.parray = &lpsa;
you are storing the *address* of the allocated memory, which makes little sense, since it is local.
ASKER
I forgot to mention in my previous post that even when the 'lpsa' is in the global scope, the problem still occurs.
I basically picked up some parts of the code form here:
http://vb.mvps.org/tips/vb5dll.asp
Thanks,
Ritesh
I basically picked up some parts of the code form here:
http://vb.mvps.org/tips/vb5dll.asp
Thanks,
Ritesh
ASKER
Oops. my apologies!
The error text changes when 'lpsa' is in global scope.
HEAP[DllData.exe]: Invalid Address specified to RtlFreeHeap( 00150000, 0043AB68 )
Unhandled exception at 0x7c901230 in DllData.exe: User breakpoint.
The error text changes when 'lpsa' is in global scope.
HEAP[DllData.exe]: Invalid Address specified to RtlFreeHeap( 00150000, 0043AB68 )
Unhandled exception at 0x7c901230 in DllData.exe: User breakpoint.
ASKER
Here is the client code which calls the dll.
HRESULT hr = ::CoInitialize(NULL);
if (SUCCEEDED(hr))
{
ITestVariant *pTestVariant = NULL;
HRESULT hr = ::CoCreateInstance(CLSID_T estVariant , NULL, CLSCTX_LOCAL_SERVER, IID_ITestVariant, (LPVOID*)(&pTestVariant));
if(SUCCEEDED(hr))
{
SAFEARRAY* repeatData = NULL;
hr = pTestVariant->GetData(&rep eatData);
if(SUCCEEDED(hr))
printf("Hello World !!!");
else
printf("Bad World !!!");
}
}
HRESULT hr = ::CoInitialize(NULL);
if (SUCCEEDED(hr))
{
ITestVariant *pTestVariant = NULL;
HRESULT hr = ::CoCreateInstance(CLSID_T
if(SUCCEEDED(hr))
{
SAFEARRAY* repeatData = NULL;
hr = pTestVariant->GetData(&rep
if(SUCCEEDED(hr))
printf("Hello World !!!");
else
printf("Bad World !!!");
}
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
In this case the loop runs only once
for(int i=0; i<1; i++)
for(int i=0; i<1; i++)
ASKER
The answer didnt help me directly, but I got some pointers and was able to proceed further.
Thanks for all the efforts!
Thanks for all the efforts!
In
for(int i=0; i<1; i++)
{
LPSAFEARRAY lpsa;
//...
pBstrR[i].name.vt = VT_ARRAY|VT_RECORD|VT_BYRE
pBstrR[i].name.pparray = &lpsa;
}
'lpsa' is a local variable that goes out of scope when the loop terminates. If you now store the address of that variable - which will cease to exist after it goes out of scope - anywhere, an access violation is preassigned.