Source: refCount.cpp

MSXML 5.0 SDK

Microsoft XML Core Services (MSXML) 5.0 for Microsoft Office - DOM Developer's Guide

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)

#include <stdio.h>
#include <windows.h>
#import <msxml5.dll> raw_interfaces_only
using namespace MSXML2;

// The following macro executes an arbitratry method call, followed
// by error checking. Using it in the main() function below makes
// the code more readable.
#define HRCALL(a, errmsg) \
do { \
    hr = (a); \
    if (FAILED(hr)) { \
        dprintf( "%s:%d  HRCALL Failed: %s\n  0x%.8x = %s\n", \
                __FILE__, __LINE__, errmsg, hr, #a ); \
        goto clean; \
    } \
} while (0)

// This helper function outputs a message to both stdout and 
// debug-output in Visual Studio.
void dprintf( char * format, ...)
{
    static char buf[1024];
    va_list args;
    va_start( args, format );
    //va_arg( args, char *); // Skip format.
    vsprintf( buf, format, args );
    va_end( args);
    OutputDebugStringA( buf);
    printf("%s", buf);
}

// Helper function to create a DOM instance: 
IXMLDOMDocument * DomFromCOM()
{
   HRESULT hr;
   IXMLDOMDocument *pxmldoc = NULL;

    HRCALL( CoCreateInstance(__uuidof(DOMDocument50),
                      NULL,
                      CLSCTX_INPROC_SERVER,
                      __uuidof(IXMLDOMDocument),
                      (void**)&pxmldoc),
            "Create a new DOMDocument");
    // pxmldoc RefCount = 1

    HRCALL( pxmldoc->put_async(VARIANT_FALSE),
            "should never fail");
    HRCALL( pxmldoc->put_validateOnParse(VARIANT_FALSE),
            "should never fail");
    HRCALL( pxmldoc->put_resolveExternals(VARIANT_FALSE),
            "should never fail");

   return pxmldoc;
clean:
   if (pxmldoc)
    {
        // pxmldoc RefCount = 0 -> deleted
      pxmldoc->Release();
    }
   return NULL;
}

// Helper function creates an element and returns it as an
// XMLDOMNode.
IXMLDOMNode *ElementFromDom(BSTR name, IXMLDOMDocument *pDom)
{
   if (pDom==NULL) {
      dprintf("ElementFromDom: invalid pDom\n");
      return NULL;
   }

    HRESULT hr;
   IXMLDOMNode *pNode = NULL;
   IXMLDOMElement *pElem = NULL;

   // We use createElement() instead of createNode() to illustrate
   // when to call Release on a DOM object.
    HRCALL( pDom->createElement(name, &pElem),
            "can't create pElem" );
    // pElem RefCount = 1

   HRCALL( pElem->QueryInterface(__uuidof(IXMLDOMNode), (void**)&pNode),
          "can't QI IXMLDOMNode from pElem.");
    // pNode RefCount = 1

clean:
    if (pElem)
    {
       // We are done with pElem, so we release it.
       pElem->Release();
    }

    // pNode RefCount = 1
   return pNode;
}

// 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)
{
   dprintf("dm%d:  refCount(%s) = %d\n", output_index++, title, refCountOf(pUnk));
}

// Helper function to display the specified refcount:
void ShowRefCount(char * title, ULONG count)
{
   dprintf("dm%d:  refCount(%s) = %d\n", output_index++, title, count);
}

//////////////////////////////
//
int main(int argc, char* argv[])
{
   HRESULT hr;
   IXMLDOMDocument *pDom = NULL;
   IXMLDOMNode      *pRoot = NULL;
   IXMLDOMNode      *pElem = NULL;
   IXMLDOMNode      *pElemA = NULL;
   IXMLDOMNode      *pElemOut = NULL;
   BSTR bstr = NULL;
   ULONG count;

   CoInitialize(NULL);

   pDom = DomFromCOM();      
   if (!pDom) 
      goto clean;
   ShowRefCountOf("pDom ++", pDom);      // dm1:

   // Create an empty <root> element.
    bstr = SysAllocString(L"root");
   pRoot = ElementFromDom(bstr, pDom);   
   if (!pRoot) {
      goto clean;
   }
   ShowRefCountOf("pRoot ++", pRoot);      // dm2:
    SysFreeString( bstr);
    bstr = NULL;

   // Create an empty <A> element.
    bstr = SysAllocString(L"A");
   pElem = ElementFromDom(bstr, pDom);  
   if (!pElem) {
      goto clean;
   }
   ShowRefCountOf("pElem ++", pElem);         // dm3:
    SysFreeString( bstr);
    bstr = NULL;


   // Append <A> to <root>.
    HRCALL( pRoot->appendChild(pElem, &pElemOut),
            "failed to append <A> to <root>" );
   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.
   count = pElem->Release();
   ShowRefCount("pElem --", count);         // dm6:
    pElem = NULL;

   count = pElemOut->Release();
    pElemOut = NULL;
   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");
   pElem = ElementFromDom(bstr, pDom);
   if (pElem==NULL) {
      goto clean;
   }
    SysFreeString( bstr);
    bstr = NULL;

    bstr = SysAllocString(L"11");
    HRCALL( pElem->put_text(bstr),
            "put_text(...)");
   ShowRefCountOf("pElem ++", pElem);         // dm9:
    SysFreeString( bstr);
    bstr = NULL;

   // Append <a> to <A>.
    HRCALL( pElemA->appendChild(pElem, &pElemOut),
            "append <a> to <A>");
   ShowRefCountOf("pElemOut ++", pElemOut);   // dm10:

   // We're done with pElemA.
   count = pElemA->Release();
    pElemA = NULL;
   ShowRefCount("pElemA --", count);         // dm11:

   // Recycle pElem and pElemOut.
   count = pElem->Release();
    pElem = NULL;
   ShowRefCount("pElem --", count);         // dm12:

   count = pElemOut->Release();
    pElemOut = NULL;
   ShowRefCount("pElemOut --", count);         // dm13:

   // Create a <B> element with a text value of "2".
    bstr = SysAllocString(L"B");
   pElem = ElementFromDom(bstr, pDom);
   if (!pElem)
      goto clean;
    SysFreeString( bstr);
    bstr = NULL;

    bstr = SysAllocString(L"2");
   HRCALL( pElem->put_text(bstr),
            "put_text(...)");
   ShowRefCountOf("pElem ++", pElem);         // dm14:
    SysFreeString( bstr);
    bstr = NULL;

   // Append <B> to <root>.
   HRCALL( pRoot->appendChild(pElem, &pElemOut),
            "append <B> to <root>");
   ShowRefCountOf("pElemOut ++", pElemOut);   // dm15:

   // We're done with pElem, and recycle pElemOut.
   count = pElem->Release();
    pElem = NULL;
   ShowRefCount("pElem --", count);         // dm16:

   count = pElemOut->Release();
    pElemOut = NULL;
   ShowRefCount("pElemOut --", count);         // dm17:


   // Append <root> to dom.
   HRCALL( pDom->appendChild(pRoot, &pElemOut),
            "append <root> to dom");
   ShowRefCountOf("pElemOut ++", pElemOut);   // dm18:

   // We're done with pElemOut.
   count = pElemOut->Release();
    pElemOut = NULL;
   ShowRefCount("pElemOut --", count);         // dm19:

   HRCALL( pDom->get_xml(&bstr),
            "get_xml");
   dprintf("\npDom->xml:\n\n%S\n", bstr);
   
clean:   
   if (bstr)
      SysFreeString(bstr);

   if (pElem)
        pElem->Release();
   if (pElemA)
        pElemA->Release();
   if (pElemOut)
        pElemOut->Release();

    if (pDom) {
      count = pDom->Release();
      ShowRefCount("pDom  --", count);      // dm20:
   }

   if (pRoot) {
      count = pRoot->Release();
      ShowRefCount("pRoot --", count);      // dm21:
   } 

   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.