Looking for some pointers (no pun intended...) as to the best approach for this scenario.
So, I have a DLL (Provided Externally) that has the following exported function:
typedef std::function<void (
unsigned int msgType,
unsigned int size,
const char* const value
) > SCallback;
__declspec(dllexport) int StartS( SCallback fnS );
I'm attempting to call this from a C# Console Application, and this is what I am doing:
[DllImport("SeqLib.dll", EntryPoint = "?StartS@SApi@@YAKV?$function@$$A6AXIIPBD@Z@std@@@Z", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int StartS(DCallback cb);
public delegate void DCallback(int msgType, int size, IntPtr value);
public static void MessageReceived(int msgType, int size, IntPtr value)
{
return 0;
}
DCallback callback = new DCallback(MessageReceived);
StartS(callback);
Running this gives:
System.AccessViolationException: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Exception aside, is there something wrong with the basic approach above? Can anyone advise on the correct approach to calling an exported function that has a std::function parameter as above?
Thanks in advance.
Looking for some pointers (no pun intended...) as to the best approach for this scenario.
So, I have a DLL (Provided Externally) that has the following exported function:
typedef std::function<void (
unsigned int msgType,
unsigned int size,
const char* const value
) > SCallback;
__declspec(dllexport) int StartS( SCallback fnS );
I'm attempting to call this from a C# Console Application, and this is what I am doing:
[DllImport("SeqLib.dll", EntryPoint = "?StartS@SApi@@YAKV?$function@$$A6AXIIPBD@Z@std@@@Z", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int StartS(DCallback cb);
public delegate void DCallback(int msgType, int size, IntPtr value);
public static void MessageReceived(int msgType, int size, IntPtr value)
{
return 0;
}
DCallback callback = new DCallback(MessageReceived);
StartS(callback);
Running this gives:
System.AccessViolationException: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Exception aside, is there something wrong with the basic approach above? Can anyone advise on the correct approach to calling an exported function that has a std::function parameter as above?
Thanks in advance.
Share Improve this question asked Jan 31 at 10:29 MikeMike 5654 silver badges12 bronze badges 5 |1 Answer
Reset to default -2You need to use extern "C"
to prevent name mangling. And you need to specify the calling convention on the delegate.
You should also use string
on the value
parameter and marshal it properly
extern "C" {
__declspec(dllexport) int StartS( SCallback fnS );
}
And in C#
[DllImport("SeqLib.dll", EntryPoint = "StartS", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int StartS(DCallback cb);
[UnamangedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public delegate void DCallback(int msgType, int size, string value);
If the C++ side holds on to the function pointer in global state past the end of the function then you need to keep the delegate alive. For example, put it into a field.
private DCallback _callback = MessageReceived;
private void SetCallback()
{
_ = StartS(callback);
}
Note that C# cannot handle C++ objects such as smart pointers and classes. You must only use basic types such as numbers, string pointers and array pointers. C# also can't usually free the pointers correctly, you'd need to free them on the C++ side.
extern "C"
to prevent name mangling. @PepijnKramer That is really not correct, it's perfectly possible to use C++ functions, you just need to prevent mangling and not use C++ objects (as C++ can't interact or destroy them) – Charlieface Commented Jan 31 at 12:06