F # Marshall structures with delegate type field

I have a native C library and I want to do some F # coding with it. The fact is that I get an exception:

System.TypeLoadException: Unable to throw a log field of type "LoggingModel": there is no marshaling support for this type.
in System.StubHelpers.ValueClassMarshaler.ConvertToNative (IntPtr dst, IntPtr src, IntPtr pMT, CleanupWorkList & pCleanupWorkList)
at FSI_0009.Initialize (flags ComponentOverrideFlags, LoggingModel & loggingModel, ThreadingModel & threadingModel, SchedulingModel & schedulingModel, IntPtr memoryModel)
in. $ FSI_0011.main @ () in D: \ dev_p \ f # \ FunBindings \ FunExample \ Environment.fs: line 16 Aborted due to an error

Here is the code:

module Interop [<CLSCompliant(true); Flags>] type LogTarget = | None = 0 | Console = 1 | Trace = 2 | Custom = 4 [<UnmanagedFunctionPointer(CallingConvention.Cdecl)>] type LogCallback = delegate of LogTarget * string * string * nativeint -> unit [<UnmanagedFunctionPointer(CallingConvention.Cdecl)>] type ReleaseCallback = delegate of nativeint -> unit [<Struct>] type LoggingModel = val mutable targets : LogTarget val mutable log : LogCallback val mutable deleteModel : ReleaseCallback val mutable userparam : IntPtr [<DllImport("CLIBRARY.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "txInitialize")>] [<MethodImpl(MethodImplOptions.ForwardRef)>] extern int Initialize(ComponentOverrideFlags flags, LoggingModel& loggingModel, ThreadingModel& threadingModel, SchedulingModel& schedulingModel, IntPtr memoryModel) module Environment let initialize = let mutable loggingModel = new LoggingModel() let mutable threadingModel = new ThreadingModel() let mutable schedulingModel = new SchedulingModel() Initialize(ComponentOverrideFlags.None, &loggingModel, &threadingModel, &schedulingModel, IntPtr.Zero) 

Basically, I get the above error when I try to execute the "initialize" function interactively.

I would really appreciate any help.

Update: I checked the code a little more and noticed that it works outside the interactive console, without crashing with exceptions. I need to provide a little more information for CLibrary. Meanwhile, if anyone knows what might cause this exception and how it can be prevented, I would really appreciate the answer.

+6
source share
2 answers

I think the problem is that the delegate of LogTarget * string * string * nativeint -> unit declares the delegate where the arguments are in curry. (This makes no sense to me, since a * b usually represents a tuple.)

Subtle difference delegate of (LogTarget * string * string * nativeint) -> unit declares a delegate with alternating arguments that will be compatible with the native function.

You can see this difference if you try to assign a .NET method to two different types of delegates:

 type Curried = delegate of int * int -> int type Tupled = delegate of (int * int) -> int //let a = new Curried (Math.Max) // doesn't compile let b = new Tupled (Math.Max) // works 
+2
source

Have you tried adding [<MarshalAsAttribute(UnmanagedType.FunctionPtr)>] to the LoggingModel?

 [<Struct>] type LoggingModel = val mutable targets : LogTarget [<MarshalAsAttribute(UnmanagedType.FunctionPtr)>] val mutable log : LogCallback [<MarshalAsAttribute(UnmanagedType.FunctionPtr)>] val mutable deleteModel : ReleaseCallback val mutable userparam : IntPtr 

IL code without this attribute:

 // Fields .field public class Interop.LogCallback log 

but with this attribute:

 // Fields .field public marshal(Func) class Interop.LogCallback log 

Without the marshal(Func) / MarshalAs attribute, the delegate cannot be configured even with the UnmanagedFunctionPointer attribute. It is not possible to test it using the native library.

0
source

All Articles