0

当我在没有运行时包的情况下执行此代码时,我有一个 32 代码错误,这是正确的。但是当我激活运行时包(例如,仅使用“FireDACASADriver;YmagControlDB”)时,错误代码始终为“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;

如何使用运行时包修复 GetLastError?

4

2 回答 2

4

GetLastError打电话给那里根本不合适。您正在混合两种不同的错误处理模型。

如果文档要求,在 API调用GetLastError失败后立即调用。当您调用它时,其他函数很可能会调用SetLastError并重置该值。

所以调用是错误的,GetLastError因为你没有使用 Win32 函数,应该删除对GetLastError. 您的代码应该是:

procedure TForm1.Button1Click(Sender: TObject);
var
  Stream: TStream;
begin
  Stream := TFileStream.Create('d:\toto.docx', fmOpenRead);
  try
    // ....    
  finally
    Stream.Free;
  end;
end;

如果出现错误,将引发异常,该异常将由顶级异常处理程序报告。

运行时包应该与此代码的执行方式无关。

错误的可能原因是该文件不存在,或者它被锁定。

你写了:

if Assigned(Stream) then
  Stream.Free;

这总是毫无意义的,因为该Free方法还会检查对象引用是否为nil. 实际上,您的代码等效于:

if Assigned(Stream) then
  if Assigned(Stream) then
    Stream.Destroy;

因此,依靠内部的测试Free并简单地编写:

Stream.Free;

在评论中,您声明您实际上想要测试文件是否被锁定。不要为此使用文件流。而是执行以下操作:

  • 调用CreateFile打开文件。
  • 检查返回的句柄INVALID_HANDLE_VALUE以检测错误。
  • 如果出现错误GetLastError,请找出错误原因。
  • 否则用 关闭手柄CloseHandle

但是,不建议这样做。您可能会使用这种方法来确定文件未锁定,但当您尝试读取它时,它已被锁定。有一个固有的竞争条件。

作为一般准则,请求宽恕比许可更好。

于 2016-04-08T06:46:48.043 回答
0

引发异常的行为可以重置调用线程的错误代码。GetLastError()在异常处理程序内部调用根本不合适。

话虽如此,如果TFileStream无法打开文件,则会引发异常,其中包含系统提供的错误消息(但不是实际的错误代码),例如:

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;

如果您需要访问错误代码,则不能使用TFileStream,您必须CreateFile()直接使用:

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;

或者:

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;
于 2016-04-08T22:46:26.120 回答