Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Marshall structs with field of delegate type

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

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

Here 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 aforementioned error when I try to execute "initialize" function in interactive.

I would really appreciate any help.

Update: I've checked the code a bit more and noticed that outside of the interactive console it seems to be working, without failing with exceptions. I need to provide a bit more coverage for CLibrary to be sure. Meanwhile, if there anybody who knows what could cause this exception and how it could be prevented, I would really appreciate the answer.

like image 676
fxdxpz Avatar asked Aug 28 '15 09:08

fxdxpz


1 Answers

I think the problem is that delegate of LogTarget * string * string * nativeint -> unit declares a delegate where the arguments are curried. (This doesn't really make sense to me either since a * b normally represents a tuple.)

The subtly different delegate of (LogTarget * string * string * nativeint) -> unit declares a delegate with tupled arguments which would be compatible with a native function.

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

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
like image 152
Tim Rogers Avatar answered Sep 30 '22 20:09

Tim Rogers