接口的限制: COM要求客户和服务器高度的分离,这已经由接口实现了,但是现在问题是,接口方法只提供了有限的几种数据类型. 如果接口是基于IDispatch的,我们的选择更加有限.请记住这些限制, C++对象只在下面几种情况下可以传递: 1. 客户和服务都是VC编译的; 2. 他们必须有共同的对象的定义,比如相同的头文件; 3. 通过传递C++对象简化应用的设计; 4. 在分布式环境中,需要注意你的COM必须具备远程激活, 本地/远程透明性, 安全性登方面的特性. 下面是一个例子:
1. 生成一个ATL DLL服务器 2. 添加一个继承于CObject的类. 3. 在类的头文件中加上DECLARE_SERIAL 4. 在类的CPP文件中加上IMPLEMENT_SERIAL 5. 重载Serialize方法
class CSimpleObj : public CObject
{
DECLARE_SERIAL( CSimpleObj )
public:
CSimpleObj();
virtual ~CSimpleObj();
void SetString( CString csData );
virtual void Serialize(CArchive& ar);
void Show();
private:
CString m_strData;//这里定义一个字符串对象 };
void CSimpleObj::Serialize(CArchive& ar)
{
CObject::Serialize( ar );
if (ar.IsLoading())
{
ar >> m_strData;
}
else
{
ar << m_strData;
}
}
void CSimpleObj::Show()
{
AfxMessageBox(m_strData);
}
void CSimpleObj::SetString(CString csData)
{
m_strData = csData;
}
6. 下一步我们通过CArchive存取对象,这里用了另外一个类CBlob.
class CBlob
{
public:
CBlob() {};
virtual ~CBlob() {};
SAFEARRAY* Load( CObject *pObj );
BOOL Expand( CObject * &pObj, SAFEARRAY *pVar );
private:
};
SAFEARRAY* CBlob::Load( CObject *pObj)
{
CMemFile memfile;
long lMode = CArchive::store | CArchive::bNoFlushOnDelete;
CArchive ar(&memfile, lMode );
ar.m_pDocument = NULL;
ar.WriteObject(pObj);
ar.Close();
long llen = memfile.GetLength();
unsigned char *pMemData = memfile.Detach();
SAFEARRAY *psa;
psa = SafeArrayCreateVector( VT_UI1, 0, llen );
unsigned char *pData = NULL;
SafeArrayAccessData( psa, (void**)&pData );
memcpy( pData, pMemData, llen );
delete pMemData;
SafeArrayUnaccessData(psa);
return psa;
}
BOOL CBlob::Expand(CObject * &rpObj, SAFEARRAY *psa)
{
CMemFile memfile;
long lLength;
char *pBuffer;
SafeArrayAccessData( psa, (void**)&pBuffer );
lLength = psa->rgsabound->cElements;
memfile.Attach((unsigned char*)pBuffer, lLength);
memfile.SeekToBegin();
CArchive ar(&memfile, CArchive::load | CArchive::bNoFlushOnDelete);
ar.m_pDocument = NULL;
rpObj = ar.ReadObject(0);
ar.Close();
pBuffer = (char*) memfile.Detach();
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] SAFEARRAY(unsigned char) *pData); };
STDMETHODIMP CBolbData::SetArray(SAFEARRAY *pData) { AFX_MANAGE_STATE(AfxGetStaticModuleState())
CSimpleObj *dummy=NULL; CBlob blob; blob.Expand( (CObject*&)dummy, pData ); dummy->Show(); delete dummy;
return S_OK; }
STDMETHODIMP CBolbData::GetArray(SAFEARRAY **pData) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) CSimpleObj *pMyOb = new CSimpleObj();
pMyOb->SetString( "A SAFEARRAY from the server!" );
CBlob blob;
*pData = blob.Load( pMyOb ); delete pMyOb;
return S_OK; }
最后,我们做一个带有2个按钮的对话框应用程序, 2个按钮的响应方法是: void CClientDlg::OnOK() {
try { IBolbDataPtr pI( "Server.BolbData.1" ); SAFEARRAY *psa ;
pI->GetArray( &psa );
CSimpleObj *dummy=NULL;
CBlob blob;
blob.Expand( (CObject *&)dummy, psa ); dummy->Show();
delete dummy; } catch (_com_error e) { AfxMessageBox( e.ErrorMessage() ); } }
void CClientDlg::OnLoad() { try { IBolbDataPtr pI( "Server.BolbData.1" ); SAFEARRAY *psa ;
CSimpleObj *pMyOb = new CSimpleObj();
pMyOb->SetString( "The client sent a SAFEARRAY!" );
CBlob blob;
psa = blob.Load( pMyOb );
delete pMyOb;
pI->SetArray( psa );
} catch (_com_error e) { AfxMessageBox( e.ErrorMessage() ); } } 这个例子里涵盖的内容比较多,包括了如何使用串行化,如何使用安全数组,如何通过接口传递C++对象.
作者原贴在这里: http://www.codeguru.com/Cpp/COM-Tech/atl/atl/article.php/c3587/ 
|