在ATL DLL中传递C++对象

接口的限制:
    COM要求客户和服务器高度的分离,这已经由接口实现了,但是现在问题是,接口方法只提供了有限的几种数据类型. 如果接口是基于IDispatch的,我们的选择更加有限.请记住这些限制,  C++对象只在下面几种情况下可以传递:
    1. 客户和服务都是VC编译的;
    2. 他们必须有共同的对象的定义,比如相同的头文件;
    3. 通过传递C++对象简化应用的设计;
    4. 在分布式环境中,需要注意你的COM必须具备远程激活, 本地/远程透明性, 安全性登方面的特性.
下面是一个例子:

    1. 生成一个ATL  DLL服务器
    2. 添加一个继承于CObject的类.
    3. 在类的头文件中加上DECLARE_SERIAL
    4. 在类的CPP文件中加上IMPLEMENT_SERIAL
    5. 重载Serialize方法

//  你的CSimpleObj类看起来这样子的
class CSimpleObj : public CObject { DECLARE_SERIAL( CSimpleObj ) public: // constructor and destructor CSimpleObj(); virtual ~CSimpleObj(); // 设置内部的字符串
void SetString( CString csData ); // 用于串行化你的数据
virtual void Serialize(CArchive& ar); // 显示数据
void Show(); private: CString m_strData;//这里定义一个字符串对象
}; // Write this object to an archive void CSimpleObj::Serialize(CArchive& ar) { CObject::Serialize( ar ); if (ar.IsLoading()) { // extract data from archive ar >> m_strData; } else { // store data into archive ar << m_strData; } } // Method to display data in this object void CSimpleObj::Show() { AfxMessageBox(m_strData); } // save a string in data member void CSimpleObj::SetString(CString csData) { m_strData = csData; }
6. 下一步我们通过CArchive存取对象,这里用了另外一个类CBlob.
class CBlob
{
public:
  CBlob() {};
  virtual ~CBlob() {};

  // Extract data from a CObject and load it into a SAFEARRAY.
  SAFEARRAY* Load( CObject *pObj );
  // Re-create an object from a SAFEARRAY
  BOOL Expand( CObject * &pObj, SAFEARRAY *pVar );
private:
};

// Extract data from a CObject and use it to create a SAFEARRAY.
SAFEARRAY* CBlob::Load( CObject *pObj)
{
  CMemFile memfile;      // memory file

  // define the flag that tells the archive whether it should 
  // load or store
  long lMode = CArchive::store | CArchive::bNoFlushOnDelete;
  // create the archive using the memory file
  CArchive ar(&memfile, lMode );

  // m_pDocument is not used
  ar.m_pDocument = NULL;
  // serialize the object into the archive
  ar.WriteObject(pObj);
  // close the archive -- the data is now stored in memfile
  ar.Close();

  // get the length (in bytes) of the memory file
  long llen = memfile.GetLength();

  // detach the buffer and close the file
  unsigned char *pMemData = memfile.Detach();

  // set up safearray
  SAFEARRAY *psa;

  // create a safe array to store the stream data
  psa = SafeArrayCreateVector( VT_UI1, 0, llen );

  // pointers to byte arrays
  unsigned char *pData = NULL;

  // get a pointer to the safe array. Locks the array.
  SafeArrayAccessData( psa, (void**)&pData );

  // copy the memory file into the safearray
  memcpy( pData, pMemData, llen );

  // clean up buffer
  delete pMemData;

  // unlock access to safearray
  SafeArrayUnaccessData(psa);

  // return a pointer to a SAFEARRAY allocated here
  return psa;
}

// Re-create an object from a SAFEARRAY
BOOL CBlob::Expand(CObject * &rpObj, SAFEARRAY *psa)
{
  CMemFile memfile;          // memory file for de-serailze
  long lLength;              // number of bytes
  char *pBuffer;             // buffer pointer

  // lock access to array data
  SafeArrayAccessData( psa, (void**)&pBuffer );

  // get number of elements in array. This is the number of bytes
  lLength = psa->rgsabound->cElements;

  // attach the buffer to the memory file
  memfile.Attach((unsigned char*)pBuffer, lLength);

  // start at beginning of buffer
  memfile.SeekToBegin();

  // create an archive with the attached memory file
  CArchive ar(&memfile, CArchive::load | CArchive::bNoFlushOnDelete);

  // document pointer is not used
  ar.m_pDocument = NULL;

  // inflate the object and get the pointer
  rpObj = ar.ReadObject(0);

  // close the archive
  ar.Close();

  // Note: pBuffer is freed when the SAFEARRAY is destroyed
  // Detach the buffer and close the file
  pBuffer = (char*) memfile.Detach();

  // release the safearray buffer
  SafeArrayUnaccessData( psa );

  return TRUE;
}
这里用了SAFEARRAY ,是比较适合我们的目的的,它能够容纳复杂的多维数组,这里我们只用了一个很简单的数组. 但是对于SAFEARRAY 有一个问题,MIDL 不认识这种类型,最简单的办法是用VARIANT 类型.

