?
Solved

Problems with VT_BYREF and VARIANTS

Posted on 2007-08-08
9
Medium Priority
?
1,118 Views
Last Modified: 2013-11-25
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(SAFEARRAY** repeatData)
{
      ITypeLib* pTypelib = NULL;
      ITypeInfo *pTypeInfo;
      HRESULT hr = LoadTypeLib(L".\\DllData.tlb", &pTypelib);
      pTypelib->GetTypeInfoOfGuid(ID_MYBSTRSTRUCT, &pTypeInfo);
      IRecordInfo* pRecInfo = NULL;
      ::GetRecordInfoFromTypeInfo(pTypeInfo, &pRecInfo);

       //Allocate memory for the safe data
      *repeatData = ::SafeArrayCreateEx(VT_RECORD, 1, &bound, pRecInfo);

      BstrStruct *pBstrR = NULL;
      SafeArrayAccessData(*repeatData, (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(*repeatData);
}

The code works fine but when I change the lines with the following:

            pBstrR[i].name.vt = VT_ARRAY|VT_RECORD|VT_BYREF;
            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!

0
Comment
Question by:riteshtonk
  • 6
  • 3
9 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 19657656
>>Any idea on what am I doing wrong here?

In

      for(int i=0; i<1; i++)
      {
            LPSAFEARRAY lpsa;      
       
            //...

            pBstrR[i].name.vt = VT_ARRAY|VT_RECORD|VT_BYREF;
            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.
0
 

Author Comment

by:riteshtonk
ID: 19657706
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
0
 
LVL 86

Expert Comment

by:jkr
ID: 19657739
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.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:riteshtonk
ID: 19657799
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
0
 

Author Comment

by:riteshtonk
ID: 19657813
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.
0
 

Author Comment

by:riteshtonk
ID: 19657846
Here is the client code which calls the dll.

      HRESULT hr = ::CoInitialize(NULL);
      if (SUCCEEDED(hr))
      {
            ITestVariant *pTestVariant = NULL;
            HRESULT hr = ::CoCreateInstance(CLSID_TestVariant, NULL, CLSCTX_LOCAL_SERVER, IID_ITestVariant, (LPVOID*)(&pTestVariant));
            if(SUCCEEDED(hr))
            {
                  SAFEARRAY*  repeatData = NULL;

                  hr = pTestVariant->GetData(&repeatData);
                  if(SUCCEEDED(hr))
                        printf("Hello World !!!");
                  else
                        printf("Bad World !!!");
            }
      }
0
 
LVL 86

Accepted Solution

by:
jkr earned 375 total points
ID: 19657921
If you declare the vairable at global scope, you will always store the same address, which makes little sense...
0
 

Author Comment

by:riteshtonk
ID: 19657978
In this case the loop runs only once

for(int i=0; i<1; i++)

0
 

Author Comment

by:riteshtonk
ID: 19668145
The answer didnt help me directly, but I got some pointers and was able to proceed further.
Thanks for all the efforts!
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
Q&A with Course Creator, Mark Lassoff, on the importance of HTML5 in the career of a modern-day developer.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses
Course of the Month15 days, 2 hours left to enroll

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question