我有一个Delphi编写的DLL,它向vb.net应用程序公开了一些接口。 接口继承自IUnknown(但如果需要可以更改),简化示例:
IWindow = interface(IUnknown)
['{E9A11D0B-8A05-4CBA-83FA-C5CC6818DF6E}']
function GetCaption(var Caption: PChar): HRESULT; stdcall;
end;
vb.net应用程序中的相同界面:
<ComImport(), Guid("E9A11D0B-8A05-4CBA-83FA-C5CC6818DF6E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Public Interface IWindow
ReadOnly Property Caption() As <MarshalAs(UnmanagedType.LPWStr)> String
End Interface
一切正常。
现在我想将IWindow的集合转移到vb.net,在vb.net应用程序中,我希望能够通过for循环遍历它。
我读过可以使用IEnumerable / IEnumerator,但我不太明白如何实现它们。有没有关于此的好的教程,特别是双方的声明?示例代码会很棒。
请注意,我不想创建应该注册和导入的com dll。目前我导出的功能使我能够获得接口。
答案 0 :(得分:0)
我有一个解决方案,但我并不完全满意。我把它放在这里作为答案,希望其他人的评论可以改进它,或者(甚至更好)将提供更好的答案。
我发现IEnumerator和IEnumerable的Delphi声明(Delphi 2010)没有使用stdcall调用约定所以我声明它们是这样的:
IEnumerator = interface(IInterface)
['{496B0ABE-CDEE-11D3-88E8-00902754C43A}']
function MoveNext: Boolean; safecall;
function GetCurrent: IWindow; safecall;
function Reset: HResult; stdcall;
end;
IEnumerable = interface(IInterface)
['{496B0ABE-CDEE-11D3-88E8-00902754C43A}']
function GetEnumerator(var Enumerator: IEnumerator): HRESULT; stdcall;
end;
我的集合接口继承自IEnumerable(但它有自己的GUID):
IWindows = interface(IEnumerable)
['{D9174D5A-4946-4E5A-95B1-2CD521C3BF73}']
end;
该类实现了IEnumerable,IEnumerator和IEnumVariant。 我认为我可以删除IEnumerator但我需要做更多测试才能确认。
TIWindows = class(TInterfacedObject, IWindows, IEnumerable, IEnumVariant)
在VB.NET方面,它看起来像这样:
<ComImport(), Guid("D9174D5A-4946-4E5A-95B1-2CD521C3BF73"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Public Interface IWindows
Inherits IEnumerable
Shadows Function GetEnumerator() As IEnumerator
End Interface
我必须覆盖GetEnumerator,因为如果我不这样做,我会得到一个空引用异常,而在Delphi端,从不调用GetEnumerator()(VMT偏移问题?)。
主叫代码:
Dim Windows As IWindows
Dim Window As IWindow
Try
Windows = Session.TopLevelWindows
For Each Window In Windows
TextBox1.Text = TextBox1.Text & Window.Caption
Next
Catch ex As Exception
' Handle Exception
End Try
作为IWindow的Dim Windows需要使它工作,没有它我得到错误:“对象引用未设置为对象的实例。”
我尝试在vb.net端使用generic:
阴影函数GetEnumerator()As IEnumerator(Of IDNKWindow)
但是它给出了错误:无法编组“返回值”:通用类型无法编组。