2015-11-06 45 views
0

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

// 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 

但我无法得到它的工作,但事件不会编译。我收到一个编译错误,说“参数不可选”。我也试着通过回调函数AddressOf,但我再次收到错误 - “AddressOf运算符的使用无效”。 现在我的问题是 - 我做错了什么?将回调函数从Visual Basic传递给C#并将其调用的正确方法是什么?

谢谢你的时间!

+0

如何使用'async'和'await'来代替回调? –

+0

其实我需要回拨,因为我要订阅。所以我的回调应该一次又一次地根据服务器响应来调用。 – nabroyan

+0

VBA没有代表。您是否考虑传递一个C#可以存储并在完成时调用的对象? – DanL

回答

0

任何包含泛型的东西都不是COM可见的,所以您的GetDataFromServerAction<MyCustomType>不是COM可见的。您必须在非泛型类上定义一个方法,而不使用泛型类型参数,也不使用泛型参数或返回类型。

在COM中传递回调的通常方式是将接口指针与要调用的方法一起传递。避免采用AddressOf的方法,但是可行的,一旦你想让回调工作在进程外,这是非常糟糕的做法。

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

要了解如何在VB6/VBA中执行此操作,请搜索VB_UserMemId。从本质上讲,你必须编辑在其原始格式的类文件(在VBA,则必须将其导出),并添加属性,如:

Sub Call() 
Attribute Call.VB_UserMemId = 0 
End Sub 

在VBA中,你会从编辑删除类和进口文件。结果是Call方法现在有DispId 0.您可以随意调用它,但请记住要编辑Sub名称和Attribute

在C#中,我认为实现这种调用的唯一途径与dynamic变量有:

obj[0] 

或通过Type.InvokeMember或类似IDispatch::Invoke方法:

obj.GetType().InvokeMember("", BindingFlags.InvokeMethod, null, obj, null); 

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

一般来说,如果你控制整个情况,并且你不需要可调用的对象,只需要一个普通的方法。

关于AddressOf错误,此操作符处理模块过程和函数,因此您看到的错误可能是因为DisplayOptionQuotes是一种方法。