Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining a delegate as a function pointer

I am using a delegate which calls an unmanaged function pointer. This causes the Garbage Collector to collect it before it is used, as described in the CallbackOnCollectedDelegate MDA page on MSDN: MSDN page for CallbackOnCollectedDelegate MDA.

The resolution states that I have to marshal the appropriate delegate as an unmanaged function pointer. My initial reflex was to use:

[MarshalAs(UnmanagedType.FunctionPtr)]
public delegate void EntityCallback([MarshalAs(UnmanagedType.SysInt)] IntPtr entity);

However, the C# compiler won't let me marshal a delegate, even if this is the suggested resolution by MSDN. Moreover, the MSDN page only shows an example of the problem being thrown, but not one of the resolution.

How could I marshal my delegate as an unmanaged function pointer or keep it from being GCed?

EDIT: As suggested, I created a reference of the callback. Therefore, my code changed from/to:

// From:
foo.SetCallback(new EntityCallback(bar));

// To:
call = new EntityCallback(bar); // Referenced in class
foo.SetCallback(call);

Now this does work - but only in Debug mode. When I switch to Release, it crashes at the same point. Why is that?

EDIT 2: More complete code snippet:

public class Test
{
    private EntityCallback Call;

    private void Bar(System.IntPtr target)
    {
        ...
    }

    public Entity Foo { get; set; }

    public Test()
    {
        this.Foo = new Body.Sphere() { Visible = false }; // Irrelevant
        this.Foo.CollisionType = 3; // Irrelevant

        this.Call = new EntityCallback(this.Bar);

        this.Foo.SetCallback(this.Call, EntityCallbackType.Collision);
    }
}
like image 395
Lazlo Avatar asked Sep 11 '10 17:09

Lazlo


1 Answers

You didn't read it correctly. You must do this:

...change your code to keep a reference to that delegate on the managed side for the lifetime of the marshaled unmanaged function pointer.

In other words, just store a reference to the delegate instance in your class and make sure the class object survives long enough. Use a static if you really have to.

like image 192
Hans Passant Avatar answered Oct 12 '22 23:10

Hans Passant