Reputation: 345
When I execute this code without runtime packages, I have a 32 code error, that is correct. But when I activite runtime packages (for exemple just with "FireDACASADriver;YmagControlDB") the error code is always "0"
procedure TForm1.Button1Click(Sender: TObject);
Var
Stream: TStream;
iError : integer;
begin
Stream := nil;
iError := -1;
try
try
Stream := TFileStream.Create('d:\toto.docx', fmOpenRead);
except
begin
iError := GetLastError;
end;
end;
finally
if Assigned(Stream) then
Stream.Free;
end;
showmessage('Erreur : ' + inttostr(iError));
end;
How I can fix the GetLastError with runtime packages ?
Upvotes: 0
Views: 385
Reputation: 598319
The act of raising an exception can reset the calling thread's error code. It is simply not appropriate to call GetLastError()
inside an exception handler.
That being said, if TFileStream
fails to open the file, an exception is raised that contains a system-provided error message (but not the actual error code), eg:
procedure TForm1.Button1Click(Sender: TObject);
var
Stream: TStream;
begin
try
Stream := TFileStream.Create('d:\toto.docx', fmOpenRead);
try
// use Stream as needed
finally
Stream.Free;
end;
except
on E: Exception do
ShowMessage('Erreur : ' + E.Message);
end;
end;
If you need access to the error code, you can't use TFileStream
, you will have to use CreateFile()
directly instead:
procedure TForm1.Button1Click(Sender: TObject);
var
hFile: THandle;
iError: DWORD;
begin
hFile := CreateFile('d:\toto.docx', GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
if hFile <> INVALID_HANDLE_VALUE then
begin
try
// use hFile as needed...
//
// if you need to access the file as a TStream, you can
// instantiate a THandleStream passing hFile to its constructor...
//
finally
CloseHandle(hFile);
end;
end else
begin
iError := GetLastError;
ShowMessage('Erreur : ' + IntToStr(iError));
if iError = ERROR_SHARING_VIOLATION then
begin
// do something...
end;
end;
end;
Alternatively:
procedure TForm1.Button1Click(Sender: TObject);
var
hFile: THandle;
begin
hFile := CreateFile('d:\toto.docx', GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);
try
Win32Check(hFile <> INVALID_HANDLE_VALUE);
try
// use hFile as needed...
finally
CloseHandle(hFile);
end;
except
on E: EOSError do
begin
ShowMessage('Erreur : ' + IntToStr(E.ErrorCode));
if E.ErrorCode = ERROR_SHARING_VIOLATION then
begin
// do something...
end;
end;
end;
end;
Upvotes: 1
Reputation: 613572
It is simply not appropriate to call GetLastError
there. You are mixing two different error handling models.
Call GetLastError
immediately after an API call fails, if the documentation says to do so. When you call it, something other function could very well have called SetLastError
and reset the value.
So it is wrong to call GetLastError
since you aren't using Win32 functions, and should remove the call to GetLastError
. Your code should be:
procedure TForm1.Button1Click(Sender: TObject);
var
Stream: TStream;
begin
Stream := TFileStream.Create('d:\toto.docx', fmOpenRead);
try
// ....
finally
Stream.Free;
end;
end;
If there is an error, an exception will be raised which will be reported by the top level exception handler.
Runtime packages should have no bearing on how this code executes.
Possible causes of an error are that the file does not exist, or that it is locked.
You wrote:
if Assigned(Stream) then
Stream.Free;
That is always pointless since the Free
method also checks for the object reference being nil
. In fact your code is equivalent to:
if Assigned(Stream) then
if Assigned(Stream) then
Stream.Destroy;
So it is cleaner to rely on test inside Free
and simply write:
Stream.Free;
In the comments you state that you actually want to test whether or not the file is locked. Don't use a file stream for that. Instead do the following:
CreateFile
to open the file. INVALID_HANDLE_VALUE
to detect error. GetLastError
to find out the cause of error. CloseHandle
. However, this is not to be recommended. You might use this approach to determine that the file is not locked, but by the time you try to read it, it has been locked. There is an inherent race condition.
As a general guideline it is better to ask forgiveness than permission.
Upvotes: 5