ps. I think the wrapper_type things can be replaced with the already existing "pass_as" attribute.
On Sun, 2008-02-10 at 15:27 +0100, Philip Van Hoof wrote: > Hi there, > > I'm trying to make GtkSharp's GAPI generate the typical asynchronous > GObject style C API to something that looks a bit like the Asynchronous > Pattern often used in .NET. > > My plan is not to achieve an exact version of the Asynchronous pattern, > but nonetheless something workable. > > Some pointers: > http://msdn2.microsoft.com/en-us/library/wewwczdw.aspx > http://msdn2.microsoft.com/en-us/library/aa719595(VS.71).aspx > > Versus, for example, this one: > http://tinymail.org/API/libtinymail-1.0/libtinymail-tny-folder.html#tny-folder-get-msg-async > http://tinymail.org/API/libtinymail-1.0/libtinymail-tny-shared.html#TnyGetMsgCallback > > It's actually awesome about GtkSharp's GAPI, but not surprisingly did > GAPI do a splendid job already. There's however one big problem: > > The GError based error being passed to the callback (which in C is a > function pointer typedeffed as TnyGetMsgCallback) is not being converted > to an Exception type. > > My goal is to wrap the "IntPtr err" (which is the GError pointer in C) > with a factory's Create method that will create me the right managed > exception: > > public class Tny.ExceptionFactory > { > static Tny.TException Create (IntPtr gerror) { > // Pseudo, to get the type I'll indeed need to make > // a small piece of glue code in C ... > if (gerror->type == TNY_ERROR_THIS) > return new Tny.ThisException (gerror); > if (gerror->type == TNY_ERROR_THAT) > return new Tny.ThatException (gerror); > ... > } > } > > That way can my application developer use the error being reported in > the callback using his normal exception handling methods. > > For example: > > - private void GetMsgCallBack (Tny.Folder folder, bool cancel, Tny.Msg msg, > IntPtr err) > + private void GetMsgCallBack (Tny.Folder folder, bool cancel, Tny.Msg msg, > Tny.TException err) > { > - if (err != IntPtr.Zero) { > - Exception ex = new Tny.TException (err); > - Console.WriteLine (ex.Message); > + if (err != null) > + throw err; // Or do whatever with Exceptions > } else { > if (msg != null && !cancel) > this.msg_view.Msg = msg; > } > } > > Note that throwing it is not necessarily what the application developer > will want to do with the exception. In that callback he'll typically > want to show an error dialog to the user with the err.Message displayed. > > To achieve this, after doing some analysis on Gapi's generator, this is > my conclusion: > > Parameter needs a new property Wrapper that looks a lot like its Scope > parameter (gets it from the XML file) > Signature::ToString() needs to recognise parameters that are to be wrapped > (change the type) > CallbackGen::Generate(GenerationInfo) needs to be verified that > sig.ToString() does the right thing > CallbackGen::GenWrapper(GenerationInfo) at line 227 needs to wrap the > parameter with p.Wrapper > > > ## This > > <callback name="FolderCallback" cname="TnyFolderCallback"> > <return-type type="void" /> > <parameters> > <parameter type="TnyFolder*" name="self" /> > <parameter type="gboolean" name="cancelled" /> > <parameter type="GError*" name="err" /> > <parameter type="gpointer" name="user_data" /> > </parameters> > </callback> > > > ## Would become > > <callback name="FolderCallback" cname="TnyFolderCallback"> > <return-type type="void" /> > <parameters> > <parameter type="TnyFolder*" name="self" /> > <parameter type="gboolean" name="cancelled" /> > <parameter type="GError*" name="err" wrapper_type="Tny.TException" > wrapper="Tny.ExceptionFactory.Create ({0})" /> > <parameter type="gpointer" name="user_data" /> > </parameters> > </callback> > > > ## This > > namespace Tny { > > using System; > > public delegate void FolderCallback(Tny.Folder self, bool cancelled, > IntPtr err); > > } > > > ## Would become (err's type comes from the XML above) > > namespace Tny { > > using System; > > public delegate void FolderCallback(Tny.Folder self, bool cancelled, > Tny.TException err); > > } > > ## This > > internal class FolderCallbackWrapper { > public void NativeCallback (IntPtr self, bool cancelled, IntPtr err, > IntPtr user_data) > { > try { > Tny.Folder _arg0 = Tny.FolderAdapter.GetObject (self, > false); > bool _arg1 = cancelled; > IntPtr _arg2 = err; > managed ( _arg0, _arg1, _arg2); > if (release_on_call) > gch.Free (); > } catch (Exception e) { > GLib.ExceptionManager.RaiseUnhandledException (e, > false); > } > } > ... > } > > > ## Would become (arg2 wrap comes from the XML above) > > internal class FolderCallbackWrapper { > public void NativeCallback (IntPtr self, bool cancelled, IntPtr err, > IntPtr user_data) > { > try { > Tny.Folder _arg0 = Tny.FolderAdapter.GetObject (self, > false); > bool _arg1 = cancelled; > IntPtr _arg2 = err; > managed ( _arg0, _arg1, Tny.ExceptionFactory.Create > (_arg2)); > if (release_on_call) > gch.Free (); > } catch (Exception e) { > GLib.ExceptionManager.RaiseUnhandledException (e, > false); > } > } > ... > } > > -- Philip Van Hoof, freelance software developer home: me at pvanhoof dot be gnome: pvanhoof at gnome dot org http://pvanhoof.be/blog http://codeminded.be _______________________________________________ Gtk-sharp-list maillist - [email protected] http://lists.ximian.com/mailman/listinfo/gtk-sharp-list
