在ATL DLL中傳遞C++對象

來源:互聯網
上載者:User
介面的限制:
    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 archivevoid 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 objectvoid CSimpleObj::Show(){ AfxMessageBox(m_strData);}// save a string in data membervoid 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 SAFEARRAYBOOL 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/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.