将委托作为回调方法进行封送Marshaling a Delegate as a Callback Method

此示例演示如何将委托传递给需要函数指针的非托管函数。This sample demonstrates how to pass delegates to an unmanaged function expecting function pointers. 委托是可以容纳方法引用的类,等效于类型安全函数指针或回调函数。A delegate is a class that can hold a reference to a method and is equivalent to a type-safe function pointer or a callback function.

备注

在调用内使用委托时,公共语言运行时防止在该调用的持续时间内对委托执行垃圾回收。When you use a delegate inside a call, the common language runtime protects the delegate from being garbage collected for the duration of that call. 但是,如果非托管函数存储了该委托,以便在调用完成后使用,则必须手动防止垃圾回收,直到非托管函数结束对该委托的使用为止。However, if the unmanaged function stores the delegate to use after the call completes, you must manually prevent garbage collection until the unmanaged function finishes with the delegate. 有关详细信息,请参阅 HandleRef 示例GCHandle 示例For more information, see the HandleRef Sample and GCHandle Sample.

回调示例使用以下非托管函数(与其原始函数声明一同显示):The Callback sample uses the following unmanaged functions, shown with their original function declaration:

  • TestCallBack 从 PinvokeLib.dll 导出。TestCallBack exported from PinvokeLib.dll.

    void TestCallBack(FPTR pf, int value);
    
  • TestCallBack2 从 PinvokeLib.dll 导出。TestCallBack2 exported from PinvokeLib.dll.

    void TestCallBack2(FPTR2 pf2, char* value);
    

PinvokeLib.dll 是一种自定义的非托管库,包含上述函数的实现。PinvokeLib.dll is a custom unmanaged library that contains an implementation for the previously listed functions.

在此示例中,LibWrap 类包含 TestCallBackTestCallBack2 方法的托管原型。In this sample, the LibWrap class contains managed prototypes for the TestCallBack and TestCallBack2 methods. 这两种方法都作为参数将委托传递给回调函数。Both methods pass a delegate to a callback function as a parameter. 委托的签名必须匹配它引用的方法的签名。The signature of the delegate must match the signature of the method it references. 例如,FPtrFPtr2委托的签名与 DoSomethingDoSomething2 方法相同。For example, the FPtr and FPtr2 delegates have signatures that are identical to the DoSomething and DoSomething2 methods.

声明原型Declaring Prototypes

public delegate bool FPtr(int value);
public delegate bool FPtr2(String^ value);

public ref class LibWrap
{
public:
    // Declares managed prototypes for unmanaged functions.
    [DllImport("..\\LIB\\PinvokeLib.dll")]
    static void TestCallBack(FPtr^ cb, int value);

    [DllImport("..\\LIB\\PinvokeLib.dll")]
    static void TestCallBack2(FPtr2^ cb2, String^ value);
};
public delegate bool FPtr(int value);
public delegate bool FPtr2(string value);

public class LibWrap
{
    // Declares managed prototypes for unmanaged functions.
    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void TestCallBack(FPtr cb, int value);

    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void TestCallBack2(FPtr2 cb2, string value);
}

Public Delegate Function FPtr(ByVal value As Integer) As Boolean
Public Delegate Function FPtr2(ByVal value As String) As Boolean

Public Class LibWrap
    ' Declares managed prototypes for unmanaged functions.
    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Shared Sub TestCallBack(
        ByVal cb As FPtr, ByVal value As Integer)
    End Sub

    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Shared Sub TestCallBack2(
        ByVal cb2 As FPtr2, ByVal value As String)
    End Sub
End Class

调用函数Calling Functions

public ref class App
{
public:
    static void Main()
    {
        FPtr^ cb = gcnew FPtr(&App::DoSomething);
        LibWrap::TestCallBack(cb, 99);
        FPtr2^ cb2 = gcnew FPtr2(&App::DoSomething2);
        LibWrap::TestCallBack2(cb2, "abc");
    }

    static bool DoSomething(int value)
    {
        Console::WriteLine("\nCallback called with param: {0}", value);
        // ...
        return true;
    }

    static bool DoSomething2(String^ value)
    {
        Console::WriteLine("\nCallback called with param: {0}", value);
        // ...
        return true;
    }
};
public class App
{
    public static void Main()
    {
        FPtr cb = new FPtr(App.DoSomething);
        LibWrap.TestCallBack(cb, 99);
        FPtr2 cb2 = new FPtr2(App.DoSomething2);
        LibWrap.TestCallBack2(cb2, "abc");
    }

    public static bool DoSomething(int value)
    {
        Console.WriteLine($"\nCallback called with param: {value}");
        // ...
        return true;
    }

    public static bool DoSomething2(string value)
    {
        Console.WriteLine($"\nCallback called with param: {value}");
        // ...
        return true;
    }
}
Public Class App
    Public Shared Sub Main()
        Dim cb As FPtr = AddressOf App.DoSomething
        Dim cb2 As FPtr2 = AddressOf App.DoSomething2
        LibWrap.TestCallBack(cb, 99)
        LibWrap.TestCallBack2(cb2, "abc")
    End Sub 'Main

    Public Shared Function DoSomething(ByVal value As Integer) As Boolean
        Console.WriteLine(ControlChars.CrLf + $"Callback called with param: {value}")
        ' ...
        Return True
    End Function

    Public Shared Function DoSomething2(ByVal value As String) As Boolean
        Console.WriteLine(ControlChars.CrLf + $"Callback called with param: {value}")
        ' ...
        Return True
    End Function
End Class

请参阅See also