This one took a while to debug 馃槃
Note: All below is tested when compiling for 32-bit Windows, i.e. in rust: i686-pc-windows-msvc in C# x86.
This issue doesn't exist in x64 Windows as stdcall and cdecl calling conventions are equivalent there.
It also shouldn't exist on Unix platforms as those default to cdecl in C# (I believe that to be true - didn't check).
The ffi_service makes async functions by taking in an extra AsyncCallback. That callback has this definition: extern "C" fn(&T, *const c_void) -> ()>.
In C# we use these as follows:
- The function pointer is set to
Marshal.GetFunctionPointerForDelegate(_delegate)
- The void pointer is used for a sequential ID
All good, however the _delegate has type: delegate void AsyncCallbackCommon(IntPtr data, IntPtr callback_data)
Which by default uses stdcall calling conventions, whereas rust expects C calling convention (which currently is compatible with cdecl).
There are 2 possible solutions to this:
- define the callback in rust to use
extern "stdcall"
- Add the following attribute to the delegate type:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
Both should work in x86 and x64. I believe it would be most portable to set both sides to cdecl, i.e. in rust use extern "cdecl" and the attribute in C#. This would be most compatible with C as well.
Using cdecl should be most portable
Unfortunately I do not know how this translates to Python - I never worked with FFI in Python.
EDIT
Apparently you've already made the decision for callbacks generated with callback! macro - these seem to add the attribute to use Cdecl in c#.
Thus I would consider this a bug that the attribute is not generated for the async callback.
// Debug - write_type_definition_named_callback
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LogListenerNative(Utf8String.Unmanaged message, IntPtr callback_data); // 'True' native callback signature
public delegate void LogListenerDelegate(Utf8String message); // Our C# signature
This one took a while to debug 馃槃
Note: All below is tested when compiling for 32-bit Windows, i.e. in rust:
i686-pc-windows-msvcin C#x86.This issue doesn't exist in x64 Windows as stdcall and cdecl calling conventions are equivalent there.
It also shouldn't exist on Unix platforms as those default to cdecl in C# (I believe that to be true - didn't check).
The ffi_service makes async functions by taking in an extra
AsyncCallback. That callback has this definition:extern "C" fn(&T, *const c_void) -> ()>.In C# we use these as follows:
Marshal.GetFunctionPointerForDelegate(_delegate)All good, however the
_delegatehas type:delegate void AsyncCallbackCommon(IntPtr data, IntPtr callback_data)Which by default uses
stdcallcalling conventions, whereas rust expects C calling convention (which currently is compatible with cdecl).There are 2 possible solutions to this:
extern "stdcall"[UnmanagedFunctionPointer(CallingConvention.Cdecl)]Both should work in x86 and x64. I believe it would be most portable to set both sides to cdecl, i.e. in rust use
extern "cdecl"and the attribute in C#. This would be most compatible with C as well.Using cdecl should be most portable
Unfortunately I do not know how this translates to Python - I never worked with FFI in Python.
EDIT
Apparently you've already made the decision for callbacks generated with
callback!macro - these seem to add the attribute to use Cdecl in c#.Thus I would consider this a bug that the attribute is not generated for the async callback.