We are trying to replace a COM server originally written for a VB6 application
We have no access to source code.
For some reason, the VB6 app can call our constructor, but then it gets:
System Error &H80004002. No such interface supported.
I assume when it tries to get the interface with QueryInterface.
We have our assembly properly sent through regasm /tlb and gacutil, but I then noticed something strange. I opened the .tlb file regasm generated for our assembly, and noticed all the properties on my interface show up as methods.
Is this something the .Net tools are doing? And would this cause my issue?
Here is the full tlb definition for the original file:
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: UtopiaKeyboard.tlb
[
uuid(9B4E1840-FF65-11CF-AA2E-0020AFA49D5A),
version(1.0),
helpstring("OPOS POSKeyboard OLE Control")
]
library POSKEYBOARDLib
{
// TLib : // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("STDOLE2.TLB");
// Forward declare all types defined in this typelib
dispinterface _DPOSKeyboard;
dispinterface _DPOSKeyboardEvents;
[
uuid(9B4E1841-FF65-11CF-AA2E-0020AFA49D5A),
helpstring("Dispatch interface for OPOS POSKeyboard OLE Control"),
hidden
]
dispinterface _DPOSKeyboard {
properties:
[id(0x00000001)
]
BSTR CheckHealthText;
[id(0x00000002)
]
VARIANT_BOOL Claimed;
[id(0x00000003)
]
VARIANT_BOOL DataEventEnabled;
[id(0x00000004)
]
VARIANT_BOOL DeviceEnabled;
[id(0x00000005)
]
VARIANT_BOOL FreezeEvents;
[id(0x00000006)
]
long ResultCode;
[id(0x00000007)
]
long ResultCodeExtended;
[id(0x00000008)
]
long State;
[id(0x00000009)
]
BSTR ControlObjectDescription;
[id(0x0000000a)
]
long ControlObjectVersion;
[id(0x0000000b)
]
BSTR ServiceObjectDescription;
[id(0x0000000c)
]
long ServiceObjectVersion;
[id(0x0000000d)
]
BSTR DeviceDescription;
[id(0x0000000e)
]
BSTR DeviceName;
[id(0x0000000f)
]
long POSKeyData;
[id(0x0000001a)
]
VARIANT_BOOL AutoDisable;
[id(0x0000001b)
]
long BinaryConversion;
[id(0x0000001c)
]
long DataCount;
[id(0x0000001d)
]
VARIANT_BOOL CapKeyUp;
[id(0x0000001e)
]
long EventTypes;
[id(0x0000001f)
]
long POSKeyEventType;
[id(0x00000021)
]
long CapPowerReporting;
[id(0x00000022)
]
long PowerNotify;
[id(0x00000023)
]
long PowerState;
methods:
[id(0x00000010)]
long Open([in] BSTR DeviceName);
[id(0x00000011)]
long Close();
[id(0x00000012)]
long Claim([in] long Timeout);
[id(0x00000013)]
long Release();
[id(0x00000014)]
long CheckHealth([in] long Level);
[id(0x00000015)]
long ClearInput();
[id(0x00000016)]
long DirectIO(
[in] long Command,
[in, out] long* pData,
[in, out] BSTR* pString);
[id(0x00000017)]
void SOData([in] long Status);
[id(0x00000018)]
void SODirectIO(
[in] long EventNumber,
[in, out] long* pData,
[in, out] BSTR* pString);
[id(0x00000019)]
void SOError(
[in] long ResultCode,
[in] long ResultCodeExtended,
[in] long ErrorLocus,
[in, out] long* pErrorResponse);
[id(0x00000020)]
long SOProcessID();
[id(0x00000024)]
void SOStatusUpdate([in] long Status);
};
[
uuid(9B4E1842-FF65-11CF-AA2E-0020AFA49D5A),
helpstring("Event interface for OPOS POSKeyboard OLE Control")
]
dispinterface _DPOSKeyboardEvents {
properties:
methods:
[id(0x00000001)]
void DataEvent([in] long Status);
[id(0x00000002)]
void DirectIOEvent(
[in] long EventNumber,
[in, out] long* pData,
[in, out] BSTR* pString);
[id(0x00000003)]
void ErrorEvent(
[in] long ResultCode,
[in] long ResultCodeExtended,
[in] long ErrorLocus,
[in, out] long* pErrorResponse);
[id(0x00000004)]
void StatusUpdateEvent([in] long Status);
};
[
uuid(9B4E1843-FF65-11CF-AA2E-0020AFA49D5A),
helpstring("OPOS POSKeyboard OLE Control"),
control
]
coclass POSKeyboard {
[default] dispinterface _DPOSKeyboard;
[default, source] dispinterface _DPOSKeyboardEvents;
};
};
Here is the generate tlb for my .Net assembly:
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: POSKEYBOARDLib.tlb
[
uuid(9B4E1840-FF65-11CF-AA2E-0020AFA49D5A),
version(1.0),
custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "POSKEYBOARDLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5824208931aaf68b")
]
library POSKEYBOARDLib
{
// 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
dispinterface _DPOSKeyboard;
dispinterface _DPOSKeyboardEvents;
[
uuid(9B4E1841-FF65-11CF-AA2E-0020AFA49D5A),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "POSKEYBOARDLib._DPOSKeyboard")
]
dispinterface _DPOSKeyboard {
properties:
methods:
[id(0x00000001), propget]
BSTR CheckHealthText();
[id(0x00000001), propput]
void CheckHealthText([in] BSTR rhs);
[id(0x00000002), propget]
VARIANT_BOOL Claimed();
[id(0x00000002), propput]
void Claimed([in] VARIANT_BOOL rhs);
[id(0x00000003), propget]
VARIANT_BOOL DataEventEnabled();
[id(0x00000003), propput]
void DataEventEnabled([in] VARIANT_BOOL rhs);
[id(0x00000004), propget]
VARIANT_BOOL DeviceEnabled();
[id(0x00000004), propput]
void DeviceEnabled([in] VARIANT_BOOL rhs);
[id(0x00000005), propget]
VARIANT_BOOL FreezeEvents();
[id(0x00000005), propput]
void FreezeEvents([in] VARIANT_BOOL rhs);
[id(0x00000006), propget]
long ResultCode();
[id(0x00000006), propput]
void ResultCode([in] long rhs);
[id(0x00000007), propget]
long ResultCodeExtended();
[id(0x00000007), propput]
void ResultCodeExtended([in] long rhs);
[id(0x00000008), propget]
long State();
[id(0x00000008), propput]
void State([in] long rhs);
[id(0x00000009), propget]
BSTR ControlObjectDescription();
[id(0x00000009), propput]
void ControlObjectDescription([in] BSTR rhs);
[id(0x0000000a), propget]
long ControlObjectVersion();
[id(0x0000000a), propput]
void ControlObjectVersion([in] long rhs);
[id(0x0000000b), propget]
BSTR ServiceObjectDescription();
[id(0x0000000b), propput]
void ServiceObjectDescription([in] BSTR rhs);
[id(0x0000000c), propget]
long ServiceObjectVersion();
[id(0x0000000c), propput]
void ServiceObjectVersion([in] long rhs);
[id(0x0000000d), propget]
BSTR DeviceDescription();
[id(0x0000000d), propput]
void DeviceDescription([in] BSTR rhs);
[id(0x0000000e), propget]
BSTR DeviceName();
[id(0x0000000e), propput]
void DeviceName([in] BSTR rhs);
[id(0x0000000f), propget]
long POSKeyData();
[id(0x0000000f), propput]
void POSKeyData([in] long rhs);
[id(0x00000010)]
long Open([in] BSTR DeviceName);
[id(0x00000011)]
long Close();
[id(0x00000012)]
long Claim([in] long Timeout);
[id(0x00000013)]
long Release();
[id(0x00000014)]
long CheckHealth([in] long Level);
[id(0x00000015)]
long ClearInput();
[id(0x00000016)]
long DirectIO(
[in] long Command,
[in, out] long* pData,
[in, out] BSTR* pString);
[id(0x00000017)]
void SOData([in] long Status);
[id(0x00000018)]
void SODirectIO(
[in] long EventNumber,
[in, out] long* pData,
[in, out] BSTR* pString);
[id(0x00000019)]
void SOError(
[in] long ResultCode,
[in] long ResultCodeExtended,
[in] long ErrorLocus,
[in, out] long* pErrorResponse);
[id(0x0000001a), propget]
VARIANT_BOOL AutoDisable();
[id(0x0000001a), propput]
void AutoDisable([in] VARIANT_BOOL rhs);
[id(0x0000001b), propget]
long BinaryConversion();
[id(0x0000001b), propput]
void BinaryConversion([in] long rhs);
[id(0x0000001c), propget]
long DataCount();
[id(0x0000001c), propput]
void DataCount([in] long rhs);
[id(0x0000001d), propget]
VARIANT_BOOL CapKeyUp();
[id(0x0000001d), propput]
void CapKeyUp([in] VARIANT_BOOL rhs);
[id(0x0000001e), propget]
long EventTypes();
[id(0x0000001e), propput]
void EventTypes([in] long rhs);
[id(0x0000001f), propget]
long POSKeyEventType();
[id(0x0000001f), propput]
void POSKeyEventType([in] long rhs);
[id(0x00000020)]
long SOProcessID();
[id(0x00000021), propget]
long CapPowerReporting();
[id(0x00000021), propput]
void CapPowerReporting([in] long rhs);
[id(0x00000022), propget]
long PowerNotify();
[id(0x00000022), propput]
void PowerNotify([in] long rhs);
[id(0x00000023), propget]
long PowerState();
[id(0x00000023), propput]
void PowerState([in] long rhs);
[id(0x00000024)]
void SOStatusUpdate([in] long Status);
};
[
uuid(9B4E1842-FF65-11CF-AA2E-0020AFA49D5A),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "POSKEYBOARDLib._DPOSKeyboardEvents")
]
dispinterface _DPOSKeyboardEvents {
properties:
methods:
[id(0x00000001)]
void DataEvent([in] long Status);
[id(0x00000002)]
void DirectIOEvent(
[in] long EventNumber,
[in, out] long* pData,
[in, out] BSTR* pString);
[id(0x00000003)]
void ErrorEvent(
[in] long ResultCode,
[in] long ResultCodeExtended,
[in] long ErrorLocus,
[in, out] long* pErrorResponse);
[id(0x00000004)]
void StatusUpdateEvent([in] long Status);
};
[
uuid(9B4E1843-FF65-11CF-AA2E-0020AFA49D5A),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "POSKEYBOARDLib.POSKeyboard")
]
coclass POSKeyboard {
interface _Object;
[default] dispinterface _DPOSKeyboard;
[default, source] dispinterface _DPOSKeyboardEvents;
};
};
Somehow my properties are listed as methods... Even if I add PreserveSig, it still writes 2 methods instead of making them properties.
What changes should I try to make it identical to the original tlb? Or at least make it work.
UPDATE: Found where I did not have DispIdAttribute on my events interface. Fixed that, but the VB6 app still fails with the same error.
You can't have a COM interface with names that overlap the IUnknown method names (QueryInterface, AddRef and Release).
Update
To have your C# class generate a dispinteface (ie. a IDisptach interface for OLE automation binding), decorate your class with ClassInterfaceAttribute:
[ClassInterface(ClassInterfaceType.AutoDispatch)]
class myClass
{
public string Foo {get;}
public long Bar();
}
This will generate the automation property Foo and method Bar, as opposed to a raw COM interface.
You ever tried to use the information contained in the link:
Visual Basic: Inspect COM Components Using the TypeLib Information Object Library
[EDIT]
See if tlbimp.exe tool can help you.
Well, I figured it out...
I decompiled with a vb6 decompiler on the target app and exported as a vb6 project.
Opened it with VS 2008, upgraded to VB .Net.
Ran the application and saw the error "cannot cast to IOleObject".
Did a google search, found out that System.Windows.Forms.Control
implements this interface, so inheriting from Control
fixed my issue.
来源:https://stackoverflow.com/questions/1614702/c-sharp-writing-a-com-server-properties-mapped-to-methods