Using COM to Pass Arrays

Sunday Nov 8th 1998 by Jeff Lundgren

Using COM to Pass Arrays


COM is a great tool when programming in windows. It gives us the ability to communicate with other programs and allows us to scale our products.  There are a few things we are are used to doing however, that are more difficult with COM, one of these is passing arrays as parameters in COM methods.  This article describes the process to pass arrays of data to and from COM objects, without writing our own marshaler.


It's a myth really that COM only supports VARIANT data type as parameters.  Most COM developers don't know about this because we are used to using the wizards that only provide these as options.  We can however, pass any datatypes we want, even structs and arrays, but if we need this functionality then we must write our own marshaler.   This is not really a hard task, but it does require some additional time, and for most applications, it's much easier to use the system marshaler (oleaut32.dll).  The cost of using the system marshaler is we must use VARIANT types.

To pass an array of data, we have two choices.  We can write our own marhaler, or we can send the array as a VARIANT.  The VARIANT structure (which is what it really is) allows for a an element called SAFEARRAY.  The examples below show how to do this.


This is an example of how to send a file via COM to a server, who in turn writes the file to it's own disk system.  This is kind of like a file transfer protocol via COM.   It's not the quickest way to do it, but it works, and more importantly, we used COM, and we did it without writing our own marshaler.

//The Client

BOOL CClient::StreamIn()
	char *fBuf;
	fBuf = (char*)malloc(4096); // Allocate our buffer

	VARIANT varTemp;
	varTemp.vt = VT_UI1 | VT_ARRAY;
	long lLen = m_File->GetLength();

	long nBytesRead = m_File->Read( fBuf, 4096 ); // Read from our file into our buffer (note: file opened as binary)
	int iCount = 4096;
	while(nBytesRead>0) // While we read bytes
		bound.cElements = nBytesRead; // Set up size of array
		bound.lLbound = 0;
		varTemp.parray = SafeArrayCreate(VT_UI1, 1, &bound); // Create it
		void* pDest;
		SafeArrayAccessData(varTemp.parray, &pDest);
		memcpy(pDest, fBuf, nBytesRead); // Copy into array

		long retval = 0;
		// m_server was created using the smart pointers (#import "yourserver.tlb" no_namespace ... etc)
		HRESULT _hr = m_server->raw_SendFile(varTemp); // Call the server method, pass our VARIANT
		if(retval != 0 && !FAILED(_hr))
			return false;
		SafeArrayDestroy(varTemp.parray); // destroy the array.

		nBytesRead = m_File->Read( fBuf, 4096 );  Read moredata

	} // End of while
	return true;

//The Server
// IDL:
	[id(1), helpstring("method SendFile")] HRESULT SendFile([in] VARIANT buffer);
// Implementation
STDMETHODIMP CServer::SendFile(VARIANT buffer)
	AFX_MANAGE_STATE(AfxGetStaticModuleState()) // To support MFC

	void* pDest;
	// Previously the server object had opened it's own file
	if(m_File!=NULL) // Which should mean that it is open
		if (buffer.vt == (VT_ARRAY | VT_UI1))
			SafeArrayAccessData(buffer.parray, &pDest); // Get the data
			SafeArrayUnaccessData(buffer.parray);	    // Unaccess it.
			m_File->Write(pDest, buffer.parray->rgsabound->cElements); // Write it to the server file


	return S_OK;


We could have used SAFEARRAY's and VARIANT by using MFC or ATL wrapper classes, but the examples above are easier to understand. Also, we could have added better try catch blocks etc, but I've taken them out to simply the example.  I'll leave that up to you.   In process this code is very fast, out of process or out of band (DCOM), you'll want to set the buffer size at least as high as your network packet size, if not more.   What makes this slow is calling the method over and over.  Alternatively, we could have passed a com interface to the function, but DCOM implementations make this a nightmare.

Mobile Site | Full Site
Copyright 2018 © QuinStreet Inc. All Rights Reserved