Sample code in C++

Sooner or later, every Windows programmer has to deal with the Windows APIs. The "natural" approach is to design a C++ class to wrap the lower-level Windows APIs with default parameters and appropriate error handling.

The class implemented here (named CQPXFile) provides open, read, and close functionality for a specified file by calling the Win32 functions CreateFile, ReadFile, and CloseHandle. I used this class inside a COM component that transfers files across a network using FTP.

   Copyright (c) 2000-2001 Obvious Technology

    This is a simple wrapper class for Win32 file I/O functionality.

    Errors are thrown (rather than returned as HRESULTs) so that more complete
    error information can be returned to the calling object. This means that
    all calls to the public member functions (including the constructor if
    initialization parameters are specified) should be wrapped in a try/catch

#include "stdafx.h"
#include <stdio.h>
#include "QPXFile.h"

// constructor
CQPXFile::CQPXFile( BSTR bstrFileSpec ) throw( CHRException ) : m_hFile(INVALID_HANDLE_VALUE)
    if( bstrFileSpec == NULL )

    initFile( bstrFileSpec );

// destructor
CQPXFile::~CQPXFile() throw( CHRException )

// initFile
void CQPXFile::initFile( BSTR bstrFileSpec ) throw( CHRException )
    CHRX    oHR( CLSID_NULL, L"CQPXFile::initFile" );


        // sanity-check the parameter
        HRXASSERTPTR(10, bstrFileSpec);

        // open the file
        m_hFile = CreateFileA( W2A(bstrFileSpec),       // file name
                               GENERIC_READ,            // access mode
                               FILE_SHARE_READ,         // share mode
                               NULL,                    // security descriptor
                               OPEN_EXISTING,           // how to create
                               FILE_ATTRIBUTE_NORMAL |  // file attributes
                               NULL );                  // handle to template file

        if( m_hFile == INVALID_HANDLE_VALUE )
            WCHAR   szMsg[200];

            swprintf( szMsg, L"Cannot open file '%s'", bstrFileSpec );
            oHR( E_FAIL, szMsg );
    catch( CHRException e )
        throw e.packErrorInfo( oHR );

// uninitFile
void CQPXFile::uninitFile() throw( CHRException )
    CHRX    oHR( CLSID_NULL, L"CQPXFile::uninitFile" );

    if( m_hFile != INVALID_HANDLE_VALUE )
        // close the file
        HRXASSERT(10, CloseHandle( m_hFile ), E_FAIL);
        m_hFile = INVALID_HANDLE_VALUE;

// getBinaryData
int CQPXFile::getBinaryData( LPBYTE pBuf, int cb ) throw( CHRException )
    DWORD nCbRead = 0;
    CHRX  oHR( CLSID_NULL, L"CQPXFile::getBinaryData" );

    HRXASSERT(10, ReadFile( m_hFile, pBuf, cb, &nCbRead, NULL ), E_FAIL);
    return nCbRead;

// getFileSize
int CQPXFile::getFileSize() throw( CHRException )
    DWORD   dwLo32, dwHi32;
    CHRX    oHR( CLSID_NULL, L"CQPXFile::getFileSize" );

    // this module uses 32-bit signed integers, so the file size is limited to 2^31 bytes
    dwLo32 = GetFileSize( m_hFile, &dwHi32 );
    if( (dwLo32 & 0x80000000) || dwHi32 )
        oHR( E_FAIL, L"OQPX cannot transfer files larger than 2^31 (2147483648) bytes" );

    return static_cast<int>(dwLo32);

Some comments on the code

This code is deceptively simple. This class is part of an ATL project, so there is a lot of functionality implied by that #include <stdafx.h> statement.

The implementation handles errors using C++ structured exception handling. The class CHRX knows how to parse an HRESULT and throw a C++ exception if the HRESULT indicates an error. The error-handling class uses C++ operator overloading and some handy macros (HRXASSERT) to clarify the error-checking syntax, so the resulting code is much cleaner than it would have been had if statements been used to check HRESULTs.

This page updated Friday, October 05, 2007 at 19:30 UTC.

This page is valid XHTML and uses valid CSS.