如何接收COM组件事件(100分奉上)
一个硬件厂家提供的设备,现在要读取这个设备的事件。厂家做了一个COM组件,我要在我的DLL中访问这个组件。
现在主要是接收事件这块出问题了。
我在VC6.0、WindowsXP下开发。
其实,本来厂家是提供了DEMO程序的,如果照着那个DEMO做很容易的。
但因为我不能使用MFC的东西(主要是为了平台兼容),所以很费劲。
接收事件我用的是网上提供的CSink类的方法,就是继承IDispEventImpl而自己写的类,在这个类中接收事件。
类如下:
static _ATL_FUNC_INFO info2 =
{
CC_STDCALL, // Calling convention.
VT_HRESULT, // Return type.
2, // Number of arguments.
{ VT_BSTR, VT_I2 } // Argument types.
};
class CSvrEvent :
public CRefCount, public IDispEventImpl<IDC_TMPE_ID,CSvrEvent,
&__uuidof(IServerEvents), // Source interface GUID.
&LIBID_CSSAppServer, // typelib ID containing source interface.
1, // Major version # of LIBID_COMOBJLib. 0> // Minor version # of LIBID_COMOBJLib.
{
public:
CSvrEvent();
CSvrEvent(IServer *pIApplet);
~CSvrEvent(void);
BEGIN_SINK_MAP(CSvrEvent)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000001, ControllerDetected, &info2)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000002, ControllerOnline, &info2)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000003, ControllerOffline, &info2)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000004, DoorStatusChanged, &info4)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000005, PointStatusChanged, &info4_1)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000006, ControllerSearchEnd, &info1)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000007, NetNodeOnline, &info1)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000008, NetNodeOffline, &info1)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x00000009, UncommonDoorEvent, &info4_2)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x0000000a, HistoryEvent, &info1_1)
SINK_ENTRY_INFO(IDC_TMPE_ID,__uuidof(IServerEvents), 0x0000000b, UserAreaChanged, &info4_3)
END_SINK_MAP()
// IUnknown methods
ULONG STDMETHODCALLTYPE AddRef(void);
ULONG STDMETHODCALLTYPE Release(void);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void * *ppvObj);
// 组件发出的事件函数
STDMETHODCALLTYPE ControllerDetected(_bstr_t NodeIName, short CtrlAddr);
STDMETHODCALLTYPE ControllerOnline(_bstr_t NodeName, short CtrlAddr);
STDMETHODCALLTYPE ControllerOffline(_bstr_t NodeName, short CtrlAddr);
STDMETHODCALLTYPE DoorStatusChanged(_bstr_t NodeName, short CtrlAddr, long DoorAddr, long Status);
STDMETHODCALLTYPE PointStatusChanged(_bstr_t NodeName, short CtrlAddr, short PointAddr, long Status);
STDMETHODCALLTYPE ControllerSearchEnd(_bstr_t NodeName);
STDMETHODCALLTYPE NetNodeOnline(_bstr_t NodeName);
STDMETHODCALLTYPE NetNodeOffline(_bstr_t NodeName);
STDMETHODCALLTYPE UncommonDoorEvent(_bstr_t NodeName,WORD EventType,WORD CtrlAddr,WORD DoorAddr);
STDMETHODCALLTYPE HistoryEvent(long Events);
STDMETHODCALLTYPE UserAreaChanged (_bstr_t NodeName, long ZoneNo, long CardNo, short Area);
};
下面是在初始化时引用这个事件类的代码:
COSERVERINFO ServerInfo;
MULTI_QI Results;
ServerInfo.dwReserved1 = 0;
ServerInfo.dwReserved2 = 0;
ServerInfo.pAuthInfo =NULL;
ServerInfo.pwszName = L"192.168.0.106"; //远程服务器机器名
Results.pIID = &IID_IServer;
Results.pItf = NULL;
HRESULT hr;
hr = CoCreateInstanceEx(CLSID_Server,NULL,
CLSCTX_REMOTE_SERVER,&ServerInfo,1,&Results);
if(FAILED(hr))
{
MessageBox(NULL, "Connect to Server failed","Error",MB_OK | MB_ICONSTOP);
return FALSE;
}
Results.pItf->QueryInterface(&m_pServer);
CComPtr<IConnectionPointContainer> pCPC;
CComPtr<IConnectionPoint> pPC;
hr = m_pServer.QueryInterface(__uuidof(IConnectionPointContainer), (void **)&pCPC);
if (hr != S_OK)
{
return;
}
hr = pCPC->FindConnectionPoint(DIID_IServerEvents,&pPC);
if (hr != S_OK)
{
return;
}
CSvrEvent ServerEvent;
m_pServerEvent = new CSvrEvent(m_pServer);
CComPtr<IUnknown> pUnk;
CLSID clsid;
if(FAILED(::CLSIDFromProgID(L"CSSServer.NetNode.1",&clsid)))
{
return;
}
IDispatch * m_pDispMon;
// 由 CLSID 启动组件,并得到 IDispatch 指针
hr = ::CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (void **)&m_pDispMon);
if (hr != S_OK || m_pDispMon == NULL)
{
// AfxMessageBox("创建CooMonitor组件失败。");
return;
}
// 注册事件类
hr = m_pServerEvent->DispEventAdvise(m_pServer);
if (hr != S_OK)
{
return;
}
现在编译没问题,初始化也没问题,就是当程序运行、设备上线的事件被触发时,会发生断言,调试这个异常时来到ATLCOM.H中,错误出现在这个文件的InvokeFromFuncInfo函数中的如下代码:
HRESULT hr = DispCallFunc(
&thunk,
0,
info.cc,
info.vtReturn,
info.nParams,
info.pVarTypes,
pVarArgs,
pvarResult);
ATLASSERT(SUCCEEDED(hr));
以上代码中,hr=0x80070057,其含义是“参数不正确”。
我检查了多次参数,我定义的info2 没问题呀。如下:
static _ATL_FUNC_INFO info2 =
{
CC_STDCALL, // Calling convention.
VT_HRESULT, // Return type.
2, // Number of arguments.
{ VT_BSTR, VT_I2 } // Argument types.
};
ControllerOnline函数是设备上线时触发的,而ControllerOnline的参数是_bstr_t,难道说_bstr_t和VT_BSTR不是一回事?该怎么弄呢?
请各位大师帮忙啊。多谢,100分奉上!