Inno Setup LoadStringFromFile fails when file is open in another process
Asked Answered
A

2

3

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?

Armchair answered 9/12, 2016 at 10:47 Comment(0)
P
2

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.

Peradventure answered 9/12, 2016 at 11:37 Comment(1)
I am accepting this as the answer, as it directly answers the question I asked. However, in this instance, Graeme Perrow's answer is actually a far more elegant and simple way of telling when the database is fired up and accepting requests in SQL Anywhere.Armchair
S
3

When spawning the database server, use the dbspawn utility, which is designed for this purpose. You spawn dbspawn along with the dbeng/dbsrv command you want to run, and it starts the server for you. The dbspawn utility doesn't return until the database server is up, running, and ready to accept requests, so there's no guesswork needed and no need to read the console log file.

I don't know what version of SQL Anywhere you're running, but here is the documentation for v17. It should be the same in any other version.

Silicious answered 9/12, 2016 at 18:0 Comment(1)
I have accepted Martin Prikryl's answer as it directly addresses the coding question I asked and will be most relevant for other people looking for an answer to this question. However, I have actually used your answer for my solution. This is exactly what I needed in this particular case. My solution was a workaround I came up with in absence of knowing about this handy little utility. Thanks. Upvoted.Armchair
P
2

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.

Peradventure answered 9/12, 2016 at 11:37 Comment(1)
I am accepting this as the answer, as it directly answers the question I asked. However, in this instance, Graeme Perrow's answer is actually a far more elegant and simple way of telling when the database is fired up and accepting requests in SQL Anywhere.Armchair

© 2022 - 2024 — McMap. All rights reserved.