Marshalling a Delegate as a Callback Method
In dit voorbeeld ziet u hoe u gedelegeerden doorgeeft aan een niet-beheerde functie die functieaanwijzers verwacht. Een gemachtigde is een klasse die een verwijzing naar een methode kan bevatten en gelijk is aan een typeveilige functieaanwijzer of een callback-functie.
Notitie
Wanneer u een gemachtigde binnen een aanroep gebruikt, beschermt de algemene taalruntime de gemachtigde tegen garbagecollection voor de duur van die aanroep. Als de niet-beheerde functie echter de gemachtigde opslaat die moet worden gebruikt nadat de aanroep is voltooid, moet u de garbagecollection handmatig voorkomen totdat de onbeheerde functie is voltooid met de gemachtigde. Zie het HandleRef-voorbeeld en GCHandle-voorbeeld voor meer informatie.
In het callback-voorbeeld worden de volgende niet-beheerde functies gebruikt, weergegeven met de oorspronkelijke functiedeclaratie:
TestCallBack
geƫxporteerd uit PinvokeLib.dll.void TestCallBack(FPTR pf, int value);
TestCallBack2
geƫxporteerd uit PinvokeLib.dll.void TestCallBack2(FPTR2 pf2, char* value);
PinvokeLib.dll is een aangepaste niet-beheerde bibliotheek die een implementatie voor de eerder vermelde functies bevat.
In dit voorbeeld bevat de NativeMethods
klasse beheerde prototypes voor de TestCallBack
en TestCallBack2
methoden. Beide methoden geven een gemachtigde door aan een callback-functie als parameter. De handtekening van de gemachtigde moet overeenkomen met de handtekening van de methode die deze verwijst. De FPtr
en FPtr2
gedelegeerden hebben bijvoorbeeld handtekeningen die identiek zijn aan de DoSomething
en DoSomething2
methoden.
Prototypen declareren
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
Aanroepende functies
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