#define RETURN { hr = E_FAIL; goto Cleanup; } // don’t kill me! Look at last examples of MS
// under http://www.microsoft.com/data/xml
// You can’t catch me! 🙂
STDMETHODIMP CGetFile::GetFile(VARIANT vFileName)
{
_variant_t vReturnBuffer;
LPSAFEARRAY psaFile;
HANDLE hFile;
DWORD dwSizeOfFile;
DWORD dwNumberOfBytesRead;
BOOL bResult;
unsigned char *pReturnBuffer = NULL;
long k;
HRESULT hr = S_OK;
// Create file in this case only OPENS an existing file (or fails
// if the file does not exist!)
hFile = ::CreateFile(
vFileName.bstrVal, // name of the file
GENERIC_READ, // desired access
FILE_SHARE_READ, // shared access
NULL, // security attributes
OPEN_EXISTING, // creation disposition – open only if existing!
FILE_FLAG_SEQUENTIAL_SCAN, // flag attributes
NULL );
if( hFile == INVALID_HANDLE_VALUE )
{
return E_FAIL;
}
dwSizeOfFile = ::GetFileSize( hFile, NULL );
if (dwSizeOfFile == 0xFFFFFFFF)
{
return E_FAIL;
}
try
{
pReturnBuffer = new unsigned char[dwSizeOfFile];
}
catch( std::bad_alloc& )
{
return E_FAIL;
}
// Get the binary content of the file
bResult = ::ReadFile( hFile, pReturnBuffer, dwSizeOfFile, &dwNumberOfBytesRead, NULL );
if( FALSE == bResult )
{
RETURN(E_FAIL);
}
psaFile = ::SafeArrayCreateVector( VT_UI1 /*unsigned char*/, 0, dwSizeOfFile );
if( !psaFile )
{
RETURN(E_FAIL);
}
// Fill in the SAFEARRAY with the binary content of the file
for( k = 0; k < (int) dwSizeOfFile; k++ )
{
if( FAILED(::SafeArrayPutElement( psaFile, &k, &pReturnBuffer[k] )) )
{
RETURN(E_FAIL);
}
}
vReturnBuffer.vt = VT_ARRAY | VT_UI1;
V_ARRAY(&vReturnBuffer) = psaFile;
m_piResponse->BinaryWrite(vReturnBuffer);
Cleanup:
if( pReturnBuffer )
delete [] pReturnBuffer;
return SUCCEEDED(hr) ? S_OK : E_FAIL;
}
As you see, the idea is simple: to read the binary content of the file, to pack it into safearray and then to pass as a parameter to IResponse::BinaryWrite(). The process is pretty straightforward