Marshalling di un delegato come metodo di callback
Questo esempio dimostra come passare delegati a una funzione non gestita che prevede puntatori a funzione. Un delegato è una classe che può contenere un riferimento a un metodo ed è equivalente a un puntatore a una funzione indipendente dai tipi o a una funzione di callback.
Nota
Quando si usa un delegato all'interno di una chiamata, Common Language Runtime protegge il delegato per evitare che venga sottoposto a Garbage Collection per la durata della chiamata. Tuttavia, se la funzione non gestita archivia il delegato da usare dopo il completamento della chiamata, è necessario evitare manualmente operazioni di Garbage Collection fino a quando la funzione non gestita non ha terminato di usare il delegato. Per altre informazioni, vedere Esempio di HandleRef ed Esempio di GCHandle.
Nell'esempio di callback vengono usate le seguenti funzioni non gestite, illustrate con le dichiarazioni di funzione originali:
TestCallBack
esportata da PinvokeLib.dll.void TestCallBack(FPTR pf, int value);
TestCallBack2
esportata da PinvokeLib.dll.void TestCallBack2(FPTR2 pf2, char* value);
PinvokeLib.dll è una libreria non gestita personalizzata contenente un'implementazione per le funzioni elencate in precedenza.
In questo esempio, la classe NativeMethods
contiene prototipi gestiti per i metodi TestCallBack
e TestCallBack2
. Entrambi i metodi di passano un delegato a una funzione di callback come parametro. La firma del delegato deve corrispondere alla firma del metodo a cui fa riferimento. Ad esempio, i delegati FPtr
e FPtr2
hanno firme identiche ai metodi DoSomething
e DoSomething2
.
Dichiarazione dei prototipi
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
Funzioni chiamanti
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