组件回调的问题. 请问COM组件的回调有哪些方式?怎样实现? 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 1.可以定义一个interface实现回调: 在COM外部实现这个接口,将这个接口做为一个参数传给COM内部,COM内部就可以调用这个接口的方法(其实是做为回调来用的),你在接口的方法里处理你的回调.2.传来个LONG参数给COM,在COM里强行转化成回调函数指针,这个方法比较不可靠,如果COM给其它语言用的时候不能保证对于RPC的回调我还不会! COM中的回调有两种,一种是接口回调,例子代码如下:a) 新建一个新的ATL工程Com06b) 插入一个ATL对象(Math)其它全部采用缺省值c) 在IMath接口中增加方法(Add([in]long var1,[in]long var2,[out,retval])long* pVal)并实现之。(*pVal=var1+var2;)d) 在CMath类下创建一个成员变量ICallBack* m_pCallBack;并在构造函数中初始化为0;e) 增加另外一个方法Advise([in]ICallBack* pCallBack )STDMETHODIMP CMath::Advise(ICallBack *pCallBack){ m_pCallBack=pCallBack; m_pCallBack->AddRef(); return S_OK;}f) 增加一个方法Unadvise()STDMETHODIMP CMath::Unadvise(){ m_pCallBack->Release(); m_pCallBack=0; return S_OK;}g) 定义引出接口,在接口定义文件中增加如下内容 [ object, uuid(2EA18575-2C16-424B-9DA7-D2A6B1BDB4A3), helpstring("ICallBack Interface") ] interface ICallBack : IUnknown { [helpstring("method Complete")] HRESULT Complete([in]long lResult); };h) 重新写Add()方法如下:STDMETHODIMP CMath::Add(long var1, long var2, long *pVal){ *pVal=var1+var2; m_pCallBack->Complete(*pVal); return S_OK;}到此为止,服务端写完4、 用VC写一个客户端程序a) 首先新建一个类,存放在文件a.h中,如下内容如下所示:#include "..\Com06\Com06.h"class CCallBack:ICallBack{public: long nCount; CCallBack() { nCount=0; } HRESULT _stdcall QueryInterface(REFIID riid,void** ppvObject) { if(riid==IID_ICallBack) *ppvObject=(ICallBack*)this; else *ppvObject=(IUnknown*)(ICallBack*)this; return S_OK; } ULONG _stdcall AddRef() { return ++nCount; } ULONG _stdcall Release() { --nCount; if(nCount==0) { delete this; return 0; } return nCount; } HRESULT _stdcall Complete(long lResult) { CString str; str.Format("%d",lResult); MessageBox(0,str,"Msg",MB_OK); return S_OK; }};b) 在对话框类中增加一个新的成员变量如下:IMath* pIMath;,在头文件中增加相应的头文件a.hc) 在话框的初始化函数中增加如下代码,实现接口的登记 ICallBack* pICallBack; CCallBack* pCallBack=new CCallBack; pCallBack->QueryInterface(IID_ICallBack,(void**)&pICallBack); ::CoInitialize(NULL); ::CoCreateInstance(CLSID_Math,NULL,1,IID_IMath,(void**)&pIMath); pIMath->Advise(pICallBack);d) 在Button1的事件处理代码中增加如下代码,调用COM组件中的方法 long value; pIMath->Add(12,34,&value);e) 在对话框的关闭函数中增加如下代码,取消登记及相应接口指针的释放。void CCom06CliDlg::OnClose() { pIMath->Unadvise(); pIMath->Release(); CDialog::OnClose();} 到此为止整个VC下的回调过程实现另外一种就是连接点了,其实这两种差不太多, 还是连接点,应该必须是连接点,楼上所说的方法适用与同一进程的com组件如果,是其他的现成模式,这么做会会产生不可预料的后果,(比如是内存违规访问) 不一定要连接点,如果你的组件并不打算给别人在诸如VB的编程环境中使用, 你可以简单地接收一个接口,并调用这个接口的方法.COM规范没有阻止你这么使用.我曾经做过这样的例子.不过这么用如果客户端阻塞, 会造成服务器也阻塞.如果需要异步调用,可以用COM+的事件代替.不要使用自由线程模型. 补充: 强制转换函数指针是不对的. 即时是在同一个进程内,也不应该使用. 还会有线程等很多问题,一个C语言的函数指针对VB是没有意义的 不考虑其他的语言调用,进程服务器版本,使用从C++调用,的话可以使用Up的方法,不过那个时候需要使用com吗? msdn上的一个例子、请达者帮忙参考下、怎么修改; 在公司实习2个月后,公司给我看一个程序代码,请指教 如何根据数据库来建立文件目录 关于一本书上的问题 在基于SDI的程序中,将基类设为CScrollView类的问题求救,thx 设计一个OCX控件,如何使控件窗口区能弹出右键菜单? 寻求visual studio 97 开发工具,有的话,给我个地址,谢谢! 请高手帮忙,100分等你拿! 如何编程生成数字证书?或者经过MD5签名的文件? 一个郁闷的问题 请教:如果项目中包含了资源文件,编译后,制作成安装程序好,资源文件可以找到吗? 串口通信的超时结构的问题,在线等(云台控制)
在COM外部实现这个接口,将这个接口做为一个参数传给COM内部,COM内部就可以调用这个接口的方法(其实是做为回调来用的),你在接口的方法里处理你的回调.
2.传来个LONG参数给COM,在COM里强行转化成回调函数指针,这个方法比较不可靠,如果COM给其它语言用的时候不能保证对于RPC的回调我还不会!
a) 新建一个新的ATL工程Com06
b) 插入一个ATL对象(Math)其它全部采用缺省值
c) 在IMath接口中增加方法(Add([in]long var1,[in]long var2,[out,retval])long* pVal)并实现之。(*pVal=var1+var2;)
d) 在CMath类下创建一个成员变量ICallBack* m_pCallBack;并在构造函数中初始化为0;
e) 增加另外一个方法Advise([in]ICallBack* pCallBack )
STDMETHODIMP CMath::Advise(ICallBack *pCallBack)
{
m_pCallBack=pCallBack;
m_pCallBack->AddRef();
return S_OK;
}
f) 增加一个方法Unadvise()
STDMETHODIMP CMath::Unadvise()
{
m_pCallBack->Release();
m_pCallBack=0;
return S_OK;
}
g) 定义引出接口,在接口定义文件中增加如下内容
[
object,
uuid(2EA18575-2C16-424B-9DA7-D2A6B1BDB4A3),
helpstring("ICallBack Interface")
]
interface ICallBack : IUnknown
{
[helpstring("method Complete")] HRESULT Complete([in]long lResult);
};
h) 重新写Add()方法如下:
STDMETHODIMP CMath::Add(long var1, long var2, long *pVal)
{
*pVal=var1+var2;
m_pCallBack->Complete(*pVal);
return S_OK;
}
到此为止,服务端写完
4、 用VC写一个客户端程序
a) 首先新建一个类,存放在文件a.h中,如下内容如下所示:
#include "..\Com06\Com06.h"
class CCallBack:ICallBack
{
public:
long nCount;
CCallBack()
{
nCount=0;
}
HRESULT _stdcall QueryInterface(REFIID riid,void** ppvObject)
{
if(riid==IID_ICallBack)
*ppvObject=(ICallBack*)this;
else
*ppvObject=(IUnknown*)(ICallBack*)this;
return S_OK;
}
ULONG _stdcall AddRef()
{
return ++nCount;
}
ULONG _stdcall Release()
{
--nCount;
if(nCount==0)
{
delete this;
return 0;
}
return nCount;
}
HRESULT _stdcall Complete(long lResult)
{
CString str;
str.Format("%d",lResult);
MessageBox(0,str,"Msg",MB_OK);
return S_OK;
}
};
b) 在对话框类中增加一个新的成员变量如下:IMath* pIMath;,在头文件中增加相应的头文件a.h
c) 在话框的初始化函数中增加如下代码,实现接口的登记
ICallBack* pICallBack;
CCallBack* pCallBack=new CCallBack;
pCallBack->QueryInterface(IID_ICallBack,(void**)&pICallBack);
::CoInitialize(NULL);
::CoCreateInstance(CLSID_Math,NULL,1,IID_IMath,(void**)&pIMath);
pIMath->Advise(pICallBack);
d) 在Button1的事件处理代码中增加如下代码,调用COM组件中的方法
long value;
pIMath->Add(12,34,&value);
e) 在对话框的关闭函数中增加如下代码,取消登记及相应接口指针的释放。
void CCom06CliDlg::OnClose()
{
pIMath->Unadvise();
pIMath->Release();
CDialog::OnClose();
}
到此为止整个VC下的回调过程实现另外一种就是连接点了,其实这两种差不太多,
如果,是其他的现成模式,这么做会会产生不可预料的后果,(比如是内存违规访问)
不要使用自由线程模型.
Up的方法,不过那个时候需要使用com吗?