Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2025-07

TIniFile crash

9 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

James Richters

I'm having an issue with TIniFile,
I have a pretty simple procedure, It deletes the old .ini file, waits for it to be gone, creates a new one, writes a bunch of variables to it, then frees it. It works 99% of the time, but 1% of the time it crashes right in the middle of writing the file. The previous one was really deleted because there is nothing left of the original after the crash, it contains only lines up to the failure. I just don't see what I am doing wrong and I am hoping someone can help me figure out how to fix this. This is a single thread console application created with FreePascal with out Lazarus, and this file is not used by anything else. I just happened to catch it this time and I was sitting right here and nothing else was accessing Location.ini when the crash happened.
This happens on multiple difference computers. Most of which have no purpose other than to run this one program, so there is never anything else even open in the have any idea why this is happening and how I might be able to prevent it?
Below is the crash and related source code.

James

Saving Location
An unhandled exception occurred at $00603277:
EFCreateError: Unable to create file
"I:\Programming\Gcode\Mill\Location.ini": The process cannot access the file because it is being used by another process.
$00603277
$0060314F
$00608338
$00602148
$006021F2
$004675D7 INI_WRITESTRING, line 7204 of
I:/Programming/Gcode/Mill/PaStep.pas
$004AFC88 SAVEPOSITION, line 23835 of
I:/Programming/Gcode/Mill/PaStep.pas
$004AF8D6 SAVEBIT, line 23803 of I:/Programming/Gcode/Mill/PaStep.pas $004BF211 ENDPROGRAM, line 27228 of I:/Programming/Gcode/Mill/PaStep.pas $00408099 CTRL_X_EXIT, line 1355 of
I:/Programming/Gcode/Mill/Promill.pas
$00429825 main, line 7858 of I:/Programming/Gcode/Mill/Promill.pas

Line 7204 is Ini.WriteString(Ini_Sec,Ini_Tag,Ini_Val); from this procedure

Procedure Ini_WriteString(Const Ini_Sec,ini_Tag: AnsiString; Const Ini_Val:
AnsiString);
Begin
   Ini.WriteString(Ini_Sec,Ini_Tag,Ini_Val);
End;
Line 23835 is    Ini_WriteString    ('#### Tap File ####'                ,
'Tap_Path'                         , Tap_Path                   );
From the SavePosition procedure below

Here is the SavePostition Procedure

Procedure SavePosition;
Var
  fileSource, fileDest: AnsiString;
  Resultsofit : Boolean;
Begin
   Writeln('Saving Location');
   DeleteFileAndWaitForItToBeGone(Prog_dir+'Location.ini');
   If Ini_Save_Location_On_C Then
