This C/C++ code uses several DOM objects to generate the following simple XML document in memory.
<root> <A> <a>11</a> </A> <B>2</B> </root>
The C/C++ file uses some IXMLDOMNode objects (pElem, pElemA, and pElemOut) as temporary stores for holding elements that are added later to their respective element containers. To help you follow the state changes while objects are created and released, diagnostic messages are displayed to show the reference count of various interface pointers. These diagnostic messages begin with "dmN:", where N is the sequence number of the message.
// RefCount.cpp : Defines the entry point for the console application. // #include <stdio.h> #include <tchar.h> #import <msxml6.dll> raw_interfaces_only // Macro that calls a COM method returning HRESULT value. #define CHK_HR(stmt) do { hr=(stmt); if (FAILED(hr)) goto CleanUp; } while(0) // Macro that releases a COM object if not NULL. #define SAFE_RELEASE(p) do { if ((p)) { (p)->Release(); (p) = NULL; } } while(0) #define RELEASE_COUNT(p) do { count = (p)->Release(); (p) = NULL; } while(0) // Helper function to create a DOM instance. HRESULT CreateAndInitDOM(IXMLDOMDocument **ppDoc) { HRESULT hr = CoCreateInstance(__uuidof(MSXML2::DOMDocument60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(ppDoc)); if (SUCCEEDED(hr)) { // these methods should not fail so don't inspect result (*ppDoc)->put_async(VARIANT_FALSE); (*ppDoc)->put_validateOnParse(VARIANT_FALSE); (*ppDoc)->put_resolveExternals(VARIANT_FALSE); } return hr; } // Helper function creates an element and returns it as an XMLDOMNode. HRESULT CreateElementFromDom(BSTR bstrName, IXMLDOMDocument *pDom, IXMLDOMNode **ppNode) { HRESULT hr = S_OK; IXMLDOMElement *pElem = NULL; // We use createElement() instead of createNode() to illustrate // when to call Release on a DOM object. CHK_HR(pDom->createElement(bstrName, &pElem)); // pElem RefCount = 1 hr = pElem->QueryInterface(__uuidof(IXMLDOMNode), (void**)ppNode); // *ppNode RefCount = 1 if succeed QI // We are done with pElem, so we release it. SAFE_RELEASE(pElem); CleanUp: return hr; } // Helper function to determine the reference count of an interface pointer: ULONG refCountOf(IUnknown * pUnk) { pUnk->AddRef(); return pUnk->Release(); } int output_index = 1; // Helper function to display refcount of an interface pointer: void ShowRefCountOf(char * title, IUnknown * pUnk) { printf("dm%d: refCount(%s) = %d\n", output_index++, title, refCountOf(pUnk)); } // Helper function to display the specified refcount: void ShowRefCount(char * title, ULONG count) { printf("dm%d: refCount(%s) = %d\n", output_index++, title, count); } void refCount() { HRESULT hr = S_OK; IXMLDOMDocument *pDom = NULL; IXMLDOMNode *pRoot = NULL; IXMLDOMNode *pElem = NULL; IXMLDOMNode *pElemA = NULL; IXMLDOMNode *pElemOut = NULL; BSTR bstr = NULL; ULONG count; CHK_HR(CreateAndInitDOM(&pDom)); ShowRefCountOf("pDom ++", pDom); // dm1: // Create an empty <root> element. bstr = SysAllocString(L"root"); CHK_HR(CreateElementFromDom(bstr, pDom, &pRoot)); SysFreeString(bstr); ShowRefCountOf("pRoot ++", pRoot); // dm2: // Create an empty <A> element. bstr = SysAllocString(L"A"); CHK_HR(CreateElementFromDom(bstr, pDom, &pElem)); SysFreeString(bstr); ShowRefCountOf("pElem ++", pElem); // dm3: // Append <A> to <root>. CHK_HR(pRoot->appendChild(pElem, &pElemOut)); ShowRefCountOf("pElemOut ++", pElemOut); // dm4: // Keep a copy of the inserted <A> element and increment refcount. pElemA = pElemOut; pElemA->AddRef(); ShowRefCountOf("pElemA ++", pElemA); // dm5: // Recycle pElem and pElemOut for use in the next step. RELEASE_COUNT(pElem); ShowRefCount("pElem --", count); // dm6: RELEASE_COUNT(pElemOut); ShowRefCount("pElemOut --", count); // dm7: // The refCount of pElemA should be the same as that of // pElemOut, because they both reference the same object. ShowRefCountOf("pElemA ", pElemA); // dm8: // Create an <a> element with a text value of "11". bstr = SysAllocString(L"a"); CHK_HR(CreateElementFromDom(bstr, pDom, &pElem)); SysFreeString(bstr); bstr = SysAllocString(L"11"); CHK_HR(pElem->put_text(bstr)); SysFreeString(bstr); ShowRefCountOf("pElem ++", pElem); // dm9: // Append <a> to <A>. CHK_HR(pElemA->appendChild(pElem, &pElemOut)); ShowRefCountOf("pElemOut ++", pElemOut); // dm10: // We're done with pElemA. RELEASE_COUNT(pElemA); ShowRefCount("pElemA --", count); // dm11: // Recycle pElem and pElemOut. RELEASE_COUNT(pElem); ShowRefCount("pElem --", count); // dm12: RELEASE_COUNT(pElemOut); ShowRefCount("pElemOut --", count); // dm13: // Create a <B> element with a text value of "2". bstr = SysAllocString(L"B"); CHK_HR(CreateElementFromDom(bstr, pDom, &pElem)); SysFreeString( bstr); bstr = SysAllocString(L"2"); CHK_HR(pElem->put_text(bstr)); SysFreeString(bstr); ShowRefCountOf("pElem ++", pElem); // dm14: // Append <B> to <root>. CHK_HR(pRoot->appendChild(pElem, &pElemOut)); ShowRefCountOf("pElemOut ++", pElemOut); // dm15: // Recycle pElem and pElemOut. RELEASE_COUNT(pElem); ShowRefCount("pElem --", count); // dm16: RELEASE_COUNT(pElemOut); ShowRefCount("pElemOut --", count); // dm17: // Append <root> to dom. CHK_HR(pDom->appendChild(pRoot, &pElemOut)); ShowRefCountOf("pElemOut ++", pElemOut); // dm18: // We're done with pElemOut. RELEASE_COUNT(pElemOut); ShowRefCount("pElemOut --", count); // dm19: // Output the result XML string. CHK_HR(pDom->get_xml(&bstr)); printf("\npDom->xml:\n\n%S\n", bstr); SysFreeString(bstr); // We're done with pRoot. RELEASE_COUNT(pRoot); ShowRefCount("pRoot --", count); // dm20: // We're done with pDom. RELEASE_COUNT(pDom); ShowRefCount("pDom --", count); // dm21: CleanUp: SAFE_RELEASE(pDom); SAFE_RELEASE(pRoot); SAFE_RELEASE(pElem); SAFE_RELEASE(pElemA); SAFE_RELEASE(pElemOut); SysFreeString(bstr); } int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr = CoInitialize(NULL); if(SUCCEEDED(hr)) { refCount(); CoUninitialize(); } return 0; }
MSDN DOM sample 上的一个示例很好的说明了这些原则,下面对这篇文章的代码做些总结说明。
总结一下,DOM接口指针使用和释放的规律为:
1. 通过DOM对象接口函数(当然也包括通过CoCreateInstance获得的IXMLDOMDocument)获得的接口指针,需要显式的调用 Release释放。这些函数如IXMLDOMDocument->createElement, IXMLDOMNode->appendChild。
2. 对于手动赋值的接口指针(如代码中的pElemA = pElemOut),需要显式的在被赋值的指针上(pElemA)调用AddRef和Release,来增、减引用计数。
3.其他的使用则无需增减引用计数。
其他:
Release()返回引用计数减1后的值,即如果原来引用计数为1,则Release()返回值为0.
IXMLDOMNode->appendChild()的输出参数接口指针在值上与输入参数接口指针相同,因此二者指向同一个DOM对象。
参考:http://www.cppblog.com/gracelee/archive/2011/12/01/161260.html