A fairly common idiom in C is for functions taking a polymorphic closure to represent this as two arguments, a function pointer and void pointer (which is passed as one of the arguments to the function pointer.
An example taken from the GPGME library:
typedef gpgme_error_t (*gpgme_passphrase_cb_t) (void *hook,
const char *uid_hint,
const char *passphrase_info,
int prev_was_bad,
int fd);
void gpgme_set_passphrase_cb (gpgme_ctx_t ctx,
gpgme_passphrase_cb_t cb,
void *hook_value);
Conceptually, the function pointer plus void pointer represent the same thing as a delegate in C# (a closure). Is there a nice, canonical way to marshal a delegate when making this sort of P/Invoke call?
Is there a nice, canonical way to marshal a delegate when making this sort of P/Invoke call?
You don't need to use the void*
parameter because a C# delegate is a closure. Pass IntPtr.Zero
as the hook value. Your C# delegate still needs to accept the void*
parameter but it can simply ignore it since it does not need it.
The other answers are correct, however, I just wanted to append some C#9 information:
It is now possible to use function pointers in C# as follows (requires unsafe
to be enabled):
static int add(int a, int b) => a + b;
delegate*<int, int, int> pointer = &add;
int result = add(40, 2);
Function pointers such as in the code snippet above are internally handled as nint
(or IntPtr
) and can be used in P/Invoke declarations:
[DllImport("my_library.dll")]
static extern int CallMyCallback(delegate*<int, int, int> callback, int arg1, int arg2);
An example C++ implementation of my_library.dll
could be:
extern "C" __declspec(dllexport) int CallMyCallback(
int (*callback)(int, int),
int arg1,
int arg2)
{
return callback(arg1, arg2);
}
CallMyCallback
could be used as follows (from C#):
static int multiply(int a, int b) => a * b;
int result = CallMyCallback(&multiply, -12, 7);
Note: This language feature cannot be used with lambda-expressions or non-static methods (instance methods require an implicit this
-pointer to be passed).
The official documentation does not exist yet, but you can take a look at the C#9 GitHub issue/tracker: https://github.com/dotnet/csharplang/issues/191
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With