Search code examples
inno-setupsqlanywherepascalscript

Inno Setup LoadStringFromFile fails when file is open in another process


To check to see when a database (SQL Anywhere) is fired up and ready to receive requests I am outputting the database message window to a log (text) file and then attempting to read this using LoadStringFromFile, which I then search for specific text using Pos. The problem is that this fails (I assume) as the file is in use.

Exec(strInstallPath + '\Bin32\dbeng17.exe', '-n ' + strEngineName + ' "' + strInstallPath + '\Database\Olympus.db" -n ' + strDatabaseName + ' -gdall -xtcpip -ti0 -c25p -ot "' + strTempPath + '\dbeng.log"', '', SW_HIDE,
  ewNoWait, intResultCode);
if not LoadStringFromFile(strTempPath + '\dbeng.log', astrDatabaseEngineLog) then
  begin
    Log('Loading string from file failed.');
  end;

I have also tried to copy the log file using FileCopy and attempt to read from the copy of the file, but FileCopy also fails.

if not FileCopy(strTempPath + '\dbeng.log', strTempPath + '\dbengcopy.log', False) then
  begin
    Log('File copy failed.');
  end;

Is there any way to read from a file that is in use or another way to do this?


Solution

  • Use the TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone).

    In Unicode version of Inno Setup (the only version as of Inno Setup 6), its use is tricky due to a bad interface of the class.

    function BufferToAnsi(const Buffer: string): AnsiString;
    var
      W: Word;
      I: Integer;
    begin
      SetLength(Result, Length(Buffer) * 2);
      for I := 1 to Length(Buffer) do
      begin
        W := Ord(Buffer[I]);
        Result[(I * 2)] := Chr(W shr 8); // high byte
        Result[(I * 2) - 1] := Chr(Byte(W)); // low byte
      end;
    end;
     
    function LoadStringFromLockedFile(
      const FileName: string; var S: AnsiString): Boolean;
    var
      Buffer: string;
      Stream: TFileStream;
    begin
      Result := True;
      try
        Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
        try
          SetLength(Buffer, Stream.Size div 2);
          Stream.ReadBuffer(Buffer, Stream.Size);
          S := BufferToAnsi(Buffer);
        finally
          Stream.Free;
        end;
      except
        Result := False;
      end;
    end;
    

    The code is based on TLama's code posted in Read bytes from file at desired position with Inno Setup.