Маршалинг делегата как метода обратного вызова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.

В этом примере класс NativeMethods содержит управляемые прототипы методов TestCallBack и TestCallBack2.In this sample, the NativeMethods 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. Например, подписи делегатов для FPtr и FPtr2 аналогичны методам DoSomething и DoSomething2.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);

private ref class NativeMethods
{
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);

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

    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal 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

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

    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Friend 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);
        NativeMethods::TestCallBack(cb, 99);
        FPtr2^ cb2 = gcnew FPtr2(&App::DoSomething2);
        NativeMethods::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);
        NativeMethods.TestCallBack(cb, 99);
        FPtr2 cb2 = new FPtr2(App.DoSomething2);
        NativeMethods.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
        NativeMethods.TestCallBack(cb, 99)
        NativeMethods.TestCallBack2(cb2, "abc")
    End Sub

    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