Recent

Author Topic: External executable linked resources  (Read 3951 times)

andersonscinfo

  • Full Member
  • ***
  • Posts: 141
External executable linked resources
« on: May 22, 2024, 02:10:06 pm »
Hello, first of all, forgive me for my English, I'm using Google Translate.
I have a program (multiplatform win and linux), this program of mine is an automation system, I have a log class, and through this main exe I open other exes that I also created, a somewhat similar behavior is happening strange, this log class of mine uses a TTextFile to save the logs, and when the main system ends, some programs that I opened through it remain open (this is normal) but it happens that for some reason this TTextFile is stuck to external programs, why not I can delete, below the log class, and also the way I use to open external programs.

Code: Pascal  [Select][+][-]
  1.   with TProcess.Create(nil) do
  2.   begin
  3.     try
  4.       Executable:=ProgramFilename;
  5.       Parameters.Text:=CmdLineParameters;
  6.       Options:=[];
  7.       CurrentDirectory:=ExtractFilePath(ProgramFilename);
  8.       Execute;
  9.     finally
  10.       Free;
  11.     end;
  12.   end;
  13.  

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: External executable linked resources
« Reply #1 on: May 22, 2024, 08:20:57 pm »
In theory the access errors should be gone as long not 2 or more processes try write to same file, but that you control by executing whatever :D
Code: Pascal  [Select][+][-]
  1. unit Basic_Logger;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes,
  9.   SysUtils;
  10.  
  11. type
  12.  
  13.   { TLogger }
  14.  
  15.   TLogger = class
  16.   private
  17.     FFileHandle : TextFile;
  18.     FFileName: String;
  19.     FSubDir: String;
  20.     FMaxFileSize: Int64;
  21.     procedure ValidationSize(const APath: String);
  22.     function GetFileSize(const AFileName: String): Int64;
  23.   strict private
  24.     function WriteStrings(const AMessage: string): Boolean;
  25.   protected
  26.     procedure Initialize();
  27.     procedure Finalize();
  28.   public
  29.     constructor Create(const AFileName: String; const ASubDir: String = 'Log'; const AMaxFileSize: Int64 = 100000);
  30.     destructor Destroy; override;
  31.     procedure LogError( ErrorMessage : string; Location : string );
  32.     procedure LogWarning( WarningMessage : string; Location : string );
  33.     procedure LogStatus( StatusMessage : string; Location : string );
  34.   end;
  35.  
  36.   //inline access
  37.   function Logging: TLogger;
  38.   procedure FreeLogging;
  39.  
  40. implementation
  41.  
  42. Var
  43.   _Logging: TLogger;
  44.  
  45. function Logging: TLogger;
  46. begin
  47.   if not(Assigned(_Logging)) then
  48.     _Logging:=TLogger.Create('');
  49.   Result:=_Logging;
  50. end;
  51.  
  52. procedure FreeLogging;
  53. begin
  54.   if Assigned(_Logging) then
  55.     FreeAndNil(_Logging);
  56. end;
  57.  
  58. procedure TLogger.ValidationSize(const APath: String);
  59. Var
  60.   I: Integer;
  61.   VFileSize: Int64;
  62. begin
  63.   VFileSize:=0;
  64.   if FileExists(APath) then
  65.   begin
  66.     VFileSize:=GetFileSize(APath);
  67.   end;
  68.  
  69.  
  70.   if VFileSize > FMaxFileSize then
  71.   begin
  72.     I:=1;
  73.     while FileExists(APath+IntToStr(I)) do
  74.     begin
  75.       Inc(I);
  76.     end;
  77.     RenameFile(APath, APath+IntToStr(I));
  78.   end;
  79.  
  80. end;
  81.  
  82. function TLogger.GetFileSize(const AFileName: String): Int64;
  83. var
  84. //  FileHandle: THandle;
  85.   fs: TStream;
  86. begin
  87.   Result := -1;
  88.   fs := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
  89.   try
  90.     Result := fs.Size;
  91.   finally
  92.     fs.Free;
  93.   end;
  94. {
  95.   FileHandle := FileOpen(AFileName, fmOpenRead or fmShareDenyNone);
  96.   if FileHandle <> THandle(-1) then
  97.   try
  98.     Result := FileSeek(FileHandle, 0, fsFromEnd);
  99.   finally
  100.     FileClose(FileHandle);
  101.   end;
  102. }
  103. end;
  104.  
  105. function TLogger.WriteStrings(const AMessage: string): Boolean;
  106. begin
  107.   Result := False;
  108.  
  109.   {$I-}
  110.   AssignFile(FFileHandle, FFileName);
  111.   if FileExists(FFileName) then
  112.     Append( FFileHandle )
  113.   else
  114.     Rewrite(FFileHandle);
  115.   {$I+}
  116.  
  117.   if IOResult <> 0 then
  118.     Exit;
  119.  
  120.   WriteLn( FFileHandle, AMessage );
  121.   Flush( FFileHandle );
  122.   CloseFile( FFileHandle );
  123.   Result := True;
  124. end;
  125.  
  126. procedure TLogger.Initialize;
  127. Var
  128.   VFileName: String;
  129.   VDir: String;
  130. begin
  131.   VDir:=ExtractFilePath(ParamStr(0));
  132.   if FSubDir.Trim <> '' then
  133.   begin
  134.     VDir:=VDir+FSubDir;
  135.     VDir:=IncludeTrailingPathDelimiter(VDir);
  136.   end;
  137.   ForceDirectories(VDir);
  138.   if FFileName.Trim = '' then
  139.     FFileName:=ChangeFileExt( ExtractFileName( ParamStr(0) ), '.log' );
  140.   VFileName:=VDir+FFileName;
  141.   FFileName := VFileName;
  142.  
  143.   ValidationSize(VFileName);
  144. end;
  145.  
  146. procedure TLogger.Finalize();
  147. begin
  148. //  CloseFile( FFileHandle );
  149. end;
  150.  
  151. { TLogger }
  152. constructor TLogger.Create(const AFileName: String; const ASubDir: String;
  153.   const AMaxFileSize: Int64);
  154. begin
  155.   FFileName:=AFileName;
  156.   FSubDir:=ASubDir;
  157.   if AMaxFileSize < 1 then
  158.     FMaxFileSize:=100000
  159.   else
  160.     FMaxFileSize:=AMaxFileSize;
  161.   Initialize();
  162. end;
  163.  
  164. destructor TLogger.Destroy;
  165. begin
  166.   Finalize();
  167.   inherited;
  168. end;
  169.  
  170. procedure TLogger.LogError(ErrorMessage: string; Location: string);
  171. var
  172.   S : string;
  173. begin
  174.   S := '*** ERROR *** : @ ' + DateTimeToStr(Now) + ' MSG : ' + ErrorMessage + ' IN : ' + Location;
  175.   WriteStrings(S);
  176. end;
  177.  
  178. procedure TLogger.LogStatus(StatusMessage: string; Location: string);
  179. var
  180.   S : string;
  181. begin
  182.   S := 'STATUS INFO : @ ' + DateTimeToStr(Now) + ' MSG : ' + StatusMessage + ' IN : ' + Location;
  183.   WriteStrings(S);
  184. end;
  185.  
  186. procedure TLogger.LogWarning(WarningMessage: string; Location: string);
  187. var
  188.   S : string;
  189. begin
  190.   S := '=== WARNING === : @ ' + DateTimeToStr(Now) + ' MSG : ' + WarningMessage + ' IN : ' + Location;
  191.   WriteStrings(S);
  192. end;
  193.  
  194. finalization
  195.   FreeLogging;
  196.  
  197. end.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

