Delphi 为什么GetLastError在程序开始之前有错误?

Delphi 为什么GetLastError在程序开始之前有错误?,delphi,winapi,error-handling,delphi-xe8,Delphi,Winapi,Error Handling,Delphi Xe8,在调用Windows API函数包装器(如ExtractShortPathName后使用GetLastError时,我注意到GetLastError返回一个非零错误代码,无论调用ExtractShortPathName成功与否。事实上,在我的程序执行之前似乎有一个“最后的错误”,例如 program TestGetLastError; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; var ErrorCode: Integer

在调用Windows API函数包装器(如
ExtractShortPathName
后使用
GetLastError
时,我注意到
GetLastError
返回一个非零错误代码,无论调用
ExtractShortPathName
成功与否。事实上,在我的程序执行之前似乎有一个“最后的错误”,例如

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.
我是误解了什么还是做错了什么

如果Delphi运行时执行的操作导致设置了
GetLastError
,那么在我的程序开始执行之前,清除该错误的正确方法是什么?我应该使用
SetLastError(ERROR\u SUCCESS)与Delphi API文档中的示例类似:

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;
过程TForm2.btRaiseLastClick(发送方:TObject);
开始
{将上一个操作系统错误设置为伪值。}
System.SetLastError(错误\访问被拒绝);
尝试
RAISELASTERROR();
除了
关于Ex:EOS错误
MessageDlg('捕获到一个操作系统错误,代码为:'+IntToStr(例如ErrorCode),mtError[mbOK],0);
结束;
{让Delphi异常对话框出现。}
RAISELASTERROR(错误\u内存不足);
{最后将最后一个错误设置为无。}
System.SetLastError(错误\成功);
如果GetLastError()错误\u成功,则
MessageDlg(‘哎呀,同时出了点问题!’,mtError[mbOK],0);
{不应在此处引发异常,因为最后一个操作系统错误是“error\u SUCCESS”。}
CheckOSError(GetLastError());
结束;

只有在Windows API调用失败后,并且该函数的文档指定通过调用
GetLastError()
可以获得扩展错误信息时,
GetLastError()返回的值才与此相关

在该上下文之外调用它将返回以前调用的内容,可能来自您的代码、Delphi运行时、您调用的DLL,甚至是Windows API中的某些内容

正如
GetLastError()
的Windows API文档所述:

当发生错误时,应立即调用GetLastError函数 函数的返回值表示这样的调用将返回有用的 数据

的文档表明,只有在以下情况下才可用:

  • API调用失败,并且
  • 失败的函数表示可以使用GetLastError获取有关原因的更多信息。 从该文档(强调我的
返回值是调用线程的最后一个错误代码

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


这表明在没有先记录函数中出现故障的情况下调用它以将其设置为失败是毫无意义的。除非您知道发生了错误,并且只有在您调用的特定函数指示它失败后才调用GetLastError,否则无法调用GetLastError

除非出现故障,否则不要调用GetLastError。这没有意义,我有完全相同的结果。有趣的是,当我从uses子句中删除
SysUtils
(以及所有需要它的内容)时,我会得到错误代码
50
请求不受支持。
)。但是@Jonathan是对的,除非实际发生了错误,否则没有理由调用
GetLastError
。想象一下10分钟前在一个完全不同的窗口中发生的错误。然后,无论出于何种原因,您调用
GetLastError
,从而返回10分钟前的相同代码。API文档表明,只有在以下情况下GetLastError才可用:a)API调用失败,b)失败的函数表示可以使用GetLastError了解更多有关原因的信息。在一个记录在案的函数中,随机调用它或在没有失败的情况下调用它,以将其设置为失败,这是毫无意义的。除非您知道发生了错误,并且只有在您调用的特定函数表明它失败后才调用GetLastError。那么,我是误解了什么还是做错了什么?两者都是。:-)@KendallLister
ExtractShortPathName
不是Windows API调用,它内置于Delphi SysUtils中,Delphi SysUtils反过来调用
GetShortPathName
,这是一个API调用:)
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;