Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use msxml with Visual Studio 2008 Express (no ATL classes) without becoming crazy?

It is not really a question because I have already found a solution. It took me a lot of time, that's why I want to explain it here.

Msxml is based on COM so it is not really easy to use in C++ even when you have helpful classes to deal with memory allocation issues. But writing a new XML parser would be much more difficult so I wanted to use msxml.

The problem:

I was able to find enough examples on the internet to use msxml with the help of CComPtr (smart pointer to avoid having to call Release() for each IXMLDOMNode manually), CComBSTR (to convert C++ strings to the COM format for strings) and CComVariant. This 3 helpful classes are ATL classes and need an #include <atlbase.h>.

Problem: Visual Studio 2008 Express (the free version) doesn't include ATL.

Solution:

Use comutil.h and comdef.h, which include some simple helper classes:

  • _bstr_t replaces more or less CComBSTR
  • _variant_t replaces more or less CComVariant
  • _com_ptr_t replaces indirectly CComPtr through the use of _COM_SMARTPTR_TYPEDEF

Small example:

#include <msxml.h>
#include <comdef.h>
#include <comutil.h>

// Define some smart pointers for MSXML
_COM_SMARTPTR_TYPEDEF(IXMLDOMDocument,     __uuidof(IXMLDOMDocument));     // IXMLDOMDocumentPtr
_COM_SMARTPTR_TYPEDEF(IXMLDOMElement,      __uuidof(IXMLDOMElement));      // IXMLDOMElementPtr
_COM_SMARTPTR_TYPEDEF(IXMLDOMNodeList,     __uuidof(IXMLDOMNodeList));     // IXMLDOMNodeListPtr
_COM_SMARTPTR_TYPEDEF(IXMLDOMNamedNodeMap, __uuidof(IXMLDOMNamedNodeMap)); // IXMLDOMNamedNodeMapPtr
_COM_SMARTPTR_TYPEDEF(IXMLDOMNode,         __uuidof(IXMLDOMNode));         // IXMLDOMNodePtr

void test_msxml()
{
    // This program will use COM
    CoInitializeEx(NULL, COINIT_MULTITHREADED);

    {
        // Create parser
        IXMLDOMDocumentPtr pXMLDoc;
        HRESULT hr = CoCreateInstance(__uuidof (DOMDocument), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&pXMLDoc);
        pXMLDoc->put_validateOnParse(VARIANT_FALSE);
        pXMLDoc->put_resolveExternals(VARIANT_FALSE);
        pXMLDoc->put_preserveWhiteSpace(VARIANT_FALSE);

        // Open file
        VARIANT_BOOL bLoadOk;
        std::wstring sfilename = L"testfile.xml";
        hr = pXMLDoc->load(_variant_t(sfilename.c_str()), &bLoadOk);

        // Search for node <testtag>
        IXMLDOMNodePtr pNode;
        hr = pXMLDoc->selectSingleNode(_bstr_t(L"testtag"), &pNode);

        // Read something
        _bstr_t bstrText;
        hr = pNode->get_text(bstrText.GetAddress());
        std::string sSomething = bstrText;
    }

    // I'm finished with COM
    // (Don't call before all IXMLDOMNodePtr are out of scope)
    CoUninitialize();
}
like image 700
Name Avatar asked Jan 21 '09 22:01

Name


1 Answers

Maybe try using the #import statement.

I've used it in a VS6 project I have hanging around, you do something like this (for illustrative purposes only; this worked for me but I don't claim to be error proof):

#import  "msxml6.dll"

  ...

MSXML2::IXMLDOMDocument2Ptr pdoc;
HRESULT hr = pdoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
if (!SUCCEEDED(hr)) return hr;

MSXML2::IXMLDOMDocument2Ptr pschema;
HRESULT hr = pschema.CreateInstance(__uuidof(MSXML2::DOMDocument60));
if (!SUCCEEDED(hr)) return hr;

pschema->async=VARIANT_FALSE;
VARIANT_BOOL b;
b = pschema->loadXML(_bstr_t( /* your schema XML here */ ));

MSXML2::IXMLDOMSchemaCollection2Ptr pSchemaCache;
hr = pSchemaCache.CreateInstance(__uuidof(MSXML2::XMLSchemaCache60));
if (!SUCCEEDED(hr)) return hr;

_variant_t vp=pschema.GetInterfacePtr();
pSchemaCache->add(_bstr_t( /* your namespace here */ ),vp); 

pdoc->async=VARIANT_FALSE;
pdoc->schemas = pSchemaCache.GetInterfacePtr();
pdoc->validateOnParse=VARIANT_TRUE;
if (how == e_filename)
    b = pdoc->load(v);
else
    b = pdoc->loadXML(bxmldoc);

pXMLError = pdoc->parseError;
if (pXMLError->errorCode != 0)
    return E_FAIL; // an unhelpful return code, sigh....
like image 104
Jason S Avatar answered Nov 15 '22 08:11

Jason S