2015-08-28 16 views
6

Mam natywną bibliotekę C i chcę zrobić z nią kodowanie F #. Chodzi o to, otrzymuję wyjątek:F # Konstrukcje Marshalla z polem typu delegata

System.TypeLoadException: Nie można feldmarszałek „log” typu „LoggingModel”: Nie ma wsparcia Organizowanie tego typu.
w System.StubHelpers.ValueClassMarshaler.ConvertToNative (IntPtr DST IntPtr SRC IntPtr PMT CleanupWorkList & pCleanupWorkList)
w FSI_0009.Initialize (ComponentOverrideFlags flag, LoggingModel & loggingModel, ThreadingModel & ThreadingModel, SchedulingModel & schedulingModel, IntPtr memoryModel)
na $ FSI_0011.main @() w . D: \ dev_p \ f # \ FunBindings \ FunExample \ Environment.fs: linia 16 przerwane z powodu błędu

Oto kod:

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) 

Zasadniczo, pojawia się wspomniany błąd, gdy próbuję wykonać „zainicjować” funkcję w interaktywny.

Byłbym wdzięczny za każdą pomoc.

Aktualizacja: Sprawdziłem kod nieco więcej i zauważyłem, że poza konsolą interaktywną wydaje się działać, bez żadnych wyjątków. Muszę zapewnić nieco więcej zasięgu dla biblioteki, aby mieć pewność. W międzyczasie, jeśli ktoś, kto wie, co może spowodować ten wyjątek i jak można mu zapobiec, naprawdę byłbym wdzięczny za odpowiedź.

Odpowiedz

2

Myślę, że problem polega na tym, że delegate of LogTarget * string * string * nativeint -> unit deklaruje delegata, w którym argumenty są wymieniane. (To nie ma dla mnie sensu, ponieważ a * b normalnie reprezentuje krotkę.)

Subtelnie odmienna delegate of (LogTarget * string * string * nativeint) -> unit deklaruje delegata z potkniętymi argumentami, które byłyby zgodne z natywną funkcją.

Można zobaczyć tę różnicę, jeśli spróbujesz przypisać metody .NET do dwóch różnych typów delegatów:

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 
+0

Przepraszam, Tim, to nie pomogło. Będę edytować pytanie z pełnymi informacjami o wyjątku. – PompolutZ

0

Czy próbowałeś dodanie [<MarshalAsAttribute(UnmanagedType.FunctionPtr)>] do 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 

kod IL bez tego atrybutu:

// Fields 
.field public class Interop.LogCallback log 

ale z tego atrybutu:

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

Bez marshal(Func)/MarshalAs przypisują delegat nie może zostać zgromadzona nawet z atrybutem UnmanagedFunctionPointer. Nie można tego przetestować w bibliotece natywnej.

+0

Tak, próbowałem już wcześniej. Niestety to nie pomaga. Ten sam błąd. – PompolutZ

+0

Czy próbowałeś również dodać odpowiednie MarshalAs do argumentów funkcji w 'typ LogCallback = delegat (LogTarget * string * string * nativeint) -> unit', np. '] target: LogTarget'? Prawdopodobnie wyliczenie nie ma domyślnego zestawienia. –

+0

Cześć, właśnie próbowałem i wydaje się, że pozostaje. Wyjątek nadal wskazuje na pole dziennika. – PompolutZ