[Mono-list] Re: Calling back from unmanaged code to managed code.
Cory Nelson
Cory Nelson <phrosty@gmail.com>
Fri, 17 Dec 2004 06:14:57 -0800
Would be good to note, on Windows, that your C code expecting a
__cdecl or __stdcall function pointer can make all the difference.
Gave me a nice 2 day long headache with debugging :)
On Thu, 16 Dec 2004 21:04:15 -0500, Jonathan Pryor <jonpryor@vt.edu> wrote:
> 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
>
>
> _______________________________________________
> Mono-list maillist - Mono-list@lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-list
>
--
Cory Nelson
http://www.int64.org