====== Exception handling at program startup ======
Specially GUI applications can show a undesiderable behavior if the encounter a failure before the GUI is initialized. That can be a missing and needed DLL, a runtime error in the initialization of the GUI itself or some other undesired behavior.
The solution is to implement an own startip method that uses alternative ways to display the error and exit, maybe using the Windows Console and/or writing to an error log.
The implementation differs a bit depending if you have a migrated VO application or a natively written .NET application mainly because of the different handling of namespaces. For the handling of namespace in migrated applications please see here: [[:compiler_option_ins|/ins Compiler option]]
This is a sample code for an own startup class in a migrated application:
using System.Runtime.InteropServices
class XStartupCode
[STAThreadAttribute];
static method Start() as void strict
local oSB as System.Text.StringBuilder
try
StartupExceptionTester.Exe.Functions.Start()
catch oEx as Exception
AllocConsole()
oSB := System.Text.StringBuilder{}
Output( oSB, "An unhandled exception has occurred" )
Output( oSB, "===================================" )
do while oEx != null
Output( oSB, "Exception: " + oEx:Message )
Output( oSB, "Callstack:")
Output( oSB, oEx:StackTrace )
Output( oSB, "" )
oEx := oEx:InnerException
enddo
Output( oSB, "===================================" )
Output( oSB, "Press Return to close the application" )
Console.ReadLine()
MessageBox( 0, oSB:ToString(), "Runtime error", 0 )
System.IO.File.AppendAllText( System.IO.Path.Combine( AppDomain.CurrentDomain:BaseDirectory, "ApplicationError.log" ), oSB:ToString() )
end try
return
static method Output( oSB as System.Text.StringBuilder, cText as string ) as void
oSB:AppendLine( cText )
Console.WriteLine( cText )
return
[DllImport("kernel32.dll", SetLastError := true)];
[return: MarshalAs(UnmanagedType.Bool)];
static extern method AllocConsole() as logic
[DllImport("user32.dll", CharSet := CharSet.Ansi)];
static method MessageBox(hwnd as IntPtr, lpText as string, lpCaption as string, uType as dword) as int pascal
end class
To define this class as startup class, you have to add a compiler option:
-main:XStartupCode
Please see here for a sample as XIDE application export file:
[[https://docs.xsharp.it/lib/exe/fetch.php?media=download:startupexceptiontester.zip|startupexceptiontester.zip]]
For a native .NET application with namespaces the code changes a bit:
class ProdPlan.XStartupCode
[STAThreadAttribute];
static method Start as void
local oSB as System.Text.StringBuilder
where ''ProdPlan'' is the namespace of your application.
The compiler option than has to be
-main:ProdPlan.XStartupCode
To explain: since the GUI can be not yet started when an exception is occurring, the console mode needs to be activated so the error can be shown even with no GUI (and written to a file for later evaluation).