andersonscinfo

  • Full Member
  • ***
  • Posts: 141
Re: External executable linked resources
« Reply #2 on: May 22, 2024, 11:44:09 pm »
Thank you very much for your collaboration, this will solve it, thanks

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: External executable linked resources
« Reply #3 on: May 23, 2024, 01:49:13 am »
If needed, here is a TStream replacement for the legacy code:
Code: Pascal  [Select][+][-]
  1. function TLogger.WriteStrings(const AMessage: AnsiString): Boolean;
  2. var
  3.   fs: TStream;
  4.   i: Integer;
  5. begin
  6.   // initialize result
  7.   Result := False;
  8.   // check if append or create new
  9.   if FileExists(FFileName) then
  10.     fs := TFileStream.Create(FFileName, fmOpenReadWrite)
  11.   else
  12.     fs := TFileStream.Create(FFileName, fmCreate or fmOpenReadWrite);
  13.   try
  14.     // append to end of file
  15.     i := fs.Size;
  16.     fs.Position := i;
  17.     // add the string
  18.     fs.WriteBuffer(AMessage[1], Length(AMessage));
  19.     // insert a CRLF, like WriteLn() does do
  20.     fs.WriteBuffer(LineEnding[1], Length(LineEnding));
  21.     // test if filesize is increased
  22.     Result := (i < fs.Size);
  23.   finally
  24.     fs.Free;
  25.   end;
  26. end;
« Last Edit: May 23, 2024, 01:54:02 am by KodeZwerg »
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

andersonscinfo

  • Full Member
  • ***
  • Posts: 141
Re: External executable linked resources
« Reply #4 on: May 23, 2024, 12:57:49 pm »
I ended up using textfile because I thought the performance would be better, I remember that in the past I used textfile for large files and it seemed instantaneous, very fast, but I will evaluate the use of stream too, at the moment the change above worked well, thanks again .

Att

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: External executable linked resources
« Reply #5 on: May 24, 2024, 12:08:52 am »
Switching to a TStream or TList can have its benefits compared by using low level access.

A TList is most of all slower than low level or TStream since it needs to load the file before you can access it and it writes everything on save.

A TStream has the advantage that it is buffered, it just read or write when you command it and has in theory no file size limit, imagine you write the data to a TMemoryStream instead direct to a file and create a "Flush()" method to append current TMemoryStream to a TFileStream = less file access = more performance with disadvantage that on a crash the log might miss latest additions. Since you got 3 different error levels, after the "LogError()" I would "Flush()" and for the other two errors I would add internal a counter and increase that number, after maybe 10 messages do "Flush()".
A negative performance in belonging to speed I can not detect, just the opposite, its faster than low level.

Just my thoughts about it and yes I would always prefer TStream :D
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

Thaddy

  • Hero Member
  • *****
  • Posts: 16145
  • Censorship about opinions does not belong here.
Re: External executable linked resources
« Reply #6 on: May 24, 2024, 04:03:56 pm »
TTextFile and TextFile are the poor man's answer for the Pascal type: Text.
I hope you do not use such aliases anymore.
https://www.freepascal.org/docs-html/rtl/system/textfile.html

And yes, streams are usually faster and more comfortable.
If I smell bad code it usually is bad code and that includes my own code.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5752
  • Compiler Developer
Re: External executable linked resources
« Reply #7 on: May 26, 2024, 10:03:22 pm »
TTextFile and TextFile are the poor man's answer for the Pascal type: Text.
I hope you do not use such aliases anymore.
https://www.freepascal.org/docs-html/rtl/system/textfile.html

They are not the poor man's answer. They are to allow users to continue using the old style Pascal I/O within VCL (or LCL) code without having to manually specify the System unit as prefix, just like AssignFile or CloseFile instead of Assign or Close.

 

TinyPortal © 2005-2018