Il 11/02/2013 09:21, Michael Van Canneyt ha scritto:
On Mon, 11 Feb 2013, Giuliano Colla wrote:
3) But if also the *path* to the file doesn't yet exist, it just
crashes without rising an exception that the user application can
handle somehow.
This is incorrect. It does tell you why it fails.
This is rather unpleasant, because the path provided by
GetAppConfigXx does usually exist, so you have an application which
99% of the times works just fine, and 1% of the times crashes without
telling why.
It tells you *exactly* why it 'crashes':
home: >./ti
An unhandled exception occurred at $000000000042AE87:
EFCreateError: Unable to create file "/tmp/path/to/nothing.txt"
$000000000042AE87
This is true only if you invoke the program from command line, which is
something the end user will never do. Consider that this sort of errors
doesn't pop up when you're developing, but rather after you've deployed
your application.
Let's assume that saving configuration is on a FormClose procedure, as
usual, and you have a try..finally construct, as usual.
Your user starts the program by clicking on a launching Icon.
When he clicks on a Close button, if the path doesn't exist the program
won't be terminated, and he's left with a window he can't close. On a
terminal you can see
TApplication.HandleException Unable to create file "/home/colla/.pippo/uclc.cfg"
Stack trace:
$080BAF29
[..]
exception at 080BAF29:
Unable to create file "/home/colla/.pippo/uclc.cfg".
But no error is shown on the screen (try..finally has trapped it), and
the form is not closed. Then the user will attempt to click again on the
close button of a form which is already "almost" closed. On a terminal
you can see:
TApplication.HandleException Access violation
Stack trace:
[..]
$082A9B6D GTK2WSBUTTON_CLICKED, line 2417
But again nothing on the screen. The program hangs here. From command
line you need a ^C to terminate. Otherwise you need a killall. Which
isn't a very good situation for an end user.
home: >cat ti.pp
program ti;
uses inifiles;
begin
with TMemIniFile.create('/tmp/path/to/nothing.txt') do
try
WriteString('A','B','C');
UpdateFile;
finally
Free;
end;
end.
However, I agree that it should try to create the path as well.
I have adapted the implementation.
You'll get an error telling you if it failed to create the dir:
An unhandled exception occurred at $0000000000427F7E:
EInOutError: Could not create directory "/my/path/to/"
$0000000000427F7E
Which means that you are still (as previously) responsible for
catching possible errors.
But these errors should be less frequent with this change.
Thank you, attempting to create the path is a welcome improvement. It
makes TIniFile behavior much more consistent.
However, what I've learned from this episode is that while attempting to
save configuration data using TINIFile on program termination you should
never use a try..finally construct, as it's suggested everywhere, but
rather a try..except (or both). Otherwise you'll never be able to catch
possible errors.
Giuliano
_______________________________________________
fpc-pascal maillist - fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-pascal