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