Page #46 (Interfaces and Marshaling)


Memory Management

We have already covered how directional attributes dictate the role of the client and the server for memory management. To recap:

  • For an [in] parameter, the memory is allocated and freed by the client.

  • For an [out] parameter, the memory is allocated by the server and freed by the client.

  • For an [in, out] parameter, the memory is allocated by the client, freed by the server, allocated once again by the server, and finally freed by the client. If possible, the two server-side operations can be combined as one reallocation action.

Memory management APIs are:

  • SysAllocString, SysReAllocString, SysFreeString, etc. for BSTRs.

  • VariantInit and VariantClear for VARIANTs.

  • CoTaskMemAlloc, CoTaskMemReAlloc, and CoTaskMemFree for raw memory.

To demonstrate the use of memory management APIs, I will define two IDL structures; the first structure contains two BSTRs and a VARIANT, and the second structure contains an array of the first structure.

 typedef struct tagMYLEADER {   BSTR bsFirstName;    BSTR bsLastName;    VARIANT vTitle;  }MYLEADER;  typedef struct tagMYLEADERS {   long lElements;    [size_is(lElements)] MYLEADER* pData;  }MYLEADERS;  // Interface method  HRESULT GetMyLeaders([out] MYLEADERS* pDataArray); 

The following code fragment shows how the memory is allocated at the server side and deallocated at the client side:

 // Server code  STDMETHODIMP CMyExplore::GetMyLeaders(MYLEADERS *pDataArray)  {   pDataArray->lElements = 2;    // raw allocation    pDataArray->pData =      (MYLEADER*) ::CoTaskMemAlloc(2 * sizeof(MYLEADER));    // BSTR allocations    pDataArray->pData[0].bsFirstName=SysAllocString(L"Mohandas");    pDataArray->pData[0].bsLastName=SysAllocString(L"Gandhi");    // BSTR allocation in VARIANT    VARIANT& v0 = pDataArray->pData[0].vTitle;    ::VariantInit(&v0);    V_VT(&v0) = VT_BSTR;    V_BSTR(&v0) = ::SysAllocString(L"Mahatma");    // BSTR allocations    pDataArray->pData[1].bsFirstName=SysAllocString(L"Winston");    pDataArray->pData[1].bsLastName=SysAllocString(L"Churchil");    // BSTR allocation in VARIANT    VARIANT& v1 = pDataArray->pData[1].vTitle;    ::VariantInit(&v1);    V_VT(&v1) = VT_BSTR;    V_BSTR(&v1) = ::SysAllocString(L"Sir");    return S_OK;  }  // Client code fragment  MYLEADERS leaders;  HRESULT hr = pMyExplore->GetMyLeaders(&leaders);  ...  // Free memory  for(i=0; i<leaders.lElements; i++) {   MYLEADER* pLeader = &leaders.pData[i];    ::VariantClear(&pLeader->vTitle);   // freed BSTR in the variant    ::SysFreeString(pLeader->bsFirstName);    // freed BSTR    ::SysFreeString(pLeader->bsLastName);     // freed BSTR  }  ::CoTaskMemFree(leaders.pData);      // freed raw allocation 

The above code fragment used raw APIs for BSTRs and VARIANTs. To make the code less susceptible to human errors, one can use wrapper classes such as CComBSTR and CComVariant provided by ATL.


COM+ Programming. A Practical Guide Using Visual C++ and ATL
COM+ Programming. A Practical Guide Using Visual C++ and ATL
ISBN: 130886742
Year: 2000
Pages: 129 © 2008-2017.
If you may any questions please contact us: