奇怪的事情发生了。我刚才编译了程序,执行正确了。记得好像是调用了一次_Module.Init(),后来又删除掉了了那段代码,应该不是这段代码起的作用,因为我重新建立了一个项目,又写了一遍客户端代码,结果仍然正确,而且ATL Internal 一书中也提到了QueryInterface在模板类中实现了。看了好多这方面的帖子,感觉都说的不彻底,不能看完就能自己实现。现在总结一下连接点的客户端实现方法,希望给初学者帮上忙。
我就不说连接点的原理了,很多帖子说的很清楚,在论坛上搜索“连接点 原理”就可以找到。
我就说一下用在mfc中用ATL的模板类来实现,因为这个方法比用最原是的方法来实现简单的多,不用自己去实现IDispatch接口中的函数,尤其是Invoke函数(比较麻烦)。
1、用#import指令导入你用到的dll服务器,它会自动生成接口说明和接口ID等信息,例子:
#import "F:/vc练习/050104ATL/Debug/050104ATL.dll" raw_interfaces_only, no_namespace, named_guids
把它放在StdAfx.h里面。
2、在MFC中添加ATL支持
选择菜单中的插入-》插入ATL对象,确认添加ATL支持之后,不用真的添加一个ATL对象,因为用不着。
3、构造自己的事件接收器类。代码如下
//EventSink.h
class CEventSink :
public IDispEventImpl<1, CEventSink,&DIID__ISpeakEvents,&LIBID_MY050104ATLLib, 1, 0>
{
public:
CEventSink()
{
}
public:
BEGIN_SINK_MAP(CEventSink)
SINK_ENTRY_EX(1, DIID__ISpeakEvents, 1, OnSay)
END_SINK_MAP()
void __stdcall OnSay(long aVal); };
//EventSink.cpp
#include "stdafx.h"
#include "EventSink.h"
void __stdcall CEventSink::OnSay(long aVal)
{
AfxMessageBox("called by Event from dll Server !");
}
这样就已经完成了事件接收器类的工作,接着就是建立连接了
建立连接目的就是把接收器类的IUnknown指针传递给源对象
IUnknown *pUnk ;
HRESULT hr = m_Dispatch->QueryInterface(IID_IUnknown,(void**)&pUnk);
if (SUCCEEDED(hr) )
{
pEventSink->DispEventAdvise(pUnk);
}
m_Dispatch是我在MFC对话框类中建立的一个共有成员变量,用来保存服务器的自动化接口指针,用它来查找到IUnknown指针,传递给源对象。至此,接收器就可以工作了。断开连接与建立连接相似:
IUnknown *pUnk ;
HRESULT hr = m_Dispatch->QueryInterface(IID_IUnknown,(void**)&pUnk);
if (SUCCEEDED(hr) )
{
pEventSink->DispEventUnadvise(pUnk);
}
用原始的方法写,则比较麻烦,不过思路清晰,都在自己的掌握之中
class CMy050104COMClientDlg : public CDialog
{
// Construction
public:
CMy050104COMClientDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CMy050104COMClientDlg)
enum { IDD = IDD_MY050104COMCLIENT_DIALOG };
long m_Roal;
long m_Say;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMy050104COMClientDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CMy050104COMClientDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnButton1();
afx_msg void OnButton2();
afx_msg void OnButton3();
afx_msg void OnButton4();
afx_msg void OnButton5();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
DWORD m_dwCookie ;
LPDISPATCH m_Dispatch ;
//Added By Y.Y.He 2005-1-4 16:48:58
// DECLARE_INTERFACE_MAP() //看看这个宏得作用是什么?这里不用
BEGIN_INTERFACE_PART(EventSink,IDispatch)
INIT_INTERFACE_PART(CMy050104COMClientDlg,EventSink)
STDMETHOD(GetTypeInfoCount)(unsigned int*);
STDMETHOD(GetTypeInfo)(UINT,LCID,ITypeInfo**);
STDMETHOD(GetIDsOfNames)(REFIID,LPOLESTR*,UINT,LCID,DISPID*);
STDMETHOD(Invoke)(DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
END_INTERFACE_PART(EventSink)
int OnConnection();
int OnDisConnection();
}
实现部分:
void CMy050104COMClientDlg::OnButton4() //建立连接
{
if (OnConnection() != 1)
{
AfxMessageBox("Connection Failed !");
}
}
STDMETHODIMP_(ULONG)CMy050104COMClientDlg::XEventSink::AddRef()
{
return 1;
}
STDMETHODIMP_(ULONG)CMy050104COMClientDlg::XEventSink::Release()
{
return 0;
}
STDMETHODIMP CMy050104COMClientDlg::XEventSink::QueryInterface(REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(CMy050104COMClientDlg,EventSink)
if (IsEqualIID(iid,IID_IUnknown)||
IsEqualIID(iid,IID_IDispatch)||
IsEqualIID(iid,DIID__ISpeakEvents))
{
*ppvObj = this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP CMy050104COMClientDlg::XEventSink::GetTypeInfoCount(unsigned int*)
{
return E_NOTIMPL;
}
STDMETHODIMP CMy050104COMClientDlg::XEventSink::GetTypeInfo(UINT,LCID,ITypeInfo**)
{
return E_NOTIMPL;
}
STDMETHODIMP CMy050104COMClientDlg::XEventSink::GetIDsOfNames(REFIID,LPOLESTR*,UINT,LCID,DISPID*)
{
return E_NOTIMPL;
}
STDMETHODIMP CMy050104COMClientDlg::XEventSink::Invoke(DISPID DispID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*)
{
AfxMessageBox("Event occoured ! " );
TRACE("/n idspid =%d/n",DispID);
return S_OK;
}
int CMy050104COMClientDlg::OnConnection()
{
BOOL RetVal = 0;
if (m_dwCookie != 0)
{
return 2;
}
LPCONNECTIONPOINTCONTAINER pConnPtCont = NULL;
if((m_Dispatch != NULL)&&( SUCCEEDED(m_Dispatch->QueryInterface(IID_IConnectionPointContainer,(void**)&pConnPtCont))))
{
ASSERT(pConnPtCont != NULL);
LPCONNECTIONPOINT pConnPt = NULL;
DWORD dwCookie;
if (SUCCEEDED(pConnPtCont->FindConnectionPoint(DIID__ISpeakEvents,&pConnPt)) )
{
ASSERT(pConnPt != NULL);
pConnPt->Advise(&m_xEventSink,&dwCookie);
RetVal = 1;
pConnPt->Release();
}
pConnPtCont->Release();
m_dwCookie = dwCookie;
}
return RetVal;
}
int CMy050104COMClientDlg::OnDisConnection()
{
BOOL RetVal = 0;
if (m_dwCookie == 0)
{
return 2;
}
LPCONNECTIONPOINTCONTAINER pConnPtCont = NULL;
if ((m_Dispatch != NULL)&&( SUCCEEDED(m_Dispatch->QueryInterface(IID_IConnectionPointContainer,(void**)&pConnPtCont))))
{
ASSERT(pConnPtCont != NULL);
LPCONNECTIONPOINT pConnPt = NULL;
DWORD dwCookie;
if (SUCCEEDED(pConnPtCont->FindConnectionPoint(DIID__ISpeakEvents,&pConnPt)) )
{
ASSERT(pConnPt != NULL);
pConnPt->Unadvise(m_dwCookie);
m_dwCookie = 0;
RetVal = 1;
pConnPt->Release();
}
pConnPtCont->Release();
}
return RetVal;
}
void CMy050104COMClientDlg::OnButton5()
{
if (OnDisConnection() != 1)
{
AfxMessageBox("DisConnection Failed !");
}
}