DeleteFileAndWaitForItToBeGone(Promill_C+Program_Path+'\Location.ini');
   Ini := TIniFile.Create(Prog_dir+'Location.ini');
   Ini_WriteString ('#### Location ####'                   , 'Postition.X'
, Sav[X_Axis]                );
   Ini_WriteString ('#### Location ####'                   , 'Postition.Y'
, Sav[Y_Axis]                );
   Ini_WriteString ('#### Location ####'                   , 'Postition.Z'
, Sav[Z_Axis]                );
   Ini_WriteString ('#### Location ####'                   , 'Postition.W'
, Sav[W_Axis]                );
   Ini_WriteString ('#### Location ####'                   , 'Postition.L'
, Sav[L_Axis]                );
   Ini_WriteString ('#### Location ####'                   , 'Postition.R'
, Sav[R_Axis]                );
   Ini_WriteString ('#### Location ####'                   , 'Postition.A'
, Sav[A_Axis]                );
   Ini_WriteString ('#### Location ####'                   , 'Postition.B'
, Sav[B_Axis]                );
   Ini_WriteString ('#### Location ####'                   , 'Postition.C'
, Sav[C_Axis]                );
   Ini_WriteString    ('#### Location ####'                , 'Swap_Current'
, SWAPCURRENT                );
   Ini_WriteDouble    ('#### Location ####'                ,
'Current_Value_At_Home.Z'          , Current_Value_At_Home.Z    );
   Ini_WriteDouble    ('#### Location ####'                ,
'Current_Value_At_Home.W'          , Current_Value_At_Home.W    );
   Ini_WriteString    ('#### Location ####'                , 'Tool'
, P_Value[P_Head_Tool]       );
   Ini_WriteString    ('#### Location ####'                , 'Zone'
, P_Value[P_Zone]            );
   Ini_WriteString    ('#### Location ####'                , 'MultiSpeed'
, P_Value[MultiSpeed]        );
   Ini_WriteBoolean   ('#### Tap File ####'                ,
'Use_Default_Tap_Drive'            , Use_Default_Tap_Drive      );
   Ini_WriteBoolean   ('#### Tap File ####'                ,
'Use_Default_Tap_Directory'        , Use_Default_Tap_Directory  );
   Ini_WriteBoolean   ('#### Tap File ####'                ,
'Tap_Files_Only'                   , Tap_Files_Only             );
   Ini_WriteString    ('#### Tap File ####'                , 'Tap_Drive'
, Tap_Drive                  );
   Ini_WriteString    ('#### Tap File ####'                , 'Tap_Path'
, Tap_Path                   );
   Ini_WriteString    ('#### Tap File ####'                ,
'Tap_SubDirectory'                 , Tap_SubDirectory           );
   Ini_WriteString    ('#### Tap File ####'                , 'File'
, P_Value[P_File]            );
   Ini_WriteString    ('#### Tap File ####'                ,
'File_Extension'                   , PvalueP_Fileext            );
   Ini_WriteString    ('#### Tap File ####'                , 'Load_Filename'
, Load_Filename              );
   Ini_WriteString    ('#### Tap File ####'                , 'Loaded_File'
, Loaded_File                );

. a bunch of other things .

   Ini_WriteFormated ('#### Timers ####'               ,
'Laser_Fan_Off_Time'                  , floattostr(Laser_Fan_Off_Time) ,45,
'Off' ,0 , '');
   Ini.Free;
   If Ini_Save_Location_On_C Then
      Begin
         fileSource := Prog_dir+'Location.ini';
         fileDest := Promill_C+Program_Path+'\Location.ini';
         Resultsofit := CopyFile(PChar(fileSource), PChar(fileDest), False);
      End;
   //Writeln('Position Saved');
   //readln;
End;

DeleteFileAndWaitForItToBeGone is this

Procedure DeleteFileAndWaitForItToBeGone(Const TargetFileName: String);
Var
   Elapsedmilliseconds       : Integer;
   Sleepintervalmilliseconds : Integer;
   Timeoutmilliseconds       : Integer;
