2007-03-06 Mike Kestner <mkestner@novell.com>
* generator/Signal.cs : add try/catch blocks to native callback delegates so that exceptions are not propagated across the native boundary. Now raises GLib.ExceptionManager.UnhandledException. * glib/ExceptionManager.cs : new class with UnhandledException event and a static method to raise it. * glib/Signal.cs : wrap the generic EventHandler callback delegate with try/catch blocks and raise the UnhandledException event. svn path=/trunk/gtk-sharp/; revision=73840
This commit is contained in:
parent
6a00328dd1
commit
32de2832db
9 changed files with 251 additions and 30 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2007-03-06 Mike Kestner <mkestner@novell.com>
|
||||
|
||||
* generator/Signal.cs : add try/catch blocks to native callback
|
||||
delegates so that exceptions are not propagated across the native
|
||||
boundary. Now raises GLib.ExceptionManager.UnhandledException.
|
||||
* glib/ExceptionManager.cs : new class with UnhandledException
|
||||
event and a static method to raise it.
|
||||
* glib/Signal.cs : wrap the generic EventHandler callback delegate
|
||||
with try/catch blocks and raise the UnhandledException event.
|
||||
|
||||
2007-03-05 Mike Kestner <mkestner@novell.com>
|
||||
|
||||
* gtk/Application.custom : set prgname in Init methods so
|
||||
|
|
|
@ -17,7 +17,7 @@ ASSEMBLIES = \
|
|||
|
||||
UPDATE_ASSEMBLIES = $(addprefix -assembly:lib/, $(ASSEMBLIES))
|
||||
|
||||
UPDATER = $(MONODOCER) -path:en $(UPDATE_ASSEMBLIES)
|
||||
UPDATER = $(MONODOCER) -path:en -pretty $(UPDATE_ASSEMBLIES)
|
||||
|
||||
if ENABLE_MONODOC
|
||||
SOURCESDIR=$(prefix)/lib/monodoc/sources
|
||||
|
@ -36,11 +36,14 @@ gtk-sharp-docs.zip gtk-sharp-docs.tree: $(srcdir)/en/*/*.xml $(srcdir)/en/*.xml
|
|||
$(MDASSEMBLER) --ecma $(srcdir)/en -o gtk-sharp-docs
|
||||
|
||||
get-assemblies:
|
||||
echo "assumes gnome-sharp and gtk-sharp checkouts in same parent"
|
||||
mkdir -p lib
|
||||
cp $(top_builddir)/*/*.dll lib
|
||||
cp $(top_builddir)/*/*.dll.config lib
|
||||
cp $(top_builddir)/gconf/*/*.dll lib
|
||||
cp $(top_builddir)/gconf/*/*.dll.config lib
|
||||
cp $(top_builddir)/../gnome-sharp/*/*.dll lib
|
||||
cp $(top_builddir)/../gnome-sharp/*/*.dll.config lib
|
||||
cp $(top_builddir)/../gnome-sharp/gconf/*/*.dll lib
|
||||
cp $(top_builddir)/../gnome-sharp/gconf/*/*.dll.config lib
|
||||
|
||||
update: get-assemblies
|
||||
$(UPDATER)
|
||||
|
|
46
doc/en/GLib/ExceptionManager.xml
Normal file
46
doc/en/GLib/ExceptionManager.xml
Normal file
|
@ -0,0 +1,46 @@
|
|||
<Type Name="ExceptionManager" FullName="GLib.ExceptionManager">
|
||||
<TypeSignature Language="C#" Value="public class ExceptionManager" />
|
||||
<AssemblyInfo>
|
||||
<AssemblyName>glib-sharp</AssemblyName>
|
||||
<AssemblyVersion>2.10.0.0</AssemblyVersion>
|
||||
</AssemblyInfo>
|
||||
<Base>
|
||||
<BaseTypeName>System.Object</BaseTypeName>
|
||||
</Base>
|
||||
<Interfaces />
|
||||
<Members>
|
||||
<Member MemberName="RaiseUnhandledException">
|
||||
<MemberSignature Language="C#" Value="public static void RaiseUnhandledException (Exception e, bool is_terminal);" />
|
||||
<MemberType>Method</MemberType>
|
||||
<ReturnValue>
|
||||
<ReturnType>System.Void</ReturnType>
|
||||
</ReturnValue>
|
||||
<Parameters>
|
||||
<Parameter Name="e" Type="System.Exception" />
|
||||
<Parameter Name="is_terminal" Type="System.Boolean" />
|
||||
</Parameters>
|
||||
<Docs>
|
||||
<param name="e">Exception.</param>
|
||||
<param name="is_terminal">If <see langword="true" />, the exception terminates the application.</param>
|
||||
<summary>Raise Unhandled Exception method.</summary>
|
||||
<remarks>This method is generally only useful to language bindings. If <paramref name="is_terminal" /> is set, or a user event handler requests application exit, this method does not return.</remarks>
|
||||
</Docs>
|
||||
</Member>
|
||||
<Member MemberName="UnhandledException">
|
||||
<MemberSignature Language="C#" Value="public static event GLib.UnhandledExceptionHandler UnhandledException;" />
|
||||
<MemberType>Event</MemberType>
|
||||
<ReturnValue>
|
||||
<ReturnType>GLib.UnhandledExceptionHandler</ReturnType>
|
||||
</ReturnValue>
|
||||
<Docs>
|
||||
<summary>UnhandledException event.</summary>
|
||||
<remarks>Attach a <see cref="T:GLib.UnhandledExceptionHandler" /> delegate to this event to receive notification of Exceptions throw within managed callback delegates. If the <see cref="T:GLib.UnhandledExceptionArgs" /> contain information regarding whether the Exception is terminal and can be used to request termination of the application via the <see cref="M:GLib.UnhandledExceptionArgs.ExitApplication" /> property.</remarks>
|
||||
</Docs>
|
||||
</Member>
|
||||
</Members>
|
||||
<Docs>
|
||||
<summary>Exception management class.</summary>
|
||||
<remarks />
|
||||
<since version="Gtk# 2.10" />
|
||||
</Docs>
|
||||
</Type>
|
44
doc/en/GLib/UnhandledExceptionArgs.xml
Normal file
44
doc/en/GLib/UnhandledExceptionArgs.xml
Normal file
|
@ -0,0 +1,44 @@
|
|||
<Type Name="UnhandledExceptionArgs" FullName="GLib.UnhandledExceptionArgs">
|
||||
<TypeSignature Language="C#" Value="public class UnhandledExceptionArgs : UnhandledExceptionEventArgs" />
|
||||
<AssemblyInfo>
|
||||
<AssemblyName>glib-sharp</AssemblyName>
|
||||
<AssemblyVersion>2.10.0.0</AssemblyVersion>
|
||||
</AssemblyInfo>
|
||||
<Base>
|
||||
<BaseTypeName>System.UnhandledExceptionEventArgs</BaseTypeName>
|
||||
</Base>
|
||||
<Interfaces />
|
||||
<Members>
|
||||
<Member MemberName=".ctor">
|
||||
<MemberSignature Language="C#" Value="public UnhandledExceptionArgs (Exception e, bool is_terminal);" />
|
||||
<MemberType>Constructor</MemberType>
|
||||
<Parameters>
|
||||
<Parameter Name="e" Type="System.Exception" />
|
||||
<Parameter Name="is_terminal" Type="System.Boolean" />
|
||||
</Parameters>
|
||||
<Docs>
|
||||
<param name="e">Exception.</param>
|
||||
<param name="is_terminal">If <see langword="true" />, the application is terminating.</param>
|
||||
<summary>Public constructor.</summary>
|
||||
<remarks />
|
||||
</Docs>
|
||||
</Member>
|
||||
<Member MemberName="ExitApplication">
|
||||
<MemberSignature Language="C#" Value="public bool ExitApplication { set; get; };" />
|
||||
<MemberType>Property</MemberType>
|
||||
<ReturnValue>
|
||||
<ReturnType>System.Boolean</ReturnType>
|
||||
</ReturnValue>
|
||||
<Docs>
|
||||
<summary>ExitApplication property.</summary>
|
||||
<value>If <see langword="true" />, the application will exit.</value>
|
||||
<remarks>Indicates if an application wants to exit after event propagation is complete.</remarks>
|
||||
</Docs>
|
||||
</Member>
|
||||
</Members>
|
||||
<Docs>
|
||||
<summary>UnhandledExceptionArgs event arguments.</summary>
|
||||
<remarks>Event arguments for <see cref="T:GLib.UnhandledExceptionHandler" /> events.</remarks>
|
||||
<since version="Gtk# 2.10" />
|
||||
</Docs>
|
||||
</Type>
|
22
doc/en/GLib/UnhandledExceptionHandler.xml
Normal file
22
doc/en/GLib/UnhandledExceptionHandler.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<Type Name="UnhandledExceptionHandler" FullName="GLib.UnhandledExceptionHandler">
|
||||
<TypeSignature Language="C#" Value="public delegate void UnhandledExceptionHandler(UnhandledExceptionArgs args);" />
|
||||
<AssemblyInfo>
|
||||
<AssemblyName>glib-sharp</AssemblyName>
|
||||
<AssemblyVersion>2.10.0.0</AssemblyVersion>
|
||||
</AssemblyInfo>
|
||||
<Base>
|
||||
<BaseTypeName>System.Delegate</BaseTypeName>
|
||||
</Base>
|
||||
<Parameters>
|
||||
<Parameter Name="args" Type="GLib.UnhandledExceptionArgs" />
|
||||
</Parameters>
|
||||
<ReturnValue>
|
||||
<ReturnType>System.Void</ReturnType>
|
||||
</ReturnValue>
|
||||
<Docs>
|
||||
<param name="args">Event arguments.</param>
|
||||
<summary>Reports unhandled exceptions.</summary>
|
||||
<remarks>Attach to <see cref="M:GLib.EventManager.UnhandledException" /> event to receive notification of exceptions in managed callback delegates.</remarks>
|
||||
<since version="Gtk# 2.10" />
|
||||
</Docs>
|
||||
</Type>
|
|
@ -199,42 +199,58 @@ namespace GtkSharp.Generation {
|
|||
sw.WriteLine ();
|
||||
sw.WriteLine ("\t\tstatic " + retval.ToNativeType + " " + CallbackName + " (" + CallbackSig + ")");
|
||||
sw.WriteLine("\t\t{");
|
||||
sw.WriteLine("\t\t\tGLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;");
|
||||
sw.WriteLine("\t\t\tif (sig == null)");
|
||||
sw.WriteLine("\t\t\t\tthrow new Exception(\"Unknown signal GC handle received \" + gch);");
|
||||
sw.WriteLine();
|
||||
sw.WriteLine("\t\t\t{0} args = new {0} ();", EventArgsQualifiedName);
|
||||
sw.WriteLine("\t\t\ttry {");
|
||||
sw.WriteLine("\t\t\t\tGLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;");
|
||||
sw.WriteLine("\t\t\t\tif (sig == null)");
|
||||
sw.WriteLine("\t\t\t\t\tthrow new Exception(\"Unknown signal GC handle received \" + gch);");
|
||||
sw.WriteLine();
|
||||
if (parms.Count > 1)
|
||||
sw.WriteLine("\t\t\targs.Args = new object[" + (parms.Count - 1) + "];");
|
||||
sw.WriteLine("\t\t\t\targs.Args = new object[" + (parms.Count - 1) + "];");
|
||||
string finish = "";
|
||||
for (int idx = 1; idx < parms.Count; idx++) {
|
||||
Parameter p = parms [idx];
|
||||
IGeneratable igen = p.Generatable;
|
||||
if (p.PassAs != "out") {
|
||||
if (igen is ManualGen) {
|
||||
sw.WriteLine("\t\t\tif (arg{0} == IntPtr.Zero)", idx);
|
||||
sw.WriteLine("\t\t\t\targs.Args[{0}] = null;", idx - 1);
|
||||
sw.WriteLine("\t\t\telse {");
|
||||
sw.WriteLine("\t\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";");
|
||||
sw.WriteLine("\t\t\t}");
|
||||
sw.WriteLine("\t\t\t\tif (arg{0} == IntPtr.Zero)", idx);
|
||||
sw.WriteLine("\t\t\t\t\targs.Args[{0}] = null;", idx - 1);
|
||||
sw.WriteLine("\t\t\t\telse {");
|
||||
sw.WriteLine("\t\t\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";");
|
||||
sw.WriteLine("\t\t\t\t}");
|
||||
} else
|
||||
sw.WriteLine("\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";");
|
||||
sw.WriteLine("\t\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";");
|
||||
}
|
||||
if (p.PassAs != "")
|
||||
finish += "\t\t\targ" + idx + " = " + igen.ToNativeReturn ("((" + p.CSType + ")args.Args[" + (idx - 1) + "])") + ";\n";
|
||||
finish += "\t\t\t\targ" + idx + " = " + igen.ToNativeReturn ("((" + p.CSType + ")args.Args[" + (idx - 1) + "])") + ";\n";
|
||||
}
|
||||
sw.WriteLine("\t\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName);
|
||||
sw.WriteLine("\t\t\thandler (GLib.Object.GetObject (arg0), args);");
|
||||
sw.WriteLine (finish);
|
||||
if (!IsVoid) {
|
||||
sw.WriteLine ("\t\t\tif (args.RetVal == null)");
|
||||
if (retval.CSType == "bool")
|
||||
sw.WriteLine ("\t\t\t\treturn false;");
|
||||
else
|
||||
sw.WriteLine ("\t\t\t\tthrow new Exception(\"args.RetVal unset in callback\");");
|
||||
sw.WriteLine("\t\t\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName);
|
||||
sw.WriteLine("\t\t\t\thandler (GLib.Object.GetObject (arg0), args);");
|
||||
sw.WriteLine("\t\t\t} catch (Exception e) {");
|
||||
sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, false);");
|
||||
sw.WriteLine("\t\t\t}");
|
||||
|
||||
sw.WriteLine("\t\t\treturn " + table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";");
|
||||
if (IsVoid && finish.Length == 0) {
|
||||
sw.WriteLine("\t\t}\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sw.WriteLine("\n\t\t\ttry {");
|
||||
sw.Write (finish);
|
||||
if (!IsVoid) {
|
||||
if (retval.CSType == "bool") {
|
||||
sw.WriteLine ("\t\t\t\tif (args.RetVal == null)");
|
||||
sw.WriteLine ("\t\t\t\t\treturn false;");
|
||||
}
|
||||
sw.WriteLine("\t\t\t\treturn " + table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";");
|
||||
}
|
||||
sw.WriteLine("\t\t\t} catch (Exception) {");
|
||||
sw.WriteLine ("\t\t\t\tException ex = new Exception (\"args.RetVal or 'out' property unset or set to incorrect type in " + EventHandlerQualifiedName + " callback\");");
|
||||
sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (ex, true);");
|
||||
|
||||
sw.WriteLine ("\t\t\t\t// NOTREACHED: above call doesn't return.");
|
||||
sw.WriteLine ("\t\t\t\tthrow ex;");
|
||||
sw.WriteLine("\t\t\t}");
|
||||
sw.WriteLine("\t\t}");
|
||||
sw.WriteLine();
|
||||
}
|
||||
|
|
73
glib/ExceptionManager.cs
Normal file
73
glib/ExceptionManager.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
// GLib.Application.cs - static Application class
|
||||
//
|
||||
// Authors: Mike Kestner <mkestner@novell.com>
|
||||
//
|
||||
// Copyright (c) 2007 Novell, Inc.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of version 2 of the Lesser GNU General
|
||||
// Public License as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
// Boston, MA 02111-1307, USA.
|
||||
|
||||
|
||||
namespace GLib {
|
||||
|
||||
using System;
|
||||
|
||||
public delegate void UnhandledExceptionHandler (UnhandledExceptionArgs args);
|
||||
|
||||
public class UnhandledExceptionArgs : System.UnhandledExceptionEventArgs {
|
||||
|
||||
bool exit_app = false;
|
||||
|
||||
public UnhandledExceptionArgs (Exception e, bool is_terminal) : base (e, is_terminal) {}
|
||||
|
||||
public bool ExitApplication {
|
||||
get {
|
||||
return exit_app;
|
||||
}
|
||||
set {
|
||||
if (value)
|
||||
exit_app = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ExceptionManager {
|
||||
|
||||
|
||||
private ExceptionManager () {}
|
||||
|
||||
public static event UnhandledExceptionHandler UnhandledException;
|
||||
|
||||
public static void RaiseUnhandledException (Exception e, bool is_terminal)
|
||||
{
|
||||
if (UnhandledException == null) {
|
||||
Console.Error.WriteLine ("Exception in Gtk# callback delegate");
|
||||
Console.Error.WriteLine (" Note: Applications can use GLib.ExceptionManager.UnhandledException to handle the exception.");
|
||||
Console.Error.WriteLine (e);
|
||||
Environment.Exit (1);
|
||||
}
|
||||
|
||||
UnhandledExceptionArgs args = new UnhandledExceptionArgs (e, is_terminal);
|
||||
try {
|
||||
UnhandledException (args);
|
||||
} catch (Exception ex) {
|
||||
Console.Error.WriteLine (ex);
|
||||
Environment.Exit (1);
|
||||
}
|
||||
|
||||
if (is_terminal || args.ExitApplication)
|
||||
Environment.Exit (1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ sources = \
|
|||
DelegateWrapper.cs \
|
||||
DestroyNotify.cs \
|
||||
EnumWrapper.cs \
|
||||
ExceptionManager.cs \
|
||||
FileUtils.cs \
|
||||
GException.cs \
|
||||
GString.cs \
|
||||
|
|
|
@ -173,12 +173,18 @@ namespace GLib {
|
|||
|
||||
static void voidObjectCallback (IntPtr handle, IntPtr gch)
|
||||
{
|
||||
Signal sig = ((GCHandle) gch).Target as Signal;
|
||||
if (sig == null)
|
||||
throw new Exception ("Unknown signal class GC handle received.");
|
||||
try {
|
||||
Signal sig = ((GCHandle) gch).Target as Signal;
|
||||
if (sig == null) {
|
||||
ExceptionManager.RaiseUnhandledException (new Exception ("Unknown signal class GC handle received."), false);
|
||||
return;
|
||||
}
|
||||
|
||||
EventHandler handler = (EventHandler) sig.Handler;
|
||||
handler (Object.GetObject (handle), EventArgs.Empty);
|
||||
EventHandler handler = (EventHandler) sig.Handler;
|
||||
handler (Object.GetObject (handle), EventArgs.Empty);
|
||||
} catch (Exception e) {
|
||||
ExceptionManager.RaiseUnhandledException (e, false);
|
||||
}
|
||||
}
|
||||
|
||||
static voidObjectDelegate event_handler_delegate;
|
||||
|
|
Loading…
Reference in a new issue