This article was contributed by <!-- Author Email -->Shimon Pozzin.
Windows NT 4.x SP4, ATL 2.x, MS Visual C++ 5.x, IIS 4.x
Demonstrate IResponse::BinaryWrite call from ATL component.
Writing some scripts in ASP (hey, this is not my job! :-) ) I came across the problem of sending the binary file from server to client.
Attached project is full source code of the component, sample ASP file, sample HTM file and a sample GIF file. Of course, the file may be any binary file, but you should be careful about correct MIME type of the file being transferred. Source is free for distribution, modification etc.
IResponse::BinaryWrite() expects as a parameter a variant, containing safearray of type VT_ARRAY | VT_UI1 (array of unsigned char[s]) This project was build using standard ATL wizard with default options. Then, ASP object was inserted into the project (what else could you add to the project that must work in ASP script?!) Finally, one simple method, called GetFile() was added to the interface of the ASP object as follows:
#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 <!--webbot
bot="HTMLMarkup" startspan --><<!--webbot bot="HTMLMarkup" endspan -->(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;
}
from WWW.VCKBASE.COM
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
Download source and demo project - 62 KB <!--comments-->