Share via


Source: refCount.cpp

 

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.

C/C++ Source File (refCount.cpp)

// 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;

}

To add refCount.cpp to the project

  1. Create a new C++ source file. For detailed instructions on how to do this, see Set Up My Visual C++ Project. Name the new file refCount.cpp.

  2. Copy the C/C++ source code above and paste it into the source file you just created.

Now build and run the application. The output is listed next.