我使用ATL簡單對象嚮導在C++中使用ATL構建了一個COM服務器DLL。我遵循微軟的ATLDLLCOMServer例子。除了一件事情之外,一切都很好:我沒有在VBScript中收到COM事件。我確實收到了C#中的事件。我在早期的基於MFC的實現中使用VBScript中的事件作爲ActiveX控件。將COM事件暴露給VBScript(ATL)
我的控制是這樣定義的:
class ATL_NO_VTABLE CSetACLCOMServer :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSetACLCOMServer, &CLSID_SetACLCOMServer>,
public IConnectionPointContainerImpl<CSetACLCOMServer>,
public CProxy_ISetACLCOMServerEvents<CSetACLCOMServer>,
public IDispatchImpl<ISetACLCOMServer, &IID_ISetACLCOMServer, &LIBID_SetACLCOMLibrary, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IProvideClassInfo2Impl<&CLSID_SetACLCOMServer, &DIID__ISetACLCOMServerEvents, &LIBID_SetACLCOMLibrary> /* Required for event support in VBS */
{
public:
BEGIN_COM_MAP(CSetACLCOMServer)
COM_INTERFACE_ENTRY(ISetACLCOMServer)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CSetACLCOMServer)
CONNECTION_POINT_ENTRY(__uuidof(_ISetACLCOMServerEvents))
END_CONNECTION_POINT_MAP()
[...]
在VBScript中我使用COM對象是這樣的:
set objSetACL = WScript.CreateObject("SetACL.SetACL", "SetACL_")
' Catch and print messages from the SetACL COM server which are passed (fired) as events.
' The name postfix of this function (MessageEvent) must be identical to the event name
' as defined by SetACL.
' The prefix (SetACL_) can be set freely in the call to WScript.CreateObject
sub SetACL_MessageEvent (Message)
WScript.Echo Message
end sub
的IDL的相關部分是這樣的:
[
object,
uuid(E1B57CA5-FD7F-4304-BC0A-8BEBDE231D53),
dual,
nonextensible,
pointer_default(unique),
helpstring("SetACL COM Interface")
]
interface ISetACLCOMServer : IDispatch
{
};
[
uuid(00D4DCD3-02B9-4A71-AB61-2283504620C8),
version(1.0),
helpstring ("SetACL Type Library")
]
library SetACLCOMLibrary
{
importlib("stdole2.tlb");
[
uuid(35F76182-7F52-4D6A-BD6E-1317345F98FB),
helpstring ("SetACL Event Interface")
]
dispinterface _ISetACLCOMServerEvents
{
properties:
methods:
[id(1), helpstring("Receives string messages that would appear on the screen in the command line version")]
void MessageEvent([in] BSTR message);
};
[
uuid(13379563-8F21-4579-8AC7-CBCD488735DB),
helpstring ("SetACL COM Server"),
]
coclass SetACLCOMServer
{
[default] interface ISetACLCOMServer;
[default, source] dispinterface _ISetACLCOMServerEvents;
};
};
問題:SetACL_MessageEvent永遠不會獲得calle d。
我曾嘗試:
- 閱讀this KB article後,我加入IProvideClassInfo2的實施,但這並沒有幫助。
- 這個FAQ提到輸出接口不應該定義爲雙接口。我從我的界面定義中刪除了「雙重」,但這沒有幫助。
- 我發現this SO question似乎描述了一個類似的問題。答案從來沒有給出,只有一個解決方法。
更新1:
我現在知道它是失敗的,但不是原因:在_ISetACLCOMServerEvents_CP.h火災事件方法進行的調用失敗,E_UNEXPECTED。這是該行:
hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL);
解決方案:
問題是,我所謂的事件從COM對象的背景線程發射功能,從錯誤的公寓等字樣。
難道你不需要在vbscript/vba中使用'WithEvents'來響應COM事件嗎? – 2012-07-29 22:13:05
不,根據http://msdn.microsoft.com/en-us/library/ms974564.aspx你沒有。 – 2012-07-30 08:44:27
我想你在'IProvideClassInfo2Impl'中丟失了第二個參數。我應該是事件接口'IID'。 – 2012-07-30 09:14:55