The Wayback Machine - https://web.archive.org/web/20120426014447/http://www.codeguru.com:80/cpp/com-tech/activex/com/article.php/c5513/Passing-Binary-Data-in-COM.htm

Passing Binary Data in COM

There are two ways we can pass binary data in COM. SAFEARRAY and a pointer. by using a buffer pointer , we can get the best performance.

Here is the method declared in server IDL:

HRESULT Transfer([in] long cbSize,      
                 [in, size_is(cbSize)] unsigned char cBuffer[])

Here is the client code:

ITargetObj * pITargeObj ;
HRESULT hRC = ::CoCreateInstance(CLSID_TargetObj, 
                                 NULL, 
                                 CLSCTX_SERVER,
                                 IID_ITargetObj, 
                                 (void **)&pITargetObj ) ;
if FAILED( hRC )
{
 AfxMessageBox( "Failed to make target object!" ) ;
 return FALSE ;
}
      
BYTE * pBuffer = (BYTE *)::CoTaskMemAlloc( 15 ) ;
CopyMemory( pBuffer, "HELLO WORLD!!!!", 15 ) ;
pITargetObj->Transfer( 15, pBuffer ) ;
::CoTaskMemFree( pBuffer ) ;
pITargetObj ->Release() ;
But it only working for a INPROC Server with an object supporting a custom interface. If the object supporting a dual and dispatch interface, only the first character is transferred from client to server. Because the size_is attribute is stripped out (it's not supported by Automation), and the type library is used to marshal the interface. Obviously, this will not do. By the way, one good way to pass an array that does work for dual and dispatch interfaces is to use a SAFEARRAY.

Using CBufferVariant

Well,It's seem we have to using the SAFEARRAY, It's easy for a VB program, but I wanna same to VC program. I'v created a class named CBufferVariant, What's the cool things:

Here is the method declared in server IDL:

HRESULT Transfer([in] VARIANT vData)

Here is the server code:

STDMETHODIMP CTargeObj::Transfer(VARIANT Data)
{
 CBufferVariant bvData=Data;
 if(bvData.GetLength()==0)
  return S_OK;
 send(m_nSocketFD,bvData,bvData.GetLength(),0);
 return S_OK;
}

Here is the client code:

#include "BufferVariant.h"

ITargetObj * pITargeObj ;
HRESULT hRC = ::CoCreateInstance(CLSID_TargetObj, 
                                 NULL, 
                                 CLSCTX_SERVER,
                                 IID_ITargetObj, 
                                 (void **)&pITargetObj ) ;
if FAILED( hRC )
{
 AfxMessageBox( "Failed to make target object!" ) ;
 return FALSE ;
}

CBufferVariant bvData;

SomeStruct stData;
bvData.AssignData(&stData,sizeof(SomeStruct));
pITargetObj->Transfer( bvData );

bvData="Hello World!";
bvData+="\n";
pITargetObj->Transfer( bvData );

char buffer[2048];
File1.Read(buffer,2048);
bvData.AssignData(buffer,2048);
File2.Read(buffer,1024);
bvData.AppendData(buffer,1024);
pITargetObj->Transfer( bvData );

pITargetObj->Transfer( CBufferVariant("This is a ANSI string.") ) ;

pITargetObj->Release();

Downloads

Download source - 2 Kb

IT Offers

Comments

  • Run Faild:Bad Variant Type.

    Posted by Sohohome on 01/31/2005 11:54am

    //IDL [id(4), helpstring("method PutBinaryData")] HRESULT PutBinaryData([in]VARIANT vData); //client CBufferVariant bvData; bvData="Hello World!"; bvData+="\n"; hr=pICafeServer->PutBinaryData(bvData); if(FAILED(hr)) { char * pMsgBuf; BOOL fOk = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, hr, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR) &pMsgBuf;, 0, NULL); MessageBox(pMsgBuf); } //messagebox info is:Faild:Bad Variant Type

    Reply
  • Receiving a binary data from COM Object

    Posted by Legacy on 03/28/2002 12:00am

    Originally posted by: Sang Jeong Woo/ ERON Technology

    If we can use 
    
    

    HRESULT Send([in] long dataLength, [in, size_is(dataLength)] unsigned char* pData);

    for sending binary data to a COM object...

    why don't you use following way for receiving binary data from a COM object ?

    HRESULT Receive([out] long* pDataLength, [out, size_is(, *pDataLength)] unsigned char** ppData);

    In this case, COM allocates the buffer using CoTaskMemAlloc(), and the client responsible for reclaim the memory(using CoTaskMemFree())...

    bye~

    Reply
  • How to return a binary data from COM Method to Client?

    Posted by Legacy on 02/18/2002 12:00am

    Originally posted by: Alexander Tumarov

    How to return a binary data from COM Method to Client?
    And how to allocate and dealocate memory (and where)?

    Reply
  • Super !!

    Posted by Legacy on 11/09/2001 12:00am

    Originally posted by: Chandra Sekhar

    Thanks for your code... It is very useful

    Reply
  • Very good job!

    Posted by Legacy on 10/19/2001 12:00am

    Originally posted by: Supergiovine

    Thanks for your code, a simple way to make a difficult work!

    Reply
  • GetLength is wrong!

    Posted by Legacy on 08/15/2001 12:00am

    Originally posted by: alwayscy

    	long nLength;
    
    SafeArrayGetUBound(m_varData.parray, 1, &nLength;);
    return nLength-1;

    SafeArrayGetUBound() return the "UBOUND" of array and you "add one" when SetLength. So when return the "TRUE LENGTH OF ARRAY" minus one is wrong!

    So the code should be like this:
    long nLength;
    SafeArrayGetUBound(m_varData.parray, 1, &nLength;);
    //return nLength-1;
    return nLength; // CAII change it on 2001.8.16

    Thank for you code,it help me very much!

    Reply
  • This is excellent work!

    Posted by Legacy on 05/27/2001 12:00am

    Originally posted by: farcall

    The code just I want, better than other code that I searched. :)

    Best regard.

    Reply

Whitepapers and More

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds