使用ATL进行com组件开发,对于ActiveX和com对象事件响应

时间:2022-12-02 23:16:31
本人在做一个com组件,其中包括主要的两个com对象:一个为ActiveX对象用于UI的显示、另一个为普通的com对象主要做对于前一个对象进行响应的处理。
现在遇到的问题是,我已经完成了两个对象,但是不知道如何将两个对象的事件连接建立起来
最初设想的目标是在使用这个组件的二次开发中只要拖入ActiveX控件,在代码中创建另外的一个对象,就能自动的完成这两个对象的事件链接。
希望有相关经验的高手帮忙

14 个解决方案

#1


好像没人回答,我再说的详细点儿。希望高手帮帮忙
我的目的是希望两个在同一com组件中的com对象能够互相接收对方的事件。
并做出响应。
可不可以直接在两个对象内直接加接收器,然后在客户代码中链接连接点和接收器?
还有最好能做到自动链接,就是不用客户代码中显式的写出代码链接。

#2


现在我有个想法:在一个com组件做创建两个com对象,一个作为事件的发起者,一个做接收者。
发起者实现IConnectionPointImpl接口等,发送事件。代码如下:
Sender.h
class ATL_NO_VTABLE CSender : 
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSender, &CLSID_Sender>,
public IConnectionPointContainerImpl<CSender>,
public IDispatchImpl<ISender, &IID_ISender, &LIBID_TWOCOMLib>,
public CProxy_ISenderEvents< CSender >
{
public:
CSender()
{
}

DECLARE_REGISTRY_RESOURCEID(IDR_SENDER)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSender)
COM_INTERFACE_ENTRY(ISender)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CSender)
CONNECTION_POINT_ENTRY(DIID__ISenderEvents)
END_CONNECTION_POINT_MAP()

然后在一个任意接口的函数里fire_OnEvent(代码未写)。

#3


你说的可以实现

也就是在两个对象中都实现连接点就是了

#4


对于包含的接收器对象:
__ATL_FUNC_INFO recinfo = {CC_STDCALL,VT_EMPTY,1,{VT_BSTR}};

/////////////////////////////////////////////////////////////////////////////
// CReceiver
class ATL_NO_VTABLE CReceiver : 
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CReceiver, &CLSID_Receiver>,
public IDispatchImpl<IReceiver, &IID_IReceiver, &LIBID_TWOCOMLib>
{
public:
CReceiver()
{
m_sink = new CEventSink(this);
}
DECLARE_REGISTRY_RESOURCEID(IDR_RECEIVER)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CReceiver)
COM_INTERFACE_ENTRY(IReceiver)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// IReceiver
public:
int LinkEvents(IUnknown* ISender);// 连接Sender对象
DWORD dwCookie;
// int OnAdd();
HRESULT OnRecEvent();
class CEventSink : public IDispEventSimpleImpl<1, CEventSink, &DIID__ISenderEvents>
{
public:
CEventSink(CReceiver* currentRec){Rec = currentRec;};
virtual ~CEventSink();
BEGIN_SINK_MAP(CEventSink)
SINK_ENTRY_INFO(1, DIID__ISenderEvents, 1, OnSinkEvent,&recinfo)
END_SINK_MAP()
void __stdcall OnSinkEvent(){ Rec->OnRecEvent();}
CReceiver* Rec;
};
CEventSink *m_sink;
};

在receiver内部包含一个Sink接收器对象,然后通过receiver的一个方法进行事件连接。
现在编译通过了,但链接出问题了。
Linking...
TwoCom.obj : error LNK2005: "struct ATL::_ATL_FUNC_INFO recinfo" (?recinfo@@3U_ATL_FUNC_INFO@ATL@@A) already defined in Receiver.obj
TwoCom.obj : warning LNK4006: "struct ATL::_ATL_FUNC_INFO recinfo" (?recinfo@@3U_ATL_FUNC_INFO@ATL@@A) already defined in Receiver.obj; second definition ignored
   Creating library Debug/TwoCom.lib and object Debug/TwoCom.exp
TwoCom.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall CReceiver::CEventSink::~CEventSink(void)" (??1CEventSink@CReceiver@@UAE@XZ)
Debug/TwoCom.dll : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

#5


接着写,看看有高手知道否
目前编译没问题,问题出在链接。
--------------------Configuration: TwoCom - Win32 Debug--------------------
Linking...
   Creating library Debug/TwoCom.lib and object Debug/TwoCom.exp
TwoCom.obj : error LNK2001: unresolved external symbol "struct ATL::_ATL_FUNC_INFO recinfo" (?recinfo@@3U_ATL_FUNC_INFO@ATL@@A)
Debug/TwoCom.dll : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

TwoCom.dll - 2 error(s), 0 warning(s)
_ATL_FUNC_INFO 的链接有问题。 不知道是什么出错了,查msdn看到也是这么写的。不知道有没有高手会这个。

#6


链接问题已经解决
_ATL::_ATL_FUNC_INFO  按照msdn上讲的需要定义在.cpp文件中
不明白为什么,但是按照msdn写的做,有效果

#7


恭喜你,另外MS的宏你可以跟进去看定义的

#8


谢谢ls的关心
目前还有个问题就是我希望能让com对象获取到客户程序中 目前已创建的com对象的指针。
这样就能够实现在com对象的内部完成事件连接点和sink的链接。
从而避免了二次开发中客户面对完全不需要了解的事件进行绑定。

#9


今天解决了一个问题,回过头来再看这个问题。

#10


很复杂啊,如果一个对象创建了两次呢?

#11


en,建立了连接点就好了

#12


你可以去vcbase上找杨老师的文章,应该在回调、连接点那有讲解哦~~~~~

#13


