【问题标题】:Delphi GetLastError with execute packagesDelphi GetLastError 与执行包
【发布时间】:2016-07-29 07:52:08
【问题描述】:

当我在没有运行时包的情况下执行此代码时,出现 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?

【问题讨论】:

    标签: delphi winapi delphi-xe6 getlasterror


    【解决方案1】:

    在那里打电话给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;
    

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

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

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

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

    【讨论】:

    • 好的,但我编写此代码是为了检测锁定的文档。没有 runtimepackge 的 getLastError 的代码为 32。检测文件被锁定的最佳方法是什么?
    【解决方案2】:

    引发异常的行为可以重置调用线程的错误代码。在异常处理程序中调用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;
    

    【讨论】:

      猜你喜欢
      • 2013-07-28
      • 2023-03-22
      • 1970-01-01
      • 2010-09-14
      • 2014-06-18
      • 2013-02-11
      • 2010-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多