I need some help fixing a persistent AccessViolationException.
Given a c signature like this
struct message {
char *topic;
void *payload;
int payloadlen;
};
__declspec(dllexport) void callback_set(struct data *dat, void (*on_publish)(struct data *, void *, const struct message *));
I have this C#
public struct message
{
public string topic;
public IntPtr payload;
public int payloadlen;
};
/* INTEROP ACCESS */
public delegate void on_publish(IntPtr dat, IntPtr usrData, IntPtr messageData);
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl)]
public extern static void callback_set(IntPtr dat, IntPtr callback);
/* IMPLEMENTATION OF OUR on_publish*/
public static void MessageHandler(IntPtr dat, IntPtr usrData, IntPtr messageData)
{
var instance = (message)Marshal.PtrToStructure(messageData, typeof(message));
string test = instance.topic; // <-- this is successfully received
Console.WriteLine("message rec " + test);
} //<-- as soon as I exit, the dll blows up with access violation
/* REGISTERING MESSAGEHANDLER AS ON_PUBLISH */
public static void RegisterMessageHandler(IntPtr dat) //<-- I promise, the pointer I send here is valid and not modified
{
messageHandler = new on_publish(MessageHandler);
messageHandlerPtr = Marshal.GetFunctionPointerForDelegate(messageHandler);
callback_set(dat, messageHandlerPtr); //<-- if I do not call this, everything works, no ADE
Console.WriteLine("message handler registered");
}
//just tried to move to scope in order to retain their managed memory loc
private static IntPtr messageHandlerPtr;
private static on_publish messageHandler;
When running, and making sure a message should be received - I get the correct string for the topic
but as soon as MessageHandler
returns, I get the dreaded exception.
Things I've tried:
- Change CallingConvention
- Use on_publish instead of IntPtr in managed callback_set definition
- Probably more things in desperation that should not have an impact
Any help much appreciated!
I can share a zip of the project if anyone can help - it will be BSD licensed just like Mosquitto which I'm trying to interop with.
I ended up creating a C++/CLI project to wrap the C project to .NET.
I found it much easier to manage the unmanaged code using C++, and I ended up with a nice interop to C# as my class became .NET accessible.
I would recommend this path, and will do it myself - the next time I need to integrate C# with a C lib.