< BACK  NEXT > |
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.
< BACK  NEXT > |