The opinions expressed herein are my own personal opinions. They are not necessarily fact or sactioned by any other person or organization. If you disagree that's your right. It's also my right to not care.
© Copyright 2008, Chris Tacke
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_onlyTCHAR *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;}
Remember Me