分类: C/C++
2008-04-23 21:53:05
向ATL DLL中传递C 对象
原著:Uttam Kumar
翻译:
原文出处:
简介
几个星期以前,我拼命的寻找一个能够通过COM接口传递C 对象的例子,但是,没有找到.这就是我发表这篇文章的原因。
向ATL的DLL中传递一个C 对象参数并不是非常之难,但是,当然也会有点难度,也很有趣。
在开始一个工程以前,首先你得确信客户机和服务器组件都是适应C 的程序,其次,你必须知道怎样设置你的客户机和服务器。
接口的局限性
COM技术要求客户机和服务器高度的分离,这是通过接口实现的,但是问题出在:接口的方法中只提供了有限个参数数据类型,如果这个接口是基于IDispatch的,参数类型的可选范围就更加受到限制了,由于这些局限性,C 对象只有在满足以下条件时才能够传递:
我建议,在开始工作之前,先顺序的看一下各个标题,现在,我列出实例,并作以下事情:
// 你的 CSimpleObj 类应该像这样: 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; }
class CBlob { public: CBlob() {}; virtual ~CBlob() {}; // 从一个 CObject对象中提取数据并载入到一个 SAFEARRAY对象中. SAFEARRAY* Load( CObject *pObj ); // 重新创建一个SAFEARRAY对象 BOOL Expand( CObject * &pObj, SAFEARRAY *pVar ); private: }; // 从一个 CObject对象中提取数据并用它构建一个 SAFEARRAY对象. SAFEARRAY* CBlob::Load( CObject *pObj) { CMemFile memfile; // 内存文件 // 定义一个用来标记档案文件是读取还是存储的标志 long lMode = CArchive::store | CArchive::bNoFlushOndelete; // 用内存文件创建档案文件 CArchive ar(&memfile, lMode ); // m_pDocument 不使用 ar.m_pDocument = NULL; // 序列化对象到档案文件中 ar.WriteObject(pObj); // 关闭档案文件--现在,数据在内存文件中 ar.Close(); // 取得内存文件的长度(以字节为单位) long llen = memfile.GetLength(); // 释放缓冲区 关闭文件 unsigned char *pMemData = memfile.Detach(); // 设定safearray SAFEARRAY *psa; // 创建safearray对象存取流数据 psa = SafeArrayCreateVector( VT_UI1, 0, llen ); // 指向字节数组的指针 unsigned char *pData = NULL; // 取得一个 safe array的指针. 锁定数组. SafeArrayAccessData( psa, (void**)&pData ); // 拷贝内存文件到 safearray memcpy( pData, pMemData, llen ); // 清理缓冲区 delete pMemData; // 锁定对 safearray的访问 SafeArrayUnaccessData(psa); // 返回一个在这分配的SAFEARRAY的指针 return psa; } // 重新创建一个SAFEARRAY对象 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(); // 注意: 当SAFEARRAY被毁坏时 pBuffer 被释放 // 释放缓冲区 关闭文件 pBuffer = (char*) memfile.Detach(); // 释放safearray 缓冲区 SafeArrayUnaccessData( psa ); return TRUE; }
[helpstring("method SetArray")] HRESULT SetArray([in]SAFEARRAY (unsigned char) pData);[helpstring("method GetArray")] HRESULT GetArray([out/*,retval*/]SAFEARRAY(unsigned char) *pData);
interface IBolbData : IUnknown { [helpstring("method SetArray")] HRESULT SetArray([in]SAFEARRAY (unsigned char) pData); [helpstring("method GetArray")] HRESULT GetArray([out/*,retval*/] SAFEARRAY(unsigned char) *pData); }; // 设定对象 STDMETHODIMP CBolbData::SetArray(SAFEARRAY *pData) { AFX_MANAGE_STATE(AfxGetStaticModuleState()) // 创建CSimpleObj的亚元指针 CSimpleObj *dummy=NULL; // 创建 blob 对象 用来填充、反序列化 CBlob blob; // 使用 safearray 创建亚元对象 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!" ); // 创建blob来序列化对象 CBlob blob; // 将对象载入blob *pData = blob.Load( pMyOb ); // 删除pMyOb指针 delete pMyOb; return S_OK; }最后,写一个有两个按钮的基于对话框的 MFC 应用程序 并添加如下代码:
void CClientDlg::OnOK() { // 从CLSID串创建COM智能指针 try { IBolbDataPtr pI( "Server.BolbData.1" ); SAFEARRAY *psa ; // 从服务器取得 safearray pI->GetArray( &psa ); // 创建指针 CSimpleObj *dummy=NULL; // blob 对象 CBlob blob; //使用blob 扩展 safearray 到一个对象里 blob.Expand( (CObject *&)dummy, psa ); //通过调用一个对象的方法来测试它 dummy->Show(); // 删除对象 delete dummy; } // 通过智能指针处理任意 COM 异常 catch (_com_error e) { // 显示错误信息 AfxMessageBox( e.ErrorMessage() ); } } void CClientDlg::OnLoad() { try { // 从CLSID 串创建智能指针 IBolbDataPtr pI( "Server.BolbData.1" ); SAFEARRAY *psa ; // 创建送给服务器的对象 CSimpleObj *pMyOb = new CSimpleObj(); // 设置字符串数据 pMyOb->SetString( "The client sent a SAFEARRAY!" ); // 创建 blob 用来序列化对象 CBlob blob; // 将对象载入到 blob psa = blob.Load( pMyOb ); //删除对象 delete pMyOb; pI->SetArray( psa ); } catch (_com_error e) { // 显示错误信息 AfxMessageBox( e.ErrorMessage() ); } }总结