I am attempting to raise an event in .NET and have it picked up through COM by a VBA application. This answer has been quite helpful in getting my events to show up properly in the type library.
On the VBA side, everything looks legit. I have an object variable declared "WithEvents" ,the IDE lets me add event handlers, and the compiler doesn't complain. However at run-time, when I use New to create the object I get the Run-time error 459: This component doesn't support this set of events. According to the help file , this means: "You tried to use a WithEvents variable with a component that can't work as an event source for the specified set of events."
I do not really know why. I do not think I am running afoul of the Implements rule that the help file also explains. Below is the IDL for the type library (luckily it is a short one). Can anyone see what is wrong with this type library that is causing this?
EDIT : --------------------------------
Remembering that I had a COM version of this component from several versions ago, I compared its IDL and notice that on it, both interfaces are marked nonextensible. Is this relevant to the WithEvents failure? When I use that component instead of the new one, it does not fail at "New" and receives events properly.
The only other differences I see are the hidden attribute and the double underscore naming for the event interface (and why would either of those matter?)
.tlb from .NET
// 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);
};
};
code on the .NET side:
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
the old (working) .tlb from VB6
// 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;
};
I'd compile the .net version, then use OLEVIEW to generate the code for the TLB from both the .net and the COM VB6 versions.
Then compare them in something like BeyondCompare or Araxis.
Get the GUIDs all lined up, and then look for any other differences.
Nothing's jumping out at me from what's posted, but I've spent plenty of time comparing TLBs in order to get the .net version "just right".
I'm not sure of the etiquette on SO about posting links, but I did a project some time ago that enabled Bookmark and breakpoint saving in VB6. It was a VB.net project that generated a COM addin for the VB6 IDE, so there's LOTS of COM interop example code in there.
Check it out here:
User contributions licensed under CC BY-SA 3.0