Everytime I use a raise Exception.create('...');, it shows, differently from Delphi, the following box:
[my message]
Press OK to ignore and risk data corruption.
Press Cancel to kill the program.
I just want to change this default message and keep only my part.
Does someone know how can I do it?
To configure my own exception message, I did the following:
In the private declarations of application's main form:
procedure onExcept(sender: TObject; e: Exception);
In the OnCreate event of the main form:
procedure TfrmMain.formCreate(sender: TObject);
begin
application.onException := #onExcept;
end;
procedure TfrmMain.onExcept(sender: TObject; e: Exception);
begin
//...
end;
It's important to note that the # operator is required if you're using Lazarus. If I didn't put it, the compiler would consider onExcept as a function call. Delphi adds it internally, so you don't have to worry about it.
If you want to change this behavior, use {$mode Delphi} instead of {$mode ObjFPC} directive.
Related
I'm working with a PascalScript innosetup installer, and I fail to see where the control of the following block is flowing.
function Foo(): String;
begin
Result := 'foo';
RaiseException('...');
end;
procedure Test();
var
Z : String;
begin
Z := '';
try
Z := Foo();
except
Log(Z);
end
end;
My installer seems to indicate Z is being set with the Result of the Foo function. My understanding of exceptions in 'most' programming languages tells me the assignment Z := Foo() should not happen in case of exception.
When the Foo function raises, should Z still be assigned to?
Probably it handles result values by reference as implicit first argument. But then this can happen. It could be considered a legal of certain codegeneration/optimization, since it is quite a common way of handling return values.
However what is exactly defined in Object Pascal outside testing what Delphi does is murky territory, since there is only a x86 and x86_64 implementation. And Delphi will return the value in eax, so if you follow that logic this is illegal.
added later:
I tested Delphi with structured types, and while it passes a reference, it creates a copy on the stack to pass it.
This could make it hard to optimize code with structured types though, but a modifier/attribute to declare the return type const could fix that if ever needed.
In Delphi, strings as result values are treated like var parameters. In other words, a function like Foo is in fact compiled as:
procedure Foo(var Result: string);
begin
Result := 'Foo';
RaiseException(...);
end;
This means that Z (through the reference parameter) is assigned the value 'Foo' immediately, i.e. before the exception is raised.
In other words, the function result is not just kept in a local variable called Result and then returned when the function ends -- which would be prevented by the exception -- it is assigned immediately.
I assume this is exactly what happens in PascalScript as well.
I'd like to be able to obtain untyped pointers to functions/procedures while in {$MODE FPC} so code illustrated by the following example can work instead of getting an "Incompatible types" error, anyone know how?
program Project1;
{$MODE FPC}
{$MODESWITCH POINTERTOPROCVAR ON} // doesn't stop error
{$TYPEDADDRESS OFF} // doesn't stop error
function new_getmem(asize:longint):pointer;
begin
new_getmem:=nil;
end;
var
mem_mgr_new:tmemorymanager;
begin
mem_mgr_new.GetMem:=#new_getmem; // Error: Incompatible types...
pointer(mem_mgr_new.GetMem):=#new_getmem; // both those work but I'd prefer the
mem_mgr_new.GetMem:=pointer(#new_getmem); // clean code of the line that doesn't work
end.
EDIT:
There used to be an answer below that answered this properly, but it went away. The discussion allowed me to find out that both {$MODESWITCH CLASSICPROCVARS ON} and {$MODESWITCH POINTERTOPROCVAR ON} need to be specified for the desired line to compile, but like was explained, this opens up lots of possibilities for errors, so use with care only when necessary.
Exception is not being caught with its name but it is caught when others keyword is used? Below is my code
p.ads
package p is
procedure proc ;
end p;
p.adb
package body p is
my_exp:exception; -- user define exception
procedure proc is
begin
raise my_exp; -- spreading exception
end proc;
end p;
p_main.adb
with p;
with ada.text_io;
use ada.text_io;
use p;
procedure p_main is
begin
proc;
exception
when my_exp=>put(" my_exp");-- error but when others is used then.its good why?
end p_main;
A/c to adacore site my_exp is not visible here then how it is visible when others keyword is used?
Your code has numerous syntax errors. It's always better to copy-and-paste your exact code into the question; you appear to have re-typed it, which makes it difficult to distinguish between typos and actual errors in your original code.
Ignoring the syntax errors, this:
exception
when my_exp => put(" my_exp");
fails to compile because the name my_exp is not visible. (If you want it to be visible it should be in the package specification, but that's not what you asked.)
If you replace when my_exp by when others, it works; the exception is handled. This is because a when others clause handles any exception that's been raised, whether its name is visible or not.
An exception is a condition that exists when a program is running. The exception handler detects and handles that run-time entity. It doesn't need to refer to it by whatever identifier you used to define it.
If the name my_exp had been visible, the handler still (almost certainly) wouldn't use the name to identify the exception. Instead, the compiler creates some run-time data structure that allows exceptions to be identified, perhaps by a reference to a specific memory address. The exact mechanism depends on the compiler, and understanding the details is not terribly important unless you're writing a compiler.
The run-time detection that an exception has been raised, and which exception it is, does not depend on the name you've assigned to the exception in your source code.
The reference to the name my_exp is rejected at compile time because that name is not visible at compile time.
The first thing to understand is that if your package can raise a custom exception which isn't advertised by the package specification, that is bad design because it leads to unpleasant surprises for the package users.
So the right thing to do is to declare my_exp in the package instead of hiding it in the body.
package p is
my_exp:exception; -- user define exception
procedure proc ;
end p;
And then fix all the other trivial syntax errors, and your program works as advertised.
But even if you don't, and "my_exp" is not visible in the main program, its exception handler can identify it correctly.
procedure p_main is
begin
proc;
end p_main;
./p_main
raised P.MY_EXP : p.adb:7
Or you can manipulate that information yourself, for better diagnostics or error recovery
with Ada.Exceptions; -- we need to process exception data
procedure p_main is
begin
proc;
exception
when E : others =>
put("something bad happened : " & Ada.Exceptions.Exception_Name(E));
end p_main;
./p_main
something bad happened : P.MY_EXP
A comment by a high rep user on another question I asked earlier today suggested it would be better to swap the order of try/finally and try/except.
So, instead of this:
try
try
//some code
//something that throws an exception, eg: EIndexOutOfRangeException
//more code
except on E : EIndexOutOfRangeException do begin .... end;
finally
// some cleanup code
end;
it would have the try/finally nested inside and the try/except on the outside:
try
try
//some code
//something that throws an exception, eg: EIndexOutOfRangeException
//more code
finally
// some cleanup code
end;
except on E : EIndexOutOfRangeException do begin .... end;
end;
I would like to know when is it appropriate and a good idea to use this idiom, and are there exceptional cases where you shouldn't? Why prefer one over the other? I suppose exceptions being thrown in the cleanup code would be the main consideration, since I imagine it could suppress one of the exceptions if finally throws an exception, but could prevent unexpected bubbling up of errors?
You can use both the ways of writing try,catch and finally and it varies from situation to situation.
Consider the following code listing for try...except inside try...finally.
//You will receive a DataSet is some state.
try
try
//Here you'll change its state and perform operations on it.
//If some exception occurred you will handle it.
except
//Handle exception.
end;
finally
//Put the DataSet again in the same state.
end;
The above code listing shows the uses of try...except inside a try...finally block.
Consider the following code listing for try...finally inside try...except.
try
LObject:= TObject.Create;
//Create an Object. It better idea to create an object outside try..finally block.
//If some exception occured while creating an object an exception will be thrown.
//However its not a good idea to catch such an exception.Let the system handle it.
try
//Use the Object.
finally
//Free Object.
end;
// Returns True
except
// Returns False.
end;
Here the above code listing may be used in such a situation where the function return only true and false. If some exception occurred then simply set the value to false.
When I'm using gtkada and my GUI is running, no exception is managed and the program always crashes. The message is
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
A test code is as follows:
with GLib; use GLib;
with Gtk.Label; use Gtk.Label;
with Gtk.Window; use Gtk.Window;
with Gtk.Frame; use Gtk.Frame;
with Gtk.Button; use Gtk.Button;
with Gtk.Widget; use Gtk.Widget;
with Gtk.Handlers;
with Gtk.Main;
procedure gui_test_4 is
Window : Gtk_Window;
Label : Gtk_Label;
Frame : Gtk_Frame;
Button_S : Gtk_Button;
General_Error : exception;
package Handlers is new Gtk.Handlers.Callback (Gtk_Widget_Record);
package Return_Handlers is
new Gtk.Handlers.Return_Callback (Gtk_Widget_Record, Boolean);
function Delete_Event (Widget : access Gtk_Widget_Record'Class)
return Boolean is
begin
return False;
end Delete_Event;
procedure Destroy (Widget : access Gtk_Widget_Record'Class) is
begin
Gtk.Main.Main_Quit;
end Destroy;
procedure Clicked (Widget : access Gtk_Widget_Record'Class) is
begin
raise General_Error;
exception
when General_Error =>
null;
end Clicked;
begin
Gtk.Main.Init;
Gtk.Window.Gtk_New (Window);
Set_Default_Size (Window, 200, 200);
Gtk.Window.Set_Title (Window, "GUI_Test_4");
Gtk_New (Frame);
Add (Window, Frame);
Gtk_New (Button_S, "Try");
Add (Frame, Button_S);
Return_Handlers.Connect
( Window,
"delete_event",
Return_Handlers.To_Marshaller (Delete_Event'Access)
);
Handlers.Connect
( Window,
"destroy",
Handlers.To_Marshaller (Destroy'Access)
);
Handlers.Connect
( Button_S,
"clicked",
Handlers.To_Marshaller (Clicked'Access)
);
Show_All (Window);
Show (Window);
Gtk.Main.Main;
end gui_test_4;
When the button is pressed, an exception is raised, but it should be managed in the same procedure, but instead of that, the complete program crashes.
Any idea how to solve this problem?
Thanks
Looks like a job for the debugger to me.
In the comments it was mentioned that others are able to successfully run and build this same code. That could mean that your version of GTKAda has issues. It could instead mean that there's a real bug in there, but how/if it expresses depends on what garbage values happened to be loaded into what memory areas when the program starts up.
You might start off by making sure you have the latest version of GTKAda. But after that, fire up the debugger and try to see where its crashing. Note that in Ada programs often crashes happen during package elaboration before the first line of code in your main even gets called. If you are using Gnat you can step through the elaboration process in GDB as well though. With other compilers, you may have to find some elaboration code to try to put breakpoints into to catch it early enough.