将回调函数从Visual Basic传递给C#

时间:2015-11-06 11:02:23

标签: c# vba callback com

我有一个用C#编写的.dll,我在Visual Basic中使用它来制作一个Com对象。我从我的Visual Basic代码中调用C#函数。我对这项技术很陌生,遇到了这样的问题。在C#代码中,我有一个方法,它接收一个回调函数作为参数,从服务器获取数据然后调用该回调函数。现在我需要从我的Visual Basic代码中调用该函数并向其传递回调。 我认为应该看起来像这样

// C# dll
public bool GetDataFromServer(int someData1, Action<MyCustomType> callback, int someData2)
{
    // request to server, get data, create an object of MyCustomType
    // call callback and pass MyCustomType object to it as a parameter
}

// Visual Basic part
Public Sub DisplayData(ByRef resp As My_Dll.MyCustomType)
    ' do something with resp
End Sub

// call Dll method
My_Dll.GetDataFromServer(1, DisplayData, 2) ' I get a compile error

但我无法让它工作,事件无法编译。我收到一个编译错误,说&#34;参数不是可选的&#34;。我还尝试使用AddressOf传递回调函数,但我再次收到错误 - &#34;无效使用AddressOf运算符&#34;。 现在我的问题是 - 我做错了什么?将回调函数从Visual Basic传递给C#然后调用它的正确方法是什么。

感谢您的时间!

1 个答案:

答案 0 :(得分:0)

COM无法看到任何包含泛型的内容,因此GetDataFromServer Action<MyCustomType>的COM AddressOf不可见。您必须在非泛型类上定义一个方法,而不使用泛型类型参数,而不使用泛型参数或返回类型。

在COM中传递回调的常用方法是使用要调用的方法传递接口指针。避免使用IDispatch方法,无论多么可行,一旦你希望回调在进程外工作,这是非常糟糕的做法。

IDispatch::Invoke对象的一个​​常见技巧是使用DispId 0(DISPID_VALUE)定义一个带有DispId 0({{3}})的默认方法的类,COM服务器可以通过VB_UserMemId调用它。在某些语言中,例如JScript,可以通过这种技术调用对象。

要了解如何在VB6 / VBA中执行此操作,请搜索Sub Call() Attribute Call.VB_UserMemId = 0 End Sub 。实际上,您必须以原始格式编辑类文件(在VBA中,必须将其导出)并添加属性,例如:

Call

在VBA中,您将删除该类并从已编辑的文件中导入。结果是Sub方法现在显示为DispId 0.您可以随意调用它,但请记住同时编辑Attribute名称和dynamic

在C#中,我认为实现此类调用的唯一方法是使用obj[0] 变量:

Type.InvokeMember

或通过IDispatch::Invoke或类似的obj.GetType().InvokeMember("", BindingFlags.InvokeMethod, null, obj, null); 方法:

AddressOf

后者更可靠,你传递你想要的参数,而前者使用误导性语法并迫使你传递参数。

通常,如果你控制整个情况并且你不需要可调用的对象,那么只需要一个简单的方法。

关于DisplayOptionQuotes错误,此运算符适用于模块过程和函数,因此您看到的错误可能是因为public static IList<ForumTopicReply> getTopicRepliesByTopicId(int forumId, int categoryId, int topicId, string orderBy) { var ctx = new dataContext(); IList<ForumTopicReply> forumTopicReplies = (from r in ctx.ForumTopicReplies where r.ForumId == forumId && r.ForumCategoryId == categoryId && r.ForumTopicId == topicId orderby r.DateCreated descending select r).ToList(); return forumTopicReplies; } 是一种方法。