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>
|
2007-03-05 Mike Kestner <mkestner@novell.com>
|
||||||
|
|
||||||
* gtk/Application.custom : set prgname in Init methods so
|
* gtk/Application.custom : set prgname in Init methods so
|
||||||
|
|
|
@ -17,7 +17,7 @@ ASSEMBLIES = \
|
||||||
|
|
||||||
UPDATE_ASSEMBLIES = $(addprefix -assembly:lib/, $(ASSEMBLIES))
|
UPDATE_ASSEMBLIES = $(addprefix -assembly:lib/, $(ASSEMBLIES))
|
||||||
|
|
||||||
UPDATER = $(MONODOCER) -path:en $(UPDATE_ASSEMBLIES)
|
UPDATER = $(MONODOCER) -path:en -pretty $(UPDATE_ASSEMBLIES)
|
||||||
|
|
||||||
if ENABLE_MONODOC
|
if ENABLE_MONODOC
|
||||||
SOURCESDIR=$(prefix)/lib/monodoc/sources
|
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
|
$(MDASSEMBLER) --ecma $(srcdir)/en -o gtk-sharp-docs
|
||||||
|
|
||||||
get-assemblies:
|
get-assemblies:
|
||||||
|
echo "assumes gnome-sharp and gtk-sharp checkouts in same parent"
|
||||||
mkdir -p lib
|
mkdir -p lib
|
||||||
cp $(top_builddir)/*/*.dll lib
|
cp $(top_builddir)/*/*.dll lib
|
||||||
cp $(top_builddir)/*/*.dll.config lib
|
cp $(top_builddir)/*/*.dll.config lib
|
||||||
cp $(top_builddir)/gconf/*/*.dll lib
|
cp $(top_builddir)/../gnome-sharp/*/*.dll lib
|
||||||
cp $(top_builddir)/gconf/*/*.dll.config 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
|
update: get-assemblies
|
||||||
$(UPDATER)
|
$(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 ();
|
||||||
sw.WriteLine ("\t\tstatic " + retval.ToNativeType + " " + CallbackName + " (" + CallbackSig + ")");
|
sw.WriteLine ("\t\tstatic " + retval.ToNativeType + " " + CallbackName + " (" + CallbackSig + ")");
|
||||||
sw.WriteLine("\t\t{");
|
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\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)
|
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 = "";
|
string finish = "";
|
||||||
for (int idx = 1; idx < parms.Count; idx++) {
|
for (int idx = 1; idx < parms.Count; idx++) {
|
||||||
Parameter p = parms [idx];
|
Parameter p = parms [idx];
|
||||||
IGeneratable igen = p.Generatable;
|
IGeneratable igen = p.Generatable;
|
||||||
if (p.PassAs != "out") {
|
if (p.PassAs != "out") {
|
||||||
if (igen is ManualGen) {
|
if (igen is ManualGen) {
|
||||||
sw.WriteLine("\t\t\tif (arg{0} == IntPtr.Zero)", idx);
|
sw.WriteLine("\t\t\t\tif (arg{0} == IntPtr.Zero)", idx);
|
||||||
sw.WriteLine("\t\t\t\targs.Args[{0}] = null;", idx - 1);
|
sw.WriteLine("\t\t\t\t\targs.Args[{0}] = null;", idx - 1);
|
||||||
sw.WriteLine("\t\t\telse {");
|
sw.WriteLine("\t\t\t\telse {");
|
||||||
sw.WriteLine("\t\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";");
|
sw.WriteLine("\t\t\t\t\targs.Args[" + (idx - 1) + "] = " + p.FromNative ("arg" + idx) + ";");
|
||||||
sw.WriteLine("\t\t\t}");
|
sw.WriteLine("\t\t\t\t}");
|
||||||
} else
|
} 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 != "")
|
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\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName);
|
||||||
sw.WriteLine("\t\t\thandler (GLib.Object.GetObject (arg0), args);");
|
sw.WriteLine("\t\t\t\thandler (GLib.Object.GetObject (arg0), args);");
|
||||||
sw.WriteLine (finish);
|
sw.WriteLine("\t\t\t} catch (Exception e) {");
|
||||||
if (!IsVoid) {
|
sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, false);");
|
||||||
sw.WriteLine ("\t\t\tif (args.RetVal == null)");
|
sw.WriteLine("\t\t\t}");
|
||||||
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\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("\t\t}");
|
||||||
sw.WriteLine();
|
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 \
|
DelegateWrapper.cs \
|
||||||
DestroyNotify.cs \
|
DestroyNotify.cs \
|
||||||
EnumWrapper.cs \
|
EnumWrapper.cs \
|
||||||
|
ExceptionManager.cs \
|
||||||
FileUtils.cs \
|
FileUtils.cs \
|
||||||
GException.cs \
|
GException.cs \
|
||||||
GString.cs \
|
GString.cs \
|
||||||
|
|
|
@ -173,12 +173,18 @@ namespace GLib {
|
||||||
|
|
||||||
static void voidObjectCallback (IntPtr handle, IntPtr gch)
|
static void voidObjectCallback (IntPtr handle, IntPtr gch)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
Signal sig = ((GCHandle) gch).Target as Signal;
|
Signal sig = ((GCHandle) gch).Target as Signal;
|
||||||
if (sig == null)
|
if (sig == null) {
|
||||||
throw new Exception ("Unknown signal class GC handle received.");
|
ExceptionManager.RaiseUnhandledException (new Exception ("Unknown signal class GC handle received."), false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EventHandler handler = (EventHandler) sig.Handler;
|
EventHandler handler = (EventHandler) sig.Handler;
|
||||||
handler (Object.GetObject (handle), EventArgs.Empty);
|
handler (Object.GetObject (handle), EventArgs.Empty);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ExceptionManager.RaiseUnhandledException (e, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static voidObjectDelegate event_handler_delegate;
|
static voidObjectDelegate event_handler_delegate;
|
||||||
|
|
Loading…
Reference in a new issue