I am trying to record the session log from other applications (Proxifier) to a Memo. I've tried using the command :
procedure TForm1.TimerTimer(Sender: TObject);
begin
Memo1.Lines.LoadFromFile('C:\PMASSH\Proxyfier\Profiles\Log.txt');
end;
but at certain times I get an error
Can you help my problem above ? I would really appreciate of all the answers.
Thanks
The other program has opened the file with a sharing mode that does not allow other processes to read it. Typically this happens when the other application is writing to the file.
There's not a whole lot you can do about this. This is perfectly normal behaviour, and is to be expected. You can try detecting the error, waiting for a short period of time, and re-trying.
Since you are already running this on a timer, the re-try will just happen. So perhaps you just need to suppress those exceptions:
procedure TForm1.TimerTimer(Sender: TObject);
begin
try
Memo1.Lines.LoadFromFile(...);
except
on EFOpenError do
; //swallow this error
end;
end;
Note that detecting EFOpenError
is perhaps a little crude. Perhaps there are other failure modes that lead to that error. However, as a first pass, the code above is a decent start.
David's answer is correct. I just want to clarify why this is happening.
The answer lies in the code:
procedure TStrings.LoadFromFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
as you can see, the file is accessed for sharing but no writing is allowed. you can solve this by creating the filestream yourself:
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
and then use the Lines.LoadFromStream()
method to load the contents into the memo
Please note that the problem may subsist in cases where the other application has opened the file in exclusive mode (i.e. no sharing), so proper Exception management like in David's answer is still needed.
You can try your luck with ReadFile WinAPI. On a shared read open mode, you'll be able to sneak and read the contents of the file at last file buffer flush. If that another application (Proxifier) opened the file with CreateFile WinAPI with FILE_SHARE_READ share mode then you'll be able to open it for reading, as long as you use ReadFile API. Standart LoadFromFile method won't work here if it still was opened for share, and you'll get the same 'lock' error.
But here's the catch.. You'll have to deal with buffers, sizes and handles... You'll have to assing a handle to file for reading, get the file size with that handle, set an array with that size, do read to that array and assign, add (whatever) that array to the memo.. Pure usage of WinAPI. Some job for a simple task...
Here is a basic example of how to deal with files with WinAPI:
The key assumption of that other application's file open process:
var
Form1: TForm1;
logfile: Textfile;
h: THandle;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
// AssignFile(logfile, 'c:\deneme.txt');
// Rewrite(logfile);
h := CreateFile('C:\deneme.txt', GENERIC_WRITE, FILE_SHARE_READ, nil,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
Timer1.enabled := true;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Timer1.enabled := false;
// CloseFile(logfile);
CloseHandle(h);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
str: AnsiString;
p: pointer;
buf: array of ansichar;
written: cardinal;
begin
// Writeln(logfile, 'denemeStr');
str := 'denemeStr' + #13#10;
p := pansichar(str);
SetLength(buf, length(str));
move(p^, buf[0], length(str));
WriteFile(h, buf[0], length(buf), written, nil);
FlushFileBuffers(h);
end;
And if it's been shared for reading, this is how you can read from it:
procedure TForm1.Button1Click(Sender: TObject);
var
h: THandle;
buf: array of ansichar;
size, read: cardinal;
begin
Memo1.Lines.Clear;
// Memo1.Lines.LoadFromFile('c:\deneme.txt');
h := CreateFile('C:\deneme.txt', GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
size := GetFileSize(h, nil);
SetLength(buf, size);
ReadFile(h, buf[0], size, read, nil);
CloseHandle(h);
Memo1.Lines.Add(pansichar(buf));
end;
Hope this'd help...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With