为什么我的程序开始之前GetLastError就出错了?

3

在使用像 ExtractShortPathName 这样的 Windows API 函数包装器后调用 GetLastError,我注意到无论调用 ExtractShortPathName 成功或失败,GetLastError 都返回一个非零错误代码。实际上,在我的程序执行之前似乎已经存在一个“上一个错误”,例如:

program TestGetLastError;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

var
  ErrorCode: Integer;

begin
  try
    ErrorCode := GetLastError;
    if ErrorCode <> 0 then
      RaiseLastOSError;
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;
end.

结果是:

EOSError: System Error.  Code: 122.
The data area passed to a system call is too small

我是否有什么误解或做错了什么?

如果Delphi运行时执行某些操作导致设置了GetLastError,那么在程序开始执行之前清除该错误的正确方法是什么?我应该像Delphi API文档中的示例一样使用SetLastError(ERROR_SUCCESS);吗?

procedure TForm2.btRaiseLastClick(Sender: TObject);
begin
  { Set the last OS error to a bogus value. }
  System.SetLastError(ERROR_ACCESS_DENIED);

  try
    RaiseLastOSError();
  except
    on Ex : EOSError do
      MessageDlg('Caught an OS error with code: ' + IntToStr(Ex.ErrorCode), mtError, [mbOK], 0);
  end;

  { Let the Delphi Exception dialog appear. }
  RaiseLastOSError(ERROR_NOT_ENOUGH_MEMORY);

  { Finally set the last error to none. }
  System.SetLastError(ERROR_SUCCESS);

  if GetLastError() <> ERROR_SUCCESS then
    MessageDlg('Whoops, something went wrong in the mean time!', mtError, [mbOK], 0);

  { No exception should be thrown here because last OS error is "ERROR_SUCCESS". }
  CheckOSError(GetLastError());
end;

http://docwiki.embarcadero.com/CodeExamples/Tokyo/en/LastOSError_(Delphi)


5
只有在出现问题时才调用GetLastError函数,否则没有意义。 - Jonathan Potter
1
我得到了完全相同的结果。有趣的是,当我从使用条款中删除SysUtils(以及所有需要它的内容)时,我会得到错误代码50(请求不受支持)。但是@Jonathan是正确的,除非实际发生了错误,否则没有理由调用GetLastError。想象一下,在完全不同的窗口中发生了10分钟前的错误。然后,出于某种原因,您调用GetLastError,从而返回来自10分钟前的相同代码。 - Jerry Dodge
3
API文档指出,只有在满足以下两种情况时,使用GetLastError函数才有意义:a)API调用失败;b)失败的函数指示您可以使用GetLastError获取有关失败原因的更多信息。随意调用它或在已记录会在失败时设置它的函数中没有失败的情况下调用它是没有意义的。除非您知道发生了错误且只有在调用特定函数后指示失败后才能调用GetLastError。 - Ken White
3
“我是否有什么误解或做错了什么?”的答案是“两者都有”,笑脸。 - Ken White
2
@KendallLister ExtractShortPathName不是Windows API调用,而是内置于Delphi SysUtils中的函数,其又调用了GetShortPathName API :) - Jerry Dodge
显示剩余6条评论
2个回答

13
GetLastError()函数返回的值仅在Windows API调用失败且该函数的文档指定通过调用GetLastError()可获取扩展错误信息时才相关。
在此上下文之外调用它将返回先前调用的某些内容,可能是您的代码、Delphi运行时、已调用的DLL甚至是Windows API中的任何东西...
正如Windows API文档中对GetLastError()所述:

当函数的返回值表明此类调用将返回有用数据时,应立即调用GetLastError函数。


4

GetLastError的文档表明,它只在以下情况下有用:

  • API调用失败,并且
  • 失败的函数指示您可以使用GetLastError获取更多关于失败原因的信息。 从该文档中(我强调

返回值是调用线程的最后一个错误代码。

每个设置最后一个错误代码的函数的文档的返回值部分都记录了函数设置最后一个错误代码的条件。大多数设置线程最后一个错误代码的函数会在它们失败时设置它。但是,一些函数也会在成功时设置最后一个错误代码。如果未记录函数设置最后一个错误代码,则此函数返回的值仅为最近设置的最后一个错误代码;某些函数在成功时将最后一个错误代码设置为0,而其他函数则不会。

这表明,在没有已记录的函数失败的情况下调用它是没有意义的。除非您知道发生了错误,否则无法调用GetLastError,并且只有在调用特定函数失败后才能调用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接