Simple XML example in C++

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(“okn”));

    // 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(“okn”));

    // 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(“oknReading %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] = ”;
    bstr = new CComBSTR(wbuffer);

    _tprintf(_T(“oknLoading %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 = %in”), GetLastError());
        goto exit;
    }

    _tprintf(_T(“done.nnET = %i msnn”), 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 = ”;

    return;
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s