LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Reg Event Callback not working with .NET DLL written in F#

I have a .NET DLL written in F# which contains some CLR events.

While I can see a list of all events contained within a class in the DLL in the Reg Event Callback function, the events never cause the callback VI to be called.

I have written an example in C# where everything works fine (even with .NET 4.6). If I write the same functionality in F#, the events never appear to be received in LabView. With F# I have tried with .NET version 3.0-4.6.

 

What on earth could be the cause of this?

0 Kudos
Message 1 of 10
(3,781 Views)

@kasperh wrote:

I have a .NET DLL written in F# which contains some CLR events.

While I can see a list of all events contained within a class in the DLL in the Reg Event Callback function, the events never cause the callback VI to be called.

I have written an example in C# where everything works fine (even with .NET 4.6). If I write the same functionality in F#, the events never appear to be received in LabView. With F# I have tried with .NET version 3.0-4.6.

 

What on earth could be the cause of this?


I am assuming that F# compiles the events to IL using add_* and remove_* methods to a private delegate and labels the methods with metadata describing them as an event. This is what the C# compiler does and I presume that F# "events" compile the same although I have never tried this.

 

Can you post your examples in C# and F#?

0 Kudos
Message 2 of 10
(3,727 Views)

Sure. The [<CLIEvent>] attribute instructs the compiler to use the add_ and remove_.

 

The F# I have used

 

namespace LabViewEventTest.FSharp

type FSharpClass() =
    let someEvent = new Event<string>()

    [<CLIEvent>]
    member this.SomethingHappened = someEvent.Publish

    member this.ActionThatCausesEvent() =
        someEvent.Trigger("Something happened in F#")

The C#

namespace LabViewEventTest
{
    public class CSharpClass
    {
        public event EventHandler<string> SomethingHappened;

        public void ActionThatCausesEvent()
        {
            SomethingHappened?.Invoke(this, "Something happened in C#");
        }
    }
}
0 Kudos
Message 3 of 10
(3,702 Views)

@kasperh wrote:

Sure. The [<CLIEvent>] attribute instructs the compiler to use the add_ and remove_.

 

The F# I have used

 

namespace LabViewEventTest.FSharp

type FSharpClass() =
    let someEvent = new Event<string>()

    [<CLIEvent>]
    member this.SomethingHappened = someEvent.Publish

    member this.ActionThatCausesEvent() =
        someEvent.Trigger("Something happened in F#")

The C#

namespace LabViewEventTest
{
    public class CSharpClass
    {
        public event EventHandler<string> SomethingHappened;

        public void ActionThatCausesEvent()
        {
            SomethingHappened?.Invoke(this, "Something happened in C#");
        }
    }
}

Interesting. Presumably the metadata is intact; the CTS defines events and the event structure so I would be suprised if F# did not comply with this. Have you compared the IL?

0 Kudos
Message 4 of 10
(3,660 Views)

The IL produced by F# and C#:

 

FSharpClass.add_SomethingHappened

 

IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldfld       Query_zfrpxs+FSharpClass.someEvent
IL_0007:  callvirt    Microsoft.FSharp.Control.FSharpEvent<System.String>.get_Publish
IL_000C:  ldarg.1     
IL_000D:  tail.       
IL_000F:  callvirt    Microsoft.FSharp.Control.IDelegateEvent<Microsoft.FSharp.Control.FSharpHandler<System.String>>.AddHandler
IL_0014:  ret   
CSharpClass.add_SomethingHappened:
IL_0000:  ldarg.0     
IL_0001:  ldfld       UserQuery+Class1.SomethingHappened
IL_0006:  stloc.0     
IL_0007:  ldloc.0     
IL_0008:  stloc.1     
IL_0009:  ldloc.1     
IL_000A:  ldarg.1     
IL_000B:  call        System.Delegate.Combine
IL_0010:  castclass   System.EventHandler<System.String>
IL_0015:  stloc.2     
IL_0016:  ldarg.0     
IL_0017:  ldflda      UserQuery+Class1.SomethingHappened
IL_001C:  ldloc.2     
IL_001D:  ldloc.1     
IL_001E:  call        System.Threading.Interlocked.CompareExchange
IL_0023:  stloc.0     
IL_0024:  ldloc.0     
IL_0025:  ldloc.1     
IL_0026:  ceq         
IL_0028:  ldc.i4.0    
IL_0029:  ceq         
IL_002B:  stloc.3     
IL_002C:  ldloc.3     
IL_002D:  brtrue.s    IL_0007
IL_002F:  ret         

 

But F# does indeed generate the add_ function.

0 Kudos
Message 5 of 10
(3,623 Views)

What about the metadata tags information for both methods?

0 Kudos
Message 6 of 10
(3,592 Views)

For F#:

	Method #2 (06000002) 
	-------------------------------------------------------
		MethodName: add_SomethingHappened (06000002)
		Flags     : [Public] [HideBySig] [ReuseSlot] [SpecialName]  (00000886)
		RVA       : 0x00002068
		ImplFlags : [IL] [Managed]  (00000000)
		CallCnvntn: [DEFAULT]
		hasThis 
		ReturnType: Void
		1 Arguments
			Argument #1:  GenericInst Class Microsoft.FSharp.Control.FSharpHandler`1< String>
		1 Parameters
			(1) ParamToken : (08000001) Name : handler flags: [none] (00000000)

And C#:

	Method #1 (06000001) 
	-------------------------------------------------------
		MethodName: add_SomethingHappened (06000001)
		Flags     : [Public] [HideBySig] [ReuseSlot] [SpecialName]  (00000886)
		RVA       : 0x00002050
		ImplFlags : [IL] [Managed]  (00000000)
		CallCnvntn: [DEFAULT]
		hasThis 
		ReturnType: Void
		1 Arguments
			Argument #1:  GenericInst Class System.EventHandler`1< String>
		1 Parameters
			(1) ParamToken : (08000001) Name : value flags: [none] (00000000)
		CustomAttribute #1 (0c000001)
		-------------------------------------------------------
			CustomAttribute Type: 0a00000f
			CustomAttributeName: System.Runtime.CompilerServices.CompilerGeneratedAttribute :: instance void .ctor()
			Length: 4
			Value : 01 00 00 00                                      >                <
			ctor args: ()

 

0 Kudos
Message 7 of 10
(3,579 Views)

Rather than asking a bunch more questions, check out the metadata for the assembly, in particular the tables, for the following:  http://flylib.com/books/en/2.663.1.93/1/. Hopefully the content should line up.

0 Kudos
Message 8 of 10
(3,573 Views)

I have now looked at the two sets of metadata, and I don't see any particular difference in what they describe. I wouldn't expect there to be, as the events work fine outside LabVIEW.

0 Kudos
Message 9 of 10
(3,525 Views)

I have fixed this now.

It appears that for the event to work properly in LabVIEW it's necessary to use an custom delegate (or the EventHandler delegate).

 

let someEvent = new Event<EventHandler<string>, string>()
Message 10 of 10
(3,482 Views)