我编写了一个进程外COM组件svr.exe。
在一个局域网内,我把svr.exe部署在我的计算机上。
又编写了一个客户程序callSvr.exe,部署在其他的计算机上。 现在,callsvr可以正常的访问到svr.exe中的方法。
接下来我需要给svr.exe添加事件回调,让它可以把事件通知给客户程序。
事件回调的方法是学习vckbase网站上的文章做的,其网址如下:
http://www.vckbase.com/document/viewdoc/?id=1525 我在svr.exe中定义了一个接口方法SetCBFun,客户程序可以调用此函数来设置“事件回调函数”。
在客户程序中,调用如下代码来设置回调函数的地址:
hr = pBackupAdmin->SetCBFun(&m_sink); 其中,m_sink是CSink m_sink对象变量。CSink是客户程序中自定义的一个类,它派生于ICallBack。而ICallBack是我在svr.exe中手工定义的一个接口,具体的代码我是参照vckbase网站提供的方法写的。 现在的问题是:我在调用pBackupAdmin->SetCBFun函数时出错,我跟踪调试进入SetCBFun函数中,进入了一个扩展名为tli的文件(是系统自动生成的)。在这个文件的SetCBFun函数中,当执行完HRESULT _hr = raw_SetCBFun(pCallBack)后,_hr等于0xc0000005。我用Error Lookup查找,也无法得知是什么错误,而继续执行下一条语句时就蹦异常了:
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this)); 我也跟踪调试了vckbase网站的代码,而人家的代码就不出错,直接执行到COM组件服务的SetCBFun函数中了。我想,很可能是因为我的COM组件是远程调用的,在经过代理proxy.dll时出错了。是不是跨进程传输数据时哪里的数据没有兼容好啊? 请高手帮忙解释一下。多谢了。另外,我这里用的方法不是“事件连接点”的方法。难道必须使用“事件连接点”才可以?
在一个局域网内,我把svr.exe部署在我的计算机上。
又编写了一个客户程序callSvr.exe,部署在其他的计算机上。 现在,callsvr可以正常的访问到svr.exe中的方法。
接下来我需要给svr.exe添加事件回调,让它可以把事件通知给客户程序。
事件回调的方法是学习vckbase网站上的文章做的,其网址如下:
http://www.vckbase.com/document/viewdoc/?id=1525 我在svr.exe中定义了一个接口方法SetCBFun,客户程序可以调用此函数来设置“事件回调函数”。
在客户程序中,调用如下代码来设置回调函数的地址:
hr = pBackupAdmin->SetCBFun(&m_sink); 其中,m_sink是CSink m_sink对象变量。CSink是客户程序中自定义的一个类,它派生于ICallBack。而ICallBack是我在svr.exe中手工定义的一个接口,具体的代码我是参照vckbase网站提供的方法写的。 现在的问题是:我在调用pBackupAdmin->SetCBFun函数时出错,我跟踪调试进入SetCBFun函数中,进入了一个扩展名为tli的文件(是系统自动生成的)。在这个文件的SetCBFun函数中,当执行完HRESULT _hr = raw_SetCBFun(pCallBack)后,_hr等于0xc0000005。我用Error Lookup查找,也无法得知是什么错误,而继续执行下一条语句时就蹦异常了:
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this)); 我也跟踪调试了vckbase网站的代码,而人家的代码就不出错,直接执行到COM组件服务的SetCBFun函数中了。我想,很可能是因为我的COM组件是远程调用的,在经过代理proxy.dll时出错了。是不是跨进程传输数据时哪里的数据没有兼容好啊? 请高手帮忙解释一下。多谢了。另外,我这里用的方法不是“事件连接点”的方法。难道必须使用“事件连接点”才可以?
SetCBFun应该传递两个参数吧,你怎么只有一个啊,
一个是地址,另外一个是会话COOKID
而我现在是“在远程调用时,代理和存根在传输ICallBack接口时”出现了异常。
猜想是代理在解析远程进程外组件对象的接口时出现的问题。
不知道猜的对不对,而且也不知道如何解决。
interface ICallBack : IUnknown
{ [id(1), helpstring("method CBFun_InState")] HRESULT CBFun_InState([in] LONG nInID, [in] LONG nDecoderID, [in] LONG nInIndex, [in] LONG nState);
};组件对象类中,SetCBFun函数的实现
STDMETHODIMP CAlarmSrv::SetCBFun(ICallBack *pCallBack)
{
if( NULL == pCallBack ) // 居然给我一个空指针?!
return E_INVALIDARG;
m_pCallBack = pCallBack; // 保存 return S_OK;
}客户端-----调用COM组件的代码:
// 创建远程COM组件
hr = CoCreateInstanceEx(clsid, NULL, CLSCTX_REMOTE_SERVER, &servInf, 1, &qi);
if (FAILED(hr))
{
AfxMessageBox("CoCreateInstanceEx失败");
return FALSE;;
}
if (FAILED(qi.hr))
{
AfxMessageBox("COM库连接失败");
return FALSE;;
}
// 获得组件的指针
IArmSrv* pBackupAdmin = (IArmSrv*)qi.pItf; // Retrieve first interface pointer. // 调用组件的接口方法
hr = pBackupAdmin->Init();
if (hr != S_OK)
{
AfxMessageBox("调用接口方法失败");
return;
}
// 我的程序可以执行到这里,之前的代码都没有发生错误。 // 设置回调事件函数
hr = pBackupAdmin->SetCBFun(&m_sink);// 程序执行到这一行就异常了
pBackupAdmin->Release();
//
//////////////////////////////////////////////////////////////////////#if !defined(AFX_SINK_H__C77F3B61_D82C_4C16_A9C9_21FD64ED0423__INCLUDED_)
#define AFX_SINK_H__C77F3B61_D82C_4C16_A9C9_21FD64ED0423__INCLUDED_#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000class CSink : public ICallBack
{
public:
CSink();
virtual ~CSink();
// STDMETHOD(xx) 是宏,等价于 long __stdcall xx
STDMETHOD(QueryInterface)(const struct _GUID &iid,void ** ppv);
ULONG __stdcall CSink::AddRef(void);
ULONG __stdcall CSink::Release(void);
STDMETHOD(raw_CBFun)(long,long,long,long);};#endif // !defined(AFX_SINK_H__C77F3B61_D82C_4C16_A9C9_21FD64ED0423__INCLUDED_)
sink.cpp// Sink.cpp: implementation of the CSink class.
//
//////////////////////////////////////////////////////////////////////#include "stdafx.h"
#include "CallLocalOpcSrv.h"
#include "Sink.h"#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////CSink::CSink()
{}CSink::~CSink()
{}// STDMETHODIMP 是宏,等价于 long __stdcall
STDMETHODIMP CSink::QueryInterface(const struct _GUID &iid,void ** ppv)
{
*ppv=this;
return S_OK;
}ULONG __stdcall CSink::AddRef(void)
{ return 1; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的ULONG __stdcall CSink::Release(void)
{ return 0; } // 做个假的就可以,因为反正这个对象在程序结束前是不会退出的STDMETHODIMP CSink::raw_CBFun(long nInID, long nDecoderID,
long nInIndex, long nState)
{
AfxMessageBox("收到远程组件的消息。");
return S_OK;
}
而不是raw_CBFun
sorry,应该是raw_CBFun_InState,我在拷贝代码时,为了保护公司的信息,删除了一些字符。
因此,在删除sink类的信息时多删除了。这都让你看出来了,真细心。呵呵。原来的代码就是raw_CBFun_InState。
这一点没问题的。
您给的示例不知道是怎么回事,没有说明,打开项目后也无法运行,总之,看不懂。
而且,我也没有找到回调事件的定义。如果只是“演示如何远程调用 COM 对象”的编程,那我的程序就可以实现。
现在的问题是“远程回调事件”的应用。
也说不清区别呢。
yyunffu可能误解我的意思了。我现在是在本地用远程调用的方式来调用我的回调函数。
唉,16楼说的本机调用是指:
我有一个客户端程序要调用我自己写的COM组件,这个客户端程序假设放在192.168.0.101上。
我在把“本来应该放在其他计算机上的COM组件放在了192.168.0.101上”
我说的本机是192.168.0.101上,但调用方式还是远程调用的方式。不知我说清楚没有。