[Mono-list] Re: Calling back from unmanaged code to managed
code.
Jonathan Pryor
jonpryor@vt.edu
Thu, 16 Dec 2004 21:04:15 -0500
Just for "fun", I'll write the equivalent C# declarations inline with
the C code. Note that I haven't tried to compile this, but the basic
idea should be seen...
On Thu, 2004-12-16 at 13:32 -0500, Nigel Benns wrote:
> Here is a C example to do a DeleteEvent:
>
> void delete_cb(Ewl_Widget *w, void *event, void *data) {
> ewl_widget_destroy(w);
> ewl_main_quit();
> }
delegate void EwlDeleteCallback (IntPtr w, IntPtr event, IntPtr data);
class MyTest {
private const string LIB = "ewl";
[DllImport (LIB)]
private static extern void ewl_widget_destroy (IntPtr w);
[DllImport (LIB)]
private static extern void ewl_main_quit ();
private void delete_cb (IntPtr w, IntPtr event, IintPtr data)
{
ewl_widget_destroy (w);
ewl_main_quit ();
}
> int main(int argc, char **argv) {
> ewl_init();
[DllImport (LIB)] private static extern void ewl_init ();
> ...
> win = ewl_window_new();
[DllImport (LIB)] private static extern IntPtr ewl_window_new();
> ...
> /*Where this function appends the callback to a calback list read
> by ewl_main().
> */
> ewl_callback_append(win, EWL_CALLBACK_DELETE_WINDOW, delete_cb, NULL);
// Here's what you're interested in:
[DllImport(LIB)]
private static extern void ewl_callback_append (IntPtr win,
int callback_type, EwlDeleteCallback cb, IntPtr data);
// I'd assume that ewl_callback_append can take a variety of
// function pointer types (the callback is probably void*),
// so you could overload this function for each function
// pointer type that ewl_callback_append accepts.
// obviously, this needs to be set to the correct value.
private const int EWL_CALLBACK_DELETE_WINDOW = 0xdeadbeef;
> /*The NULL is for the Data to pass */
> ...
> ewl_main();
[DllImport(LIB)] private static extern void ewl_main ();
> }
>
> Ok, so what I'm trying figure out is how to add the ewl_callback_append as
> a delegate in C#.
public static void Main ()
{
ewl_init ();
IntPtr win = ewl_window_new ();
EwlDeleteCallback cb = new EwlDeleteCallback (delete_cb);
ewl_callback_append (win, EWL_CALLBACK_DELETE_WINDOW,
cb, IntPtr.Zero);
ewl_main ();
System.GC.KeepAlive (cb);
}
}
Note that the System.GC.KeepAlive is necessary so that the GC doesn't
collect your delegate before EWL is finished using the function pointer
it has (the delegate is marshaled as a function pointer). It would be
"bad" to have the GC collect the delegate early.
> It doesn't seem write to me that I could pass a C# function to C, even if
> I could figure out how to do that?
You can pass a delegate referring to a C# method to C.
I would suggest reading my guide, "Everything you (n)ever wanted to know
about marshaling (and were afraid to ask!)":
http://www.jprl.com/~jon/interop.html
It's also available through monodoc (though the above is more recent --
I've been lazy about committing):
http://www.go-mono.com/docs/index.aspx?tlink=8@xhtml%3anew%2fen%2fprogramming%2finterop.html
You may also want to look into Gtk#, just to see how the wrapper code
can be used.
- Jon