ASP Component to Send Arbitary Large File from Server to Client

This article was contributed by <!-- Author Email -->Shimon Pozzin.

Platform:

Windows NT 4.x SP4, ATL 2.x, MS Visual C++ 5.x, IIS 4.x

Purpose:

Demonstrate IResponse::BinaryWrite call from ATL component.

Description:

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.

How to use:

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.

Full annoying comments (aka how it was built):

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-->



To test the demo project you have to put aspfile.asp, aspfile.dll and canflag.gif in the same directory, say, /test. Then register component (from command prompt issue: regsvr32 aspfile.dll.) Then create a virtual directory without read permissions pointing to /test. Create another virtual directory, called, say, /test1. Put aspfile.htm file into this directory. Original demo project is made so that all files are in the same virtual directory, so you have to change the path in aspfile.asp to real virtual directory where aspfile.asp file is located (e.g. "/test/aspfile.asp") That's it. Open a browser, type URL http://localhost/test1/aspfile.htm and observe wonderful canadian flag!
You may ask: "Why would I bother with script if I can simply point my URL to that path and to download the file like I did a million times?"
Well, sometimes you cannot. The main reason for that is execute-only permissions for the directory where the file is located. In this case you will not be able to get the file (browser will return an error).
This is when you should remember this handy component. You may send any binary file from server to client.
Response object of ASP contains a method called BinaryWrite. We have one problem, however. This method is not documented well. And there are no examples how to use it. This is why I decided to fill this gap.

你可能感兴趣的:(windows,Microsoft,Access,asp,IIS)