下面几步:
1.  生成一个COM接口,
2. 生成一个SAFEARRAY对象
3.  在IDL文件里 定义2个方法:
 [helpstring("method SetArray")] HRESULT SetArray([in]SAFEARRAY unsigned char) pData);
[helpstring("method GetArray")] HRESULT GetArray([out/*,retval*/]SAFEARRAY(unsigned char) *pData);
4. 生成一个基于MFC的客户端进行测试

IDL文件看起来这样的:
    interface IBolbData : IUnknown
  {
    [helpstring("method SetArray")] HRESULT SetArray([in]SAFEARRAY
      (unsigned char) pData);
    [helpstring("method GetArray")] HRESULT GetArray([out/*,retval*/]
      SAFEARRAY(unsigned char) *pData);
  };

// Sets object.
STDMETHODIMP CBolbData::SetArray(SAFEARRAY *pData)
{
  AFX_MANAGE_STATE(AfxGetStaticModuleState())

  // create a dummy pointer of CSimpleObj
  CSimpleObj *dummy=NULL;
  // create blob obect to expand/deserialize
  CBlob blob;
  // Init dummy object using safe array through this function
  blob.Expand( (CObject*&)dummy, pData );
  dummy->Show();  // Call show function to test the object.
  delete dummy;      // Delete the pointer.

  return S_OK;
}

// Creates Object and sends to client.
STDMETHODIMP CBolbData::GetArray(SAFEARRAY **pData)
{
  AFX_MANAGE_STATE(AfxGetStaticModuleState())
  // create object to send to server
  CSimpleObj *pMyOb = new CSimpleObj();

  // set the string data
  pMyOb->SetString( "A SAFEARRAY from the server!" );

  // create blob to serialize object
  CBlob blob;

  // load the object into the blob
  *pData = blob.Load( pMyOb );
  // delete the pMyOb pointer
  delete pMyOb;

  return S_OK;
}

最后,我们做一个带有2个按钮的对话框应用程序, 2个按钮的响应方法是:
void CClientDlg::OnOK()
{
// create COM smart pointer from CLSID string
  try
  {
    IBolbDataPtr pI( "Server.BolbData.1" );
    SAFEARRAY *psa ;

    // Get the safearray from the server
    pI->GetArray( &psa );

    // create a pointer to an object
    CSimpleObj *dummy=NULL;

    // blob object to expand
    CBlob blob;

    // use the blob to expand the safearray into an object
    blob.Expand( (CObject *&)dummy, psa );
    // call a method on the object to test it
    dummy->Show();

    // delete the object
    delete dummy;
  }
  // Handle any COM exceptions from smart pointers
  catch (_com_error e)
  {
    // display the message string from the error
    AfxMessageBox( e.ErrorMessage() );
  }
}

void CClientDlg::OnLoad()
{
  try
  {
    // create smart pointer from CLSID string
    IBolbDataPtr pI( "Server.BolbData.1" );
    SAFEARRAY *psa ;

    // create object to send to server
    CSimpleObj *pMyOb = new CSimpleObj();

    // set the string data
    pMyOb->SetString( "The client sent a SAFEARRAY!" );

    // create blob to serialize object
    CBlob blob;

    // load the object into the blob
    psa = blob.Load( pMyOb );

    // delete the object
    delete pMyOb;

    pI->SetArray( psa );

  }
  // Handle any COM exceptions from smart pointers
  catch (_com_error e)
  {
    // display the message string from the error
    AfxMessageBox( e.ErrorMessage() );
  }
}
这个例子里涵盖的内容比较多,包括了如何使用串行化,如何使用安全数组,如何通过接口传递C++对象.

作者原贴在这里:
http://www.codeguru.com/Cpp/COM-Tech/atl/atl/article.php/c3587/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值