引用 10 楼 firmbird 的回复:
很复杂啊,如果一个对象创建了两次呢?


那就得在对象内部进行控制了啊

#14


引用 12 楼 lsupper 的回复:
你可以去vcbase上找杨老师的文章,应该在回调、连接点那有讲解哦~~~~~

谢谢,我去看看

#1


好像没人回答,我再说的详细点儿。希望高手帮帮忙
我的目的是希望两个在同一com组件中的com对象能够互相接收对方的事件。
并做出响应。
可不可以直接在两个对象内直接加接收器,然后在客户代码中链接连接点和接收器?
还有最好能做到自动链接,就是不用客户代码中显式的写出代码链接。

#2


现在我有个想法:在一个com组件做创建两个com对象,一个作为事件的发起者,一个做接收者。
发起者实现IConnectionPointImpl接口等,发送事件。代码如下:
Sender.h
class ATL_NO_VTABLE CSender : 
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSender, &CLSID_Sender>,
public IConnectionPointContainerImpl<CSender>,
public IDispatchImpl<ISender, &IID_ISender, &LIBID_TWOCOMLib>,
public CProxy_ISenderEvents< CSender >
{
public:
CSender()
{
}

DECLARE_REGISTRY_RESOURCEID(IDR_SENDER)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSender)
COM_INTERFACE_ENTRY(ISender)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CSender)
CONNECTION_POINT_ENTRY(DIID__ISenderEvents)
END_CONNECTION_POINT_MAP()

然后在一个任意接口的函数里fire_OnEvent(代码未写)。

#3


你说的可以实现

也就是在两个对象中都实现连接点就是了

#4


对于包含的接收器对象:
__ATL_FUNC_INFO recinfo = {CC_STDCALL,VT_EMPTY,1,{VT_BSTR}};

/////////////////////////////////////////////////////////////////////////////
// CReceiver
class ATL_NO_VTABLE CReceiver : 
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CReceiver, &CLSID_Receiver>,
public IDispatchImpl<IReceiver, &IID_IReceiver, &LIBID_TWOCOMLib>
{
public:
CReceiver()
{
m_sink = new CEventSink(this);
}
DECLARE_REGISTRY_RESOURCEID(IDR_RECEIVER)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CReceiver)
COM_INTERFACE_ENTRY(IReceiver)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// IReceiver
public:
int LinkEvents(IUnknown* ISender);// 连接Sender对象
DWORD dwCookie;
// int OnAdd();
HRESULT OnRecEvent();
class CEventSink : public IDispEventSimpleImpl<1, CEventSink, &DIID__ISenderEvents>
{
public:
CEventSink(CReceiver* currentRec){Rec = currentRec;};
virtual ~CEventSink();
BEGIN_SINK_MAP(CEventSink)
SINK_ENTRY_INFO(1, DIID__ISenderEvents, 1, OnSinkEvent,&recinfo)
END_SINK_MAP()
void __stdcall OnSinkEvent(){ Rec->OnRecEvent();}
CReceiver* Rec;
};
CEventSink *m_sink;
};

在receiver内部包含一个Sink接收器对象,然后通过receiver的一个方法进行事件连接。
现在编译通过了,但链接出问题了。
Linking...
TwoCom.obj : error LNK2005: "struct ATL::_ATL_FUNC_INFO recinfo" (?recinfo@@3U_ATL_FUNC_INFO@ATL@@A) already defined in Receiver.obj
TwoCom.obj : warning LNK4006: "struct ATL::_ATL_FUNC_INFO recinfo" (?recinfo@@3U_ATL_FUNC_INFO@ATL@@A) already defined in Receiver.obj; second definition ignored
   Creating library Debug/TwoCom.lib and object Debug/TwoCom.exp
TwoCom.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall CReceiver::CEventSink::~CEventSink(void)" (??1CEventSink@CReceiver@@UAE@XZ)
Debug/TwoCom.dll : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

#5


接着写,看看有高手知道否
目前编译没问题,问题出在链接。
--------------------Configuration: TwoCom - Win32 Debug--------------------
Linking...
   Creating library Debug/TwoCom.lib and object Debug/TwoCom.exp
TwoCom.obj : error LNK2001: unresolved external symbol "struct ATL::_ATL_FUNC_INFO recinfo" (?recinfo@@3U_ATL_FUNC_INFO@ATL@@A)
Debug/TwoCom.dll : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

TwoCom.dll - 2 error(s), 0 warning(s)
_ATL_FUNC_INFO 的链接有问题。 不知道是什么出错了,查msdn看到也是这么写的。不知道有没有高手会这个。

#6


链接问题已经解决
_ATL::_ATL_FUNC_INFO  按照msdn上讲的需要定义在.cpp文件中
不明白为什么,但是按照msdn写的做,有效果

#7


恭喜你,另外MS的宏你可以跟进去看定义的

#8


谢谢ls的关心
目前还有个问题就是我希望能让com对象获取到客户程序中 目前已创建的com对象的指针。
这样就能够实现在com对象的内部完成事件连接点和sink的链接。
从而避免了二次开发中客户面对完全不需要了解的事件进行绑定。

#9


今天解决了一个问题,回过头来再看这个问题。

#10


很复杂啊,如果一个对象创建了两次呢?

#11


en,建立了连接点就好了

#12


你可以去vcbase上找杨老师的文章,应该在回调、连接点那有讲解哦~~~~~

#13


引用 10 楼 firmbird 的回复:
很复杂啊,如果一个对象创建了两次呢?


那就得在对象内部进行控制了啊

#14


引用 12 楼 lsupper 的回复:
你可以去vcbase上找杨老师的文章,应该在回调、连接点那有讲解哦~~~~~

谢谢,我去看看