接口的限制: 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类看起来这样子的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个按钮的响应方法是: |
在ATL DLL中传递C++对象
最新推荐文章于 2024-01-03 10:11:46 发布