【发布时间】:2014-07-20 11:24:41
【问题描述】:
我试图在 .NET 中引发一个事件,并让 VBA 应用程序通过 COM 获取它。 This answer 非常有助于让我的事件正确显示在类型库中。
在 VBA 方面,一切看起来都是合法的。我有一个声明为“WithEvents”的对象变量,IDE 允许我添加事件处理程序,编译器不会抱怨。但是在运行时,当我使用 New 创建对象时,我得到 Run-time error 459: This component doesn't support this set of events. 根据帮助文件,这意味着:“您尝试将 WithEvents 变量与无法用作事件源的组件一起使用指定的事件集。”
我真的不知道为什么。我不认为我违反了帮助文件也解释的实施规则。下面是类型库的 IDL(幸运的是它很短)。任何人都可以看到导致这种情况的类型库有什么问题吗?
编辑:--------------------------------
记得我之前有过这个组件的 COM 版本,我比较了它的 IDL,注意到上面两个接口都标记为nonextensible。这与 WithEvents 失败有关吗?当我使用该组件而不是新组件时,它不会在“新建”处失败并正确接收事件。
我看到的唯一其他区别是 hidden 属性和事件接口的双下划线命名(为什么这两者都重要?)
.NET 中的 .tlb
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: Drawing Locator.tlb
[
uuid(4ABD3AAB-CA6A-48D6-8E4E-8082645A0F05),
version(1.0),
custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "Drawing Locator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e02c23b3671cff4d")
]
library Drawing_Locator
{
// TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
interface IDrawingFinder;
dispinterface IDrawingFinderEvents;
typedef [uuid(565D6F5A-13BF-4794-AC35-3ECC4329B280), version(1.0) ,
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "Drawing_Locator.FileTypes")
]
enum {
FileTypes_Tiff = 0,
FileTypes_Acad = 1
} FileTypes;
[
uuid(78B2A29B-C289-4D65-B373-C345AD06BD31),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "Drawing_Locator.DrawingFinder")
]
coclass DrawingFinder {
interface _Object;
[default] interface IDrawingFinder;
[default, source] dispinterface IDrawingFinderEvents;
};
[
odl,
uuid(21DBD6E1-D04F-4335-B189-5B49EB960605),
version(1.0),
dual,
oleautomation,
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "Drawing_Locator.IDrawingFinder")
]
interface IDrawingFinder : IDispatch {
[id(0x60020000)]
HRESULT GetFiles(
[in] BSTR PartNumber,
[in] FileTypes FileType,
[in] VARIANT_BOOL OpenFiles,
[out, retval] SAFEARRAY(BSTR)* pRetVal);
[id(0x60020001)]
HRESULT RegisterTiffToImaging();
};
[
uuid(60314738-04D1-4B4A-BC39-6A81DE24A13B),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "Drawing_Locator.IDrawingFinderEvents")
]
dispinterface IDrawingFinderEvents {
properties:
methods:
[id(0x00000001)]
void PartNumberChanged([in] BSTR NewPartNumber);
[id(0x00000002)]
void Searching([in, out] VARIANT_BOOL* CancelSearch);
};
};
.NET 端的代码:
Imports System.Runtime.InteropServices
<ComVisible(True)>
<InterfaceType(ComInterfaceType.InterfaceIsDual)>
<Guid("21DBD6E1-D04F-4335-B189-5B49EB960605")>
Public Interface IDrawingFinder
Function GetFiles(ByVal PartNumber As String, ByVal FileType As FileTypes, ByVal OpenFiles As Boolean) As <MarshalAs(UnmanagedType.SafeArray, SafeArraySubType:=VarEnum.VT_BSTR)> String()
Sub RegisterTiffToImaging()
End Interface
<ComVisible(True)>
<InterfaceType(ComInterfaceType.InterfaceIsIDispatch)>
<Guid("60314738-04D1-4B4A-BC39-6A81DE24A13B")>
Public Interface IDrawingFinderEvents
<System.Runtime.InteropServices.DispId(1)>
Sub PartNumberChanged(ByVal NewPartNumber As String)
<System.Runtime.InteropServices.DispId(2)>
Sub Searching(ByRef CancelSearch As Boolean)
End Interface
<ComVisible(True)>
<GuidAttribute("565D6F5A-13BF-4794-AC35-3ECC4329B280")>
Public Enum FileTypes
Tiff
Acad
End Enum
<System.Runtime.InteropServices.ComVisible(False)>
Public Delegate Sub OnPartNumberChanged(ByVal NewPartNumber As String)
<System.Runtime.InteropServices.ComVisible(False)>
Public Delegate Sub OnSearching(ByRef CancelSearch As Boolean)
<ComVisible(True)>
<ClassInterface(ClassInterfaceType.None)>
<ComDefaultInterface(GetType(Drawing_Locator.IDrawingFinder))>
<ComSourceInterfaces(GetType(Drawing_Locator.IDrawingFinderEvents))>
<GuidAttribute("78B2A29B-C289-4D65-B373-C345AD06BD31")>
Public Class DrawingFinder
Implements IDrawingFinder
Public Event PartNumberChanged As OnPartNumberChanged
Public Event Searching As OnSearching
'Event PartNumberChanged(ByVal NewPartNumber As String)
'Event Searching(ByRef CancelSearch As Boolean)
Private Declare Sub SHAddToRecentDocs Lib "shell32.dll" (ByVal uFlags As Integer, ByVal pv As String)
Private Const SHARD_PATH As Integer = 2
Dim worker As BackgroundWorker
Dim eventargs As DoWorkEventArgs
Public Function GetFiles(ByVal PartNumber As String, ByVal FileType As FileTypes, ByVal OpenFiles As Boolean) As String() Implements IDrawingFinder.GetFiles
End Sub
End Class
来自 VB6 的旧(工作).tlb
// typelib filename: DrawingFinder.dll
[
uuid(D11F3F87-F149-4060-81D3-F46A90DA28CB),
version(1.0),
helpstring("Finds and Opens Engineering Drawings"),
custom(50867B00-BB69-11D0-A8FF-00A0C9110059, 9782)
]
library DrawingSearch
{
// TLib : // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
interface _DrawingFinder;
dispinterface __DrawingFinder;
[
odl,
uuid(A0AB1327-59A7-45E0-8992-92DB8253368B),
version(1.0),
hidden,
dual,
nonextensible,
oleautomation
]
interface _DrawingFinder : IDispatch {
[id(0x60030000)]
HRESULT OpenAcadDwgs([in] BSTR PN);
[id(0x60030001)]
HRESULT OpenImageFiles([in] BSTR PN);
[id(0x60030002)]
HRESULT GetAcadDwgs(
[in] BSTR PN,
[out, retval] SAFEARRAY(BSTR)* );
[id(0x60030003)]
HRESULT GetImageFiles(
[in] BSTR PN,
[out, retval] SAFEARRAY(BSTR)* );
};
[
uuid(95E5F4E3-6A45-4B60-845B-3A78E75A8319),
version(1.0)
]
coclass DrawingFinder {
[default] interface _DrawingFinder;
[default, source] dispinterface __DrawingFinder;
};
[
uuid(BB78905B-297B-4D7C-80B0-3297D4B07AFE),
version(1.0),
hidden,
nonextensible
]
dispinterface __DrawingFinder {
properties:
methods:
[id(0x00000001)]
void Searching([in, out] VARIANT_BOOL* Cancel);
[id(0x00000002)]
void PartNumberChanged([in] BSTR FormattedPN);
};
typedef [uuid(4F3E20EC-EE21-40E8-813F-9292605EF941), version(1.0)]
enum {
errArgument_OutOfRange = 0x80040001,
errDrawing_FolderNotFound = 0x80040002,
errDrawing_FileNotFound = 0x80040003,
errDrawing_BadShortcut = 0x80040004,
errDrawing_ViewerNotFound = 0x80040005,
errDrawing_Open = 0x80040006,
errDrawing_SearchCancelled = 0x80040007,
errAcad_NotAvailable = 0x80040008
} ErrorTypeEnum;
};
【问题讨论】:
-
什么都没有跳出来。当您对 COM 服务器进行增量更改时,刷新类型库以便它使用它的更新版本很重要。在您的 VBA 环境中,删除类型库引用并将其添加回来。
-
@HansPassant 您能否在编辑后的问题中看到有关“不可扩展”的问题?
-
[nonextensible] 是一个属性,表明 [dual] 接口的两侧是相同的。也就是说,通过 IDIspatch 可用的每个方法也可以通过本机接口使用。这不应该导致事件处理本身出现问题。我的猜测是 Hans 的建议,您仍然注册了旧 DLL,并且新 DLL 的类型库不兼容。请尝试从 VBA 项目中删除该组件,取消注册旧的,也许关闭 VB 以进行良好的测量,注册新的,然后再次添加该组件。
标签: .net vba com vb6 com-interop