callback function from unmanaged dll using DllImport and delegate

B

Bart Burkhardt

Hi, I could use some help in setting a C# callback function that an
external unmanaged dll will call on a event. Using a delegate and use
the external callback set function doesn't work.
The carbage collector says hello here (-;

I have pasted some code below, any help is greatly appreciated!

//Bart


public delegate void HercEventCallbackHandler(HercAction dwAction, uint
dwValue, uint userInstance);

[DllImport("HERC.dll")]
public static extern bool
HERC_EventCallbackSet(HercEventCallbackHandler HERCPROC_DeckA,
HercEventCallbackHandler HERCPROC_DeckB, uint userInstance);

public void HercEventCallbackHandlerA(HercAction dwAction, uint
dwValue, uint userInstance)
{
//process the event
}


public Form1()
{
HERC_EventCallbackSet(HercEventCallbackHandlerA,
HercEventCallbackHandlerB, 69);
}



Exception info:

A callback was made on a garbage collected delegate of type
'Hertest!Hertest.Form1+HercEventCallbackHandler::Invoke'. This may
cause application crashes, corruption and data loss. When passing
delegates to unmanaged code, they must be kept alive by the managed
application until it is guaranteed that they will never be called.
 
M

Michael C

Bart Burkhardt said:
Hi, I could use some help in setting a C# callback function that an
external unmanaged dll will call on a event. Using a delegate and use
the external callback set function doesn't work.
The carbage collector says hello here (-;

You need to create an instance of a delegate. I'm not familiar with your
example so it will be easier if I explain with something I know, EnumWindows

//here's the definition for EnumChildWindows
[DllImport("user32")]
private static extern int EnumChildWindows(IntPtr hWndParent,
EnumWindowsProcDelegate lpEnumFunc, int lParam);

//And the definition for the delegate
private delegate int EnumWindowsProcDelegate(IntPtr hWnd, int lParam);

//the definition for the callback function
private int EnumWindowProc(IntPtr hWnd, int lParam)
{
}

//calling EnumChildWindows
EnumChildWindows(Parent.Handle, new
EnumWindowsProcDelegate(this.EnumWindowProc), 0);

note this is the incorrect way to call it because the garbage collector
might collect the instance of the delegate. (it might not also because all
the callbacks happen before the function returns, i'm not exactly sure what
would happen in this situation). The correct way to call it would be
something like this:
EnumWindowsProcDelegate del = new
EnumWindowsProcDelegate(this.EnumWindowProc);
EnumChildWindows(Parent.Handle, del, 0);

that way it is certain the delegate would NOT be disposed while callbacks
are being fired. In your case because you have a SetCallback type of
function it is essential to keep a refererence to the delegate alive the
entire time callbacks are likely to occur.

I'm off the check my code as it's possible i have the same problem in
several places!!

Michael
 
B

Bart Burkhardt

Hi Michael,

I tried this;

HercEventCallbackHandler delA = new
HercEventCallbackHandler(this.HercEventCallbackHandlerA);

HercEventCallbackHandler delB = new
HercEventCallbackHandler(this.HercEventCallbackHandlerB);
HERC_EventCallbackSet(delA, delB, 69);

But the delegates still are being disposed.

Any ideas?

//Bart


Michael C schreef:
Bart Burkhardt said:
Hi, I could use some help in setting a C# callback function that an
external unmanaged dll will call on a event. Using a delegate and use
the external callback set function doesn't work.
The carbage collector says hello here (-;

You need to create an instance of a delegate. I'm not familiar with your
example so it will be easier if I explain with something I know, EnumWindows

//here's the definition for EnumChildWindows
[DllImport("user32")]
private static extern int EnumChildWindows(IntPtr hWndParent,
EnumWindowsProcDelegate lpEnumFunc, int lParam);

//And the definition for the delegate
private delegate int EnumWindowsProcDelegate(IntPtr hWnd, int lParam);

//the definition for the callback function
private int EnumWindowProc(IntPtr hWnd, int lParam)
{
}

//calling EnumChildWindows
EnumChildWindows(Parent.Handle, new
EnumWindowsProcDelegate(this.EnumWindowProc), 0);

note this is the incorrect way to call it because the garbage collector
might collect the instance of the delegate. (it might not also because all
the callbacks happen before the function returns, i'm not exactly sure what
would happen in this situation). The correct way to call it would be
something like this:
EnumWindowsProcDelegate del = new
EnumWindowsProcDelegate(this.EnumWindowProc);
EnumChildWindows(Parent.Handle, del, 0);

that way it is certain the delegate would NOT be disposed while callbacks
are being fired. In your case because you have a SetCallback type of
function it is essential to keep a refererence to the delegate alive the
entire time callbacks are likely to occur.

I'm off the check my code as it's possible i have the same problem in
several places!!

Michael
 
B

Bart Burkhardt

I found a solution, using a GCHandler the delegates are not disposed.
It works fine now!

HercEventCallbackHandler delA = new
HercEventCallbackHandler(this.HercEventCallbackHandlerA);

HercEventCallbackHandler delB = new
HercEventCallbackHandler(this.HercEventCallbackHandlerB);

GCHandle aa = GCHandle.Alloc(delA);
GCHandle bb = GCHandle.Alloc(delB);

HERC_EventCallbackSet(delA, delB, 69);
 
M

Michael C

Bart Burkhardt said:
I found a solution, using a GCHandler the delegates are not disposed.
It works fine now!

HercEventCallbackHandler delA = new
HercEventCallbackHandler(this.HercEventCallbackHandlerA);

HercEventCallbackHandler delB = new
HercEventCallbackHandler(this.HercEventCallbackHandlerB);

GCHandle aa = GCHandle.Alloc(delA);
GCHandle bb = GCHandle.Alloc(delB);

HERC_EventCallbackSet(delA, delB, 69);

You should definately not need to do that. Are you keeping a reference to
the delegate? It seems like the GCHandle is just a complicated way to keep a
reference.
 
B

Bart Burkhardt

You should definately not need to do that. Are you keeping a reference to
the delegate? It seems like the GCHandle is just a complicated way to keep a
reference.

I tested it with a Winform. Where did you create the instance of the
delegates?
 
M

Michael C

Bart Burkhardt said:
I tested it with a Winform. Where did you create the instance of the
delegates?

The case I tested I just created the delegate inside the function and kept
it alive for the life of the function. But you're case is different and I'm
not sure how long you'll need to keep it alive. Just create it as a static
module level variable inside the class or form.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top