[Gtk-sharp-list] Handling errors when generating binding code for asynchronous APIs
Philip Van Hoof
spam at pvanhoof.be
Sun Feb 10 10:33:58 EST 2008
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
More information about the Gtk-sharp-list
mailing list