Begin
   TimeoutMilliseconds := 1000;
   SleepIntervalMilliseconds := 10;
   ElapsedMilliseconds := 0;
   If FileExists(TargetFileName) Then
      Begin
         DeleteFile(TargetFileName);
         While (FileExists(TargetFileName)) And (ElapsedMilliseconds <
TimeoutMilliseconds) Do
            Begin
               Sleep(SleepIntervalMilliseconds);
               Inc(ElapsedMilliseconds, SleepIntervalMilliseconds);
            End;
         If FileExists(TargetFileName) Then
            Begin
               TextColor(CC_Red);
               Writeln('Error: File still exists after attempted deletion:
', TargetFileName);
            End;
      End;
End;

Immediately after the crash Location.ini contains:

[#### Location ####]
Postition.X=0
Postition.Y=*
Postition.Z=19.6856
Postition.W=5.735
Postition.L=
Postition.R=
Postition.A=0
Postition.B=0
Postition.C=0
Swap_Current=Z
Current_Value_At_Home.Z=6.766
Current_Value_At_Home.W=5.08
Tool=17
Zone=
MultiSpeed=

[#### Tap File ####]
Use_Default_Tap_Drive=False
Use_Default_Tap_Directory=True
Tap_Files_Only=True
Tap_Drive=M:

Ralf Quint
to James Richters: I'm having an issue with TIniFile, I have a pretty simple procedure, It deletes the old…
James Richters wrote 22 lines
I’m having an issue with TIniFile, I have a pretty simple procedure,It deletes the old .ini file, waits for it to be gone, creates a new one, writes a bunch of variables to it, then frees it.It works 99% of the time, but 1% of the time it crashes right in the middle of writing the file.The previous one was really deleted because there is nothing left of the original after the crash, it contains only lines up to the failure.I just don’t see what I am doing wrong and I am hoping someone can help me figure out how to fix this. This is a single thread console application created with FreePascal with out Lazarus, and this file is not used by anything else.I just happened to catch it this time and I was sitting right here and nothing else was accessing Location.ini when the crash happened. This happens on multiple difference computers.Most of which have no purpose other than to run this one program, so there is never anything else even open in the system at all. Anyone have any idea why this is happening and how I might be able to prevent it? Below is the crash and related source code.

To narrow down where and why this would crash, you might want to try and use some different procedure. Just going by a guts feeling, I guess your problem is caused by this "waiting until the ini file is really deleted" procedure.
To test this, please try to write the contents to the new .INI file, deleting the old one and then rename the new one. I suspect that in this order of things, it will not crash while writing to the new file...

If it does still crash, then the problem is within the writing of the contents of the .ini file, otherwise this smells like some timing issue introduced due to that waiting procedure, possibly in connection with the OS file caching...

Ralf

James Richters
to Ralf Quint

I will try just creating a temp file, and once it’s completed delete the original file then rename the temp file to the correct name, it’s a good idea, and a least I will now that nothing I am doing is trying to access the file… because I can generate some random name for the temp file, but I guess it wouldn’t stop something like antivirus from trying to scan it before I’m done. It’s a difficult problem to figure out because it happens very rarely, but it does happen enough to be annoying.

I put the delete and wait for it to be gone procedure just to make sure the file was really gone before trying to create a new one in an attempt to solve this issue, and it is well past that part of the code when the crash happens, it had already written 19 entries to the new ini file when it crashed, and that’s why I’m confused, the error is about creating the file, but it was already created and there were already 19 successful entries to it… so what’s it creating at the point of the crash?

The thing is that the file that is on the disk after the crash is only a partial file, up to the exact line that crashed, so the file must have finished the delete and there was no problem creating a new file and writing to it.

I am having a suspicion that Ini.WriteString is opening the file, writing to it then closing it, which makes no sense to me, I would think that ini.create would create the file and open it, and it would remain open until ini.free.. but the fact that it sometimes gives me this message:

EFCreateError: Unable to create file "I:\Programming\Gcode\Mill\Location.ini": The process cannot access the file because it is being used by another process. $00603277

After writing successfully 19 entries to the ini files seems to indicate that it’s opening and closing the file for each Ini.WriteString and that 1% of the time the OS didn’t finish writing the file before it was being opened again? I’m just guessing here about what could cause this.

James

Earlier message 17 lines
From: fpc-pascal On Behalf Of Ralf Quint via fpc-pascal Sent: Tuesday, July 29, 2025 2:26 PM To: Cc: Ralf Quint Subject: Re: [fpc-pascal] TIniFile crash On 7/26/2025 2:05 PM, James Richters via fpc-pascal wrote: I’m having an issue with TIniFile, I have a pretty simple procedure, It deletes the old .ini file, waits for it to be gone, creates a new one, writes a bunch of variables to it, then frees it. It works 99% of the time, but 1% of the time it crashes right in the middle of writing the file. The previous one was really deleted because there is nothing left of the original after the crash, it contains only lines up to the failure. I just don’t see what I am doing wrong and I am hoping someone can help me figure out how to fix this. This is a single thread console application created with FreePascal with out Lazarus, and this file is not used by anything else. I just happened to catch it this time and I was sitting right here and nothing else was accessing Location.ini when the crash happened. This happens on multiple difference computers. Most of which have no purpose other than to run this one program, so there is never anything else even open in the have any idea why this is happening and how I might be able to prevent it? Below is the crash and related source code. To narrow down where and why this would crash, you might want to try and use some different procedure. Just going by a guts feeling, I guess your problem is caused by this "waiting until the ini file is really deleted" procedure. To test this, please try to write the contents to the new .INI file, deleting the old one and then rename the new one. I suspect that in this order of things, it will not crash while writing to the new file... If it does still crash, then the problem is within the writing of the contents of the .ini file, otherwise this smells like some timing issue introduced due to that waiting procedure, possibly in connection with the OS file caching... Ralf
Michael Van Canneyt
to James Richters
James Richters wrote 15 lines
I will try just creating a temp file, and once it’s completed delete the original file then rename the temp file to the correct name, it’s a good idea, and a least I will now that nothing I am doing is trying to access the file… because I can generate some random name for the temp file, but I guess it wouldn’t stop something like antivirus from trying to scan it before I’m done. It’s a difficult problem to figure out because it happens very rarely, but it does happen enough to be annoying. I put the delete and wait for it to be gone procedure just to make sure the file was really gone before trying to create a new one in an attempt to solve this issue, and it is well past that part of the code when the crash happens, it had already written 19 entries to the new ini file when it crashed, and that’s why I’m confused, the error is about creating the file, but it was already created and there were already 19 successful entries to it… so what’s it creating at the point of the crash? The thing is that the file that is on the disk after the crash is only a partial file, up to the exact line that crashed, so the file must have finished the delete and there was no problem creating a new file and writing to it. I am having a suspicion that Ini.WriteString is opening the file, writing to it then closing it, which makes no sense to me, I would think that ini.create would create the file and open it, and it would remain open until ini.free.. but the fact that it sometimes gives me this message: EFCreateError: Unable to create file "I:\Programming\Gcode\Mill\Location.ini": The process cannot access the file because it is being used by another process. $00603277 After writing successfully 19 entries to the ini files seems to indicate that it’s opening and closing the file for each Ini.WriteString and that 1% of the time the OS didn’t finish writing the file before it was being opened again? I’m just guessing here about what could cause this.

The TIniFile indeed writes to disk after every writeNNN()

There are 2 possibilities to change this behaviour:

- Set CacheUpdates to true, and call UpdateFile when done.

- Use TMemInifile, and call UpdateFile when done.
(TMemIniFIle simply sets CacheUpdates to true in its constructor)

This should improve matters.

You can also combine this with the "use temp filename and rename" approach.

Michael.

Rafael Picanço

Hi James, here are some routines to a load-create/archive cycle using a temporary TIniFile:

program handle_inifile;
uses Classes, SysUtils, IniFiles,
FileUtil;// In Lazarus you will need the LazUtils package to see the
FileUtil unit
procedure ArchiveIniFileTo(var AIniFile : TIniFile; ADestination : string);
begin
  if Assigned(AIniFile) then begin
    { You may want to implement a method
      to update/invalidate in-memory stuff here }
    //IniFileDescendent.Invalidate;
    AIniFile.UpdateFile; // Flush data to disc
    CopyFile(AIniFile.FileName, ADestination);
    if FileExists(AIniFile.FileName) then begin
      DeleteFile(AIniFile.FileName);
    end;
  end;
end;
function LoadIniFile(AFilename: string) : TIniFile;
begin
  Result := TIniFile.Create(AFilename);
  Result.CacheUpdates := True;
end;
var
  TemporaryIniFile : TIniFile;
begin
  TemporaryIniFile := LoadIniFile('tmp.ini');
  try
    TemporaryIniFile.WriteString('Section', 'Key', 'Value'); // in memory
cached updates
     ArchiveIniFileTo(TemporaryIniFile, 'destination.ini');
  finally
     TemporaryIniFile .Free;
  end;
end.

I use this approach because in-memory manipulation of the ini file is what I need (with the bonus of being faster and safer).

Best,
Rafael Picanço

Show quoted text 140 lines
Send fpc-pascal mailing list submissions to To subscribe or unsubscribe via the World Wide Web, visit https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal or, via email, send a message with subject or body 'help' to You can reach the person managing the list at When replying, please edit your Subject line so it is more specific than "Re: Contents of fpc-pascal digest..." Today's Topics: 1. Re: TIniFile crash (Michael Van Canneyt) 2. Broken Links on Free Pascal Wiki (Tim Coates) ---------------------------------------------------------------------- Message: 1 Date: Wed, 30 Jul 2025 16:25:51 +0200 (CEST) From: Michael Van Canneyt To: FPC-Pascal users discussions Subject: Re: [fpc-pascal] TIniFile crash Message-ID: Content-Type: text/plain; charset="utf-8"; Format="flowed" On Tue, 29 Jul 2025, James Richters via fpc-pascal wrote: > I will try just creating a temp file, and once it?s completed delete the original file then rename the temp file to the correct name, it?s a good idea, and a least I will now that nothing I am doing is trying to access the file? because I can generate some random name for the temp file, but I guess it wouldn?t stop something like antivirus from trying to scan it before I?m done. It?s a difficult problem to figure out because it happens very rarely, but it does happen enough to be annoying. > > I put the delete and wait for it to be gone procedure just to make sure the file was really gone before trying to create a new one in an attempt to solve this issue, and it is well past that part of the code when the crash happens, it had already written 19 entries to the new ini file when it crashed, and that?s why I?m confused, the error is about creating the file, but it was already created and there were already 19 successful entries to it? so what?s it creating at the point of the crash? > > The thing is that the file that is on the disk after the crash is only a partial file, up to the exact line that crashed, so the file must have finished the delete and there was no problem creating a new file and writing to it. > > I am having a suspicion that Ini.WriteString is opening the file, writing to it then closing it, which makes no sense to me, I would think that ini.create would create the file and open it, and it would remain open until ini.free.. but the fact that it sometimes gives me this message: > > EFCreateError: Unable to create file "I:\Programming\Gcode\Mill\Location.ini": The process cannot access the file because it is being used by another process. > $00603277 > > After writing successfully 19 entries to the ini files seems to indicate > that it?s opening and closing the file for each Ini.WriteString and that > 1% of the time the OS didn?t finish writing the file before it was being > opened again? I?m just guessing here about what could cause this. The TIniFile indeed writes to disk after every writeNNN() There are 2 possibilities to change this behaviour: - Set CacheUpdates to true, and call UpdateFile when done. - Use TMemInifile, and call UpdateFile when done. (TMemIniFIle simply sets CacheUpdates to true in its constructor) This should improve matters. You can also combine this with the "use temp filename and rename" approach. Michael. ------------------------------ Message: 2 Date: Thu, 31 Jul 2025 17:50:57 +1000 From: Tim Coates To: FPC-Pascal users discussions Subject: [fpc-pascal] Broken Links on Free Pascal Wiki Message-ID: < > Content-Type: text/plain; charset="utf-8" Dear Free Pascal Team, I understand and appreciate that Free Pascal is a volunteer-driven project, and I?m grateful for all the work that has gone into it over the years. While researching style guides for something I?m working on, I went to the Free Pascal wiki to look for documentation. Unfortunately, both the links I found for the style guide and the project guidelines appear to be dead. I was hoping to refer to these resources, but couldn?t access them. I could otherwise Delphi 11 based guide? Out of curiosity, I also wondered whether there might be other important pages that have gone offline or been moved. Is there an updated location for these documents? And if there?s a way I could help with checking or updating wiki links, I?d be happy to pitch in. Thanks again for your time and for maintaining such a valuable tool for the Pascal community. Best regards, Tim Coates -------------- next part -------------- An HTML attachment was scrubbed... URL: < http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20250731/1a5bb934/attachment-0001.htm > ------------------------------ Subject: Digest Footer _______________________________________________ fpc-pascal maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ------------------------------ End of fpc-pascal Digest, Vol 253, Issue 16 *******************************************
James Richters
to Rafael Picanço

Thank you for the great suggestions! I did not know I could have a memory version of the ini file. that sounds like a better solution than what I am doing. Right now I am reading in all the ini settings and putting them into variables like Ini_myvariable

then I use those as needed.. then write them all out, but if I am understanding it correctly could I just use the memory version of the ini file directly?

It seems like that would be much easier and also solve the issues.

James

Flávio Etrusco
to James Richters

Em sex., 1 de ago. de 2025, 17:54, James Richters via fpc-pascal <

Show quoted text 16 lines
escreveu: Thank you for the great suggestions! I did not know I could have a memory version of the ini file. that sounds like a better solution than what I am doing. Right now I am reading in all the ini settings and putting them into variables like Ini_myvariable then I use those as needed.. then write them all out, but if I am understanding it correctly could I just use the memory version of the ini file directly? It seems like that would be much easier and also solve the issues. James

https://github.com/fpc/FPCSource/blob/main/packages/fcl-base/src/inifiles.pp

To try to resolve your issue you should use TMemIniFile and invoke Rename() before freeing the TMemIniFile (or invoking UpdateFile explicitly) to save to the temporary file.

TMemIniFile is just TIniFile with some extra methods and with CacheUpdates defaulting to True. They parse the whole ini file in the constructor, so values are always read from memory.

Regards,
Flávio

P.S. Although these classes are meant for compatibility with Delphi/Windows, maybe they should provide extra methods with correct exception handling and "atomic" saving with temporary file? Or maybe someone can recommend alternatives?

Benito van der Zander
to Flávio Etrusco

Hi Fpc-Pascal Users,

P.S. Although these classes are meant for compatibility with Delphi/Windows,

that's not even entirely compatible. Afair Windows could partially overwrite lines in the file instead of the whole file at once

maybe they should provide extra methods with correct exception handling and "atomic" saving with temporary file?

I suggested that almost ten years ago but they didn’t want to:

https://gitlab.com/freepascal.org/fpc/source/-/issues/30439

Here everyone keeps running into the same problems year after year and nothing improves

Or maybe someone can recommend alternatives?

I once overwrote UpdateFile to use temporary files:

https://github.com/benibela/videlibri/blob/master/inifilessafe.pas

Sincerely,
Benito

Flávio Etrusco wrote 43 lines
Em sex., 1 de ago. de 2025, 17:54, James Richters via fpc-pascal escreveu: Thank you for the great suggestions!I did not know I could have a memory version of the ini file. that sounds like a better solution than what I am doing.Right now I am reading in all the ini settings and putting them into variables like Ini_myvariable then I use those as needed.. then write them all out, but if I am understanding it correctly could I just use the memory version of the ini file directly? It seems like that would be much easier and also solve the issues. James https://github.com/fpc/FPCSource/blob/main/packages/fcl-base/src/inifiles.pp To try to resolve your issue you should use TMemIniFile and invoke Rename() before freeing the TMemIniFile (or invoking UpdateFile explicitly) to save to the temporary file. TMemIniFile is just TIniFile with some extra methods and with CacheUpdates defaulting to True. They parse the whole ini file in the constructor, so values are always read from memory. Regards, Flávio P.S. Although these classes are meant for compatibility with Delphi/Windows, maybe they should provide extra methods with correct exception handling and "atomic" saving with temporary file? Or maybe someone can recommend alternatives? _______________________________________________ fpc-pascal maillist https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal