Oggi ho scoperto un interessante aggiunta alla classe Marshal di System.InteropServices nel Framework 2.0, ovvero il metodo GetDelegateForFunctionPointer.
Questo metodo permette di castare un puntatore a funzione verso un delegate compatibile con la firma della funzione target, aprendo perciò la strada al dynamic P-Invoke.
Questo esempio (fatto volutamente in VB... ) dimostra come sfruttare tale metodo...
Imports System.Runtime.InteropServices
Module Demo
'//Win32 functions
"kernel32")> Public Function LoadLibrary(ByVal dllName As String) As IntPtr
End Function
"kernel32")> Public Function GetProcAddress(ByVal hModule As IntPtr, ByVal procName As String) As IntPtr
End Function
"kernel32")> Public Function FreeLibrary(ByVal hModule As IntPtr) As Boolean
End Function
'//Delegate definition
Public Delegate Function sndPlaySound(<MarshalAs(UnmanagedType.LPWStr)> ByVal name As String, ByVal sound As UInt32) As Boolean
Sub Main()
'//Load library containing sndPlaySound
Dim hModule As IntPtr = LoadLibrary("winmm.dll")
'//Get fn pointer to sndPlaySound (Unicode)
Dim ptr As IntPtr = GetProcAddress(hModule, "sndPlaySoundW")
'//Cast fn Pointer to a compatible delegate
Dim fn As sndPlaySound = TryCast(Marshal.GetDelegateForFunctionPointer(ptr, GetType(sndPlaySound)), sndPlaySound)
'//Play sound syncronously
fn("c:\windows\media\tada.wav", &H20000)
'//Discard loaded library
If (FreeLibrary(hModule)) Then
Console.WriteLine("Library successfully discarded")
Else
Console.WriteLine("Failed to discard library")
End If
End Sub
End Module
Ovviamente esiste anche GetFunctionPointerForDelegate().
Anche se non credo sia una funzionalità che utilizzeremo tutti i giorni, sopratutto con l'avvento di WinFx, come diceva una vecchia pubblicità: "E' bello sapere che c'è...."