Like most developers, I have tons of small code samples and snippets lying around. I'm starting to go through them in order to post what might be useful to others.
Here's one that I wrote about 5 years ago when I had a customer complaining about the speed of parsing an XML document using MSXML. Of course this test simply confirmed that yes, MSXML is molasses-in-January slow and that if raw speed is what you want, then something like Expat is a better route to go. However the test is a reasonably good sample of how you might use the DOMDocument from a C++ application.
As always, the code is an as-is sample. uSe it at your own risk.
#include <windows.h>
#include "objbase.h"
#include "oleauto.h"
#include "MSXML.h"
#include "ATLBASE.h"
#import "msxml.dll" named_guids raw_interfaces_only
TCHAR *xmlfile = _T("\\test.xml");
using namespace MSXML;
void GetCurrentDirectory(TCHAR *szDirectory);
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSXML::IXMLDOMDocument *iXMLDoc = NULL;
HRESULT hr;
VARIANT_BOOL b;
int et = 0;
HANDLE hFile = NULL;
DWORD wsize, dwhigh = 0;
TCHAR filename[MAX_PATH];
MEMORYSTATUS ms;
BYTE *buffer = NULL;
TCHAR *wbuffer = NULL;
DWORD dwRead = 0;
DWORD toalloc = 0;
int i;
CComBSTR *bstr;
_tprintf(_T("Starting XML Benchmark...\n"));
_tprintf(_T("Creating DOMDocument..."));
// start COM
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
// create a DOMDocument
hr = CoCreateInstance (MSXML::CLSID_DOMDocument, NULL,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
MSXML::IID_IXMLDOMDocument,(LPVOID *)&iXMLDoc);
// check for success
if(!iXMLDoc)
{
_tprintf(_T("failed (hr = %i)\n"), hr);
goto exit;
}
_tprintf(_T("ok\n"));
// synchronous operation
iXMLDoc->put_async(VARIANT_FALSE);
// get the data file - pull from the same directory as our app
GetCurrentDirectory(filename);
_tcscat(filename, xmlfile);
_tprintf(_T("Opening XML file (%s)..."), filename);
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
_tprintf(_T("failed (err = %i)\n"), GetLastError());
goto exit;
}
// determine the file size
dwsize = GetFileSize(hFile, &dwhigh);
_tprintf(_T("ok\n"));
// check available memory
ms.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus(&ms);
// either 1/3 available memory or file size, whichever is less
toalloc = (dwsize > (ms.dwAvailPhys / 3)) ? (ms.dwAvailPhys / 3) : dwsize;
_tprintf(_T("Allocating %i bytes..."), toalloc);
//alocate buffers. data is ANSI, loadXML requires Unicode
buffer = (BYTE *)LocalAlloc(LPTR, toalloc);
wbuffer = (TCHAR *)LocalAlloc(LPTR, toalloc * sizeof(TCHAR) + 1);
// check for success
if((buffer == NULL) || (wbuffer == NULL))
{
_tprintf(_T("failed (err = %i)\n"), GetLastError());
goto exit;
}
_tprintf(_T("ok\nReading %i bytes..."), toalloc);
// fill the RAM buffer with data
ReadFile(hFile, &buffer[0], toalloc, &dwRead, NULL);
// lazy man's ANSI to Unicode conversion
// this is NOT recommended for production code, don't cut and paste!!
for(i = 0 ; i < (int)toalloc ; i++)
{
wbuffer[i] = buffer[i];
}
wbuffer[i] = '\0';
bstr = new CComBSTR(wbuffer);
_tprintf(_T("ok\nLoading %i bytes into DOMDocument..."), toalloc);
// get a start time
et = GetTickCount();
// load the xml
hr = iXMLDoc->loadXML(*bstr, &b);
// determine ET
et = GetTickCount() - et;
// check for load failure
if(!b)
{
_tprintf(_T("failed (hr = %i)\n"), hr);
_tprintf(_T("GetLastError = %i\n"), GetLastError());
goto exit;
}
_tprintf(_T("done.\n\nET = %i ms\n\n"), et);
exit:
// release the DOMDocument
iXMLDoc->Release();
// release the file
CloseHandle(hFile);
// release COM
CoUninitialize();
_tprintf(_T("Exiting XML Benchmark in 5 seconds...\n"));
// free buffers
if(buffer)
LocalFree(buffer);
if(wbuffer)
LocalFree(wbuffer);
// wait to allow display to persist for a while
Sleep(5000);
return 0;
}
void GetCurrentDirectory(TCHAR *szDirectory)
{
TCHAR *p, *p2;
// get current directory
GetModuleFileName(NULL, szDirectory, MAX_PATH);
// trim off the exe name
p = _tcsstr(szDirectory, _T("\\"));
if(p == NULL)
{
// no slash found - return root?
_tcscpy(szDirectory, _T("\\"));
return;
}
while( p != NULL)
{
p2 = p + 1;
p = _tcsstr(p2, _T("\\"));
}
// null terminate to crop
p2--;
*p2 = '\0';
return;
}