OOPortal OOPortal


COM Aggregation   «Prev 

COM Servers Track Reference counts

Recall from Basic COM course 1 that when a COM object gives away an interface pointer to a client, it increments a reference count on that pointer by calling AddRef. When the client is finished using a COM interface pointer, it calls Release on the pointer. Most implementations of Release decrement the reference counter, incremented in the AddRef call. COM servers track reference counts on all COM objects implemented within the server. In an in-process COM server, COM calls DllCanUnloadNow to check all reference counts. If they are all zero, DllCanUnloadNow returns S_OK, and COM unloads the server.

Memory Allocation Example

An object may need to pass memory between it and the client at some point in the object's lifetime-this applies to in-process as well as out-of-process servers.
When such a situation arises the object must use the task allocator as described previously. That is, the object must allocate memory whose ownership is transferred from one party to another through an interface function by using the local task allocator. CoGetMalloc provides a convenient way for objects to allocate working memory as well. For example, when the TextRender object under consideration in this document loads text from a file in the function IPersistFile::Load (that is, CTextRender::Load) it will want to make a memory copy of that text. It would use the task allocator for this purpose as illustrated in the following code (unnecessary details of opening files and reading data are omitted for simplicity):
//Implementation of IPersistFile::Load
HRESULT CTextRender::Load(char *pszFile, DWORD grfMode) {
	int       hFile;
	DWORD     cch;
	IMalloc * pIMalloc;
	HRESULT   hr;

	/*
	 * Open the file and seek to the end to set the
	 * cch variable to the length of the file.
	 */

	hr=CoGetMalloc(MEMCTX_TASK, &pIMalloc);

	if (FAILED(hr))
		//Close file and return failure

	psz=pIMalloc->Alloc(cch);
	pIMalloc->Release();

	if (NULL==psz)
		//Close file and return failure

	//Read text into psz buffer and close file
	
	//Save memory pointer and return success
	m_pszText=psz;
	return NOERROR;
	}

If an object will make many allocations throughout it's lifetime, it makes sense to call CoGetMalloc once when the object is created, store the IMalloc pointer in the object (m_pIMalloc or such), and call IMalloc::Release when the object is destroyed. Alternatively, the APIs CoTaskMemAlloc and its friends may be used.