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

This is not a question because I have already found a solution. It took me a long time, so I want to explain it here.

Msxml is based on COM, so in C ++ it is not so simple, even if you have useful classes for solving memory allocation problems. But writing a new XML parser would be much more difficult, so I wanted to use msxml.

Problem:

I managed to find enough examples on the Internet to use msxml with CComPtr (a smart pointer to avoid having to manually call Release () for each IXMLDOMNode file), CComBSTR (to convert C ++ strings to COM for strings) and CComVariant . These 3 useful classes are ATL classes and need #include <atlbase.h> .

Problem: Visual Studio 2008 Express (free version) does not include ATL.

Decision:

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 indirectly replaced by CComPtr with _COM_SMARTPTR_TYPEDEF

A 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(); } 
+6
c ++ xml visual-studio-2008 msxml
source share
5 answers

I am glad that I posted my question, although I already had a solution, because I had several alternative solutions. Thanks for all your answers.

Using another parser, such as eXpat or perhaps less (not so much, but enough for my needs) TinyXML can really be a good idea (and simplify porting the program to another operating system).

Using the #import directive, apparently a special Microsoft extension to simplify the use of COM, is also interesting and led me to following the MSXML in C++ but as elegant as in C# webpage, which explains how to simplify the use of msxml as much as possible.

+1
source share

Perhaps try using the #import operator.

I used it in a VS6 project with which I hanged myself, you are doing something like this (for illustrative purposes only, this worked for me, but I am not saying that this is a mistake):

 #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.... 
+7
source share

Another option is to use another XML handler that is already made, such as eXpat . This avoids the use of ATL and the complexities of COM, and is easier than implementing your own. I suggest this only because you stated that the reason you are looking at msxml is because you do not want to implement your own parser.

+1
source share

You can use TinyXML. It is open source and more platform independent.

+1
source share

Why don't you use some MSXML wrapper that would protect you from COM, like Arabica ?

0
source share

All Articles