COM Tip(2)
2011-06-12 13:37 Clingingboy 阅读(555) 评论(0) 编辑 收藏 举报
一.使用IDispatch
interface IRandom : IDispatch
{
import "oaidl.idl";
[id(0)]
HRESULT Start([out]long* pnID);
[id(1)]
HRESULT Stop([in]long nID);
[id(2)]
HRESULT StopAll();
};
使用GetIDsOfNames获取DISP
OLECHAR *fn=L"Stop";
DISPID id;
pRandom->GetIDsOfNames(IID_NULL,&fn,1,GetUserDefaultLCID(),&id);
使用Invoke动态调用函数
VARIANT var;
::VariantInit(&var);
var.lVal=2;
DISPPARAMS params;
params.cArgs=1;
params.rgvarg=&var;
pRandom->Invoke(id,IID_NULL,GetUserDefaultLCID(),DISPATCH_METHOD,
¶ms,NULL,NULL,NULL);
跟反射的概念完全是一样的
二.IDispatchImpl
ATL中,IDispatchImpl实现了IDispatch
class CRandom :
public IDispatchImpl<IRandom, &IID_IRandom, &LIBID_CONNECTLib>,
{
public:
CRandom()
{
}
~CRandom();
BEGIN_COM_MAP(CRandom)
COM_INTERFACE_ENTRY2(IDispatch, IRandom)
COM_INTERFACE_ENTRY(IRandom)
END_COM_MAP()
}
三.实现连接点
1.实现IConnectionPointContainerImpl和IConnectionPointImpl
class CRandom :
public IConnectionPointContainerImpl<CRandom>,
public IConnectionPointImpl<CRandom, &IID_IRandomEvent, {
public:
CRandom()
{
}
~CRandom();
BEGIN_COM_MAP(CRandom)
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()
// Connection Point
BEGIN_CONNECTION_POINT_MAP(CRandom)
CONNECTION_POINT_ENTRY(IID_IRandomEvent)
END_CONNECTION_POINT_MAP()
}
2.在客户端调用方实现IRandomEvent接口(接收器)
class CDriver :
public IDispatchImpl<IRandomEvent, &IID_IRandomEvent, &LIBID_CONNECTLib>,
public CComObjectRoot
{
public:
CDriver() {}
BEGIN_COM_MAP(CDriver)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IRandomEvent)
END_COM_MAP()
// IRandomEvent
STDMETHOD(Fire)(long l);
public:
};
3.客户端创建连接点进行监听
CComObject<CDriver>* pDriver;
CComObject<CDriver>::CreateInstance(&pDriver);
pDriver->m_nID = m_nAdviseCnt;
HRESULT hRes = AtlAdvise(pRandom, pDriver->GetUnknown(), IID_IRandomEvent, &m_arrAdvise[m_nAdviseCnt++]);
4.服务器端进行回调
IConnectionPointImpl<CRandom, &IID_IRandomEvent, CComDynamicUnkArray>* p = this;
Lock();
HRESULT hr = S_OK;
IUnknown** pp = p->m_vec.begin();
while (pp < p->m_vec.end() && hr == S_OK)
{
if (*pp != NULL)
{
IRandomEvent* pIRandomEvent = (IRandomEvent*)*pp;
hr = pIRandomEvent->Fire(nID);
}
pp++;
}
5.自动生成连接点代理
第4步可以用vs自动生成代码,如果事件很多(而且客户端可以多次监听),写这些重复的代码是没有必要的
template<class T>
class CProxyIRandomEvent :
public ATL::IConnectionPointImpl<T, &__uuidof(IRandomEvent)>
{
public:
HRESULT Fire_Fire(long nID)
{
HRESULT hr = S_OK;
T * pThis = static_cast<T *>(this);
int cConnections = m_vec.GetSize();
for (int iConnection = 0; iConnection < cConnections; iConnection++)
{
pThis->Lock();
CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
pThis->Unlock();
IRandomEvent * pConnection = static_cast<IRandomEvent *>(punkConnection.p);
if (pConnection)
{
hr = pConnection->Fire(nID);
}
}
return hr;
}
};
class CRandom :
public IDispatchImpl<IRandom, &IID_IRandom, &LIBID_CONNECTLib>,
public IConnectionPointContainerImpl<CRandom>,
public CProxyIRandomEvent<CRandom>
{
public:
CRandom()
{
}
~CRandom();
// Connection Point1
BEGIN_CONNECTION_POINT_MAP(CRandom)
CONNECTION_POINT_ENTRY(__uuidof(IRandomEvent))
END_CONNECTION_POINT_MAP()
让CRandom 继承自CProxyIRandomEvent,去掉之前的IConnectionPointImpl
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2010-06-12 WPF依赖属性(续)(3)依赖属性存储