Q:

Passing managed event handler to unmanaged code in Linux

I've been writing a .Net Core C# wrapper for an existing C++ library that will run under Linux. The library has the following:
int newrelic_record_metric(const char *name, double value);

void newrelic_register_message_handler(void*(*handler)(void*));

void *newrelic_message_handler(void *raw_message);

The first method is easy enough to wrap:
internal static class AgentSdkWrapper {
    [DllImport("newrelic-transaction")]
    public static extern unsafe int newrelic_record_metric(StringBuilder name, double value);

I'm struggling with the signature of the second version, I don't know how I would translate that to C#. I understand I'm dealing with void pointers, but I'm unsure what to do with them.
Also, according to the library docs, I need to register the third method as a callback to the second method:

You must register the required callback that will send data to New Relic when transactions are  completed. You will need to register the default newrelic_message_handler callback that has already been defined:
newrelic_register_message_handler(newrelic_message_handler);

I presume I need to assign newrelic_message_handler to a C# delegate and pass that into newrelic_register_message_handler, but I'm unclear how I get there.

A:

If I understood the doc correctly you just need to pass a pointer to newrelic_message_handler to the second function.
It means that for all intents and purposes your 2nd function will look like this:
[DllImport(...)]
static extern void newrelic_register_message_handler(IntPtr handler);

Because actually you are just passing a pointer and don't really care about types.
To get a pointer to newrelic_message_handler (assuming that this is a dll exported function) you need to use GetProcAdress
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

[DllImport("kernel32", SetLastError = true)]
static extern IntPtr LoadLibrary(string lpFileName);

And your final code will be:
var module = LoadLibrary("newrelic-transaction");
var proc = GetProcAddress(module, "newrelic_message_handler");
newrelic_register_message_handler(proc);

