Proper way of using IXMLDOMDocument
MSDN documentation for this is a mess and for the most part, inadequate (it's better than MSDN's C++ ADO documentation though).  

If you have access to MSXML, then you can use smart pointer wrappers that allow you to avoid worrying about releasing the objects. These smart pointers come with simplified function calls.  

For instance, here is the normal function prototype for a IXMLDOMNodeList:

HRESULT IXMLDOMNodeList::get_length(long *listLength);


Here is the "smart" version of that function for IXMLDOMNodeList object:

long IXMLDOMNodeList::Getlength ();


This allows you skip the error checking (it throws an exception on failure).
You also have access to the source code for these new functions as well. The source code is in an automatically generated .tli file, so you can always know what they do. The .tli file is usually located in C:\Users\*User*\Local\Temp\msxml6.tli. Just looking through this file can help you partially learn how to use IXMLDom.   

If you have access to comutil.h, you can use the _bstr_t type instead of BSTR for automatic memory management as well.  

Here are a few examples of using the smart pointers. I used standard library containers such as std::string and std::vector, but you could easily change these out with CStrings or other string types.  

#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;tchar.h&gt;
#include &lt;comutil.h&gt;
#import &lt;msxml6.dll&gt;

typedef std::basic_string &lt;TCHAR&gt;       tstring ;

typedef MSXML2::IXMLDOMNodePtr          NodePtr ;
typedef MSXML2::IXMLDOMNodeListPtr      NodeListPtr ;
typedef MSXML2::IXMLDOMDocumentPtr      DocumentPtr ;
typedef MSXML2::IXMLDOMElementPtr       ElementPtr ;
typedef MSXML2::IXMLDOMNamedNodeMapPtr  NamedNodeMapPtr ;

DocumentPtr LoadXMLDocument (const tstring &amp;strFile)
{
    // Call ::CoInitialize or ::CoInitializeEx before this.
    HRESULT hr ;
    DocumentPtr pDoc = NULL ;
    hr = pDoc.CreateInstance (__uuidof (MSXML2::DOMDocument60)) ; 
    if (hr != S_OK) {
        // This could happen if ::CoInitialize or ::CoInitializeEx hasn't been called.
        // Throw an exception.
    }

    pDoc-&gt;async = VARIANT_FALSE ;
    pDoc-&gt;validateOnParse = VARIANT_FALSE ;
    pDoc-&gt;resolveExternals = VARIANT_FALSE ;

    VARIANT_BOOL vbOk = pDoc-&gt;load (_variant_t (strFile.data ())) ;

    if (vbOk == VARIANT_FALSE) {
        // Throw an exception.
    }

    return pDoc ;
}

tstring GetAttribute (const NamedNodeMapPtr &amp;pAttrs, const tstring &amp;strKey)
{
    tstring str ;

    NodePtr pAttr = pAttrs-&gt;getNamedItem (_bstr_t (strKey.data ())) ;
    if (pAttr == NULL) {
        // Throw an exception.
    }

    _variant_t var = pAttr-&gt;GetnodeValue () ;
    if (var.vt == VT_BSTR) {
        str = (TCHAR *) (_bstr_t) var ;

    } else {
        // Throw an exception.
    }

    return str ;
}

tstring GetAttribute (const NodePtr &amp;pNode, const tstring &amp;strKey)
{
    NamedNodeMapPtr pAttrs = pNode-&gt;Getattributes () ;
    return GetAttribute (pAttrs, strKey) ;
}

tstring GetSubElementText (const ElementPtr &amp;pNode, const tstring &amp;strSubElement)
{
    NodePtr pSub = pNode-&gt;selectSingleNode (_bstr_t (strSubElement.data ())) ;
    if (pSub == NULL) {
        // Throw an exception.
    }

    _bstr_t bsRoot = pSub-&gt;Gettext () ;
    tstring strText = (TCHAR *) bsRoot ;
    return strText ;
}

void GetAttributes (const NodePtr &amp;pNode, const std::vector &lt;tstring&gt; &amp;vecKeys, std::vector &lt;tstring&gt; &amp;vecValues, const tstring &amp;strDefault)
{
    NamedNodeMapPtr pAttrs = pNode-&gt;Getattributes () ;
    for (unsigned n = 0; n &lt; vecKeys.size (); ++n) {
        const tstring &amp;strKey = vecKeys [n] ;
        tstring str = BVLib::GetAttribute (pAttrs, strKey) ;
        vecValues.push_back (str) ;
    }
}