[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