为什么GetLastError在DLL库中调用时返回0?

TLa*_*ama 6 delphi delphi-2009

假设我有一个带有这个伪代码的DLL库:

var
  LastError: DWORD;

procedure DoSomethingWrong; stdcall;
var
  FileStream: TFileStream;
begin
  try
    FileStream := TFileStream.Create('?', fmCreate);
  except
    on EFCreateError do
      LastError := GetLastError; // <- why does GetLastError return 0 here ?
  end;
end;
Run Code Online (Sandbox Code Playgroud)

为什么GetLastError函数在如上所示的DLL库中使用时返回0?有没有办法获得此案例的最后一个错误代码?

Dav*_*nan 10

您对GetLastError返回的调用,0因为返回后调用了其他API CreateFile,并且您的异常代码将执行.

GetLastError线程局部变量返回的错误代码,在线程中运行的所有代码之间共享.因此,为了捕获错误代码,您需要GetLastError在失败的函数返回后立即调用.

文件解释它是这样的:

调用线程执行的函数通过调用SetLastError函数来设置该值 .当函数的返回值指示此类调用将返回有用数据时,应立即调用GetLastError函数.这是因为一些函数在成功时调用 SetLastError为零,消除了最近失败的函数设置的错误代码.

如果您正在使用,TFileStream.Create那么框架不会让您有机会GetLastError在适当的时候致电.如果你真的想获得这些信息,你必须CreateFile自己打电话,THandleStream而不是使用TFileStream.

有这个想法,THandleStream你负责合成传递给构造函数的文件句柄THandleStream.这使您有机会在发生故障时捕获错误代码.

  • 我不认为雷米报告的错误是一个错误.我认为期待RTL长期保留最后一个错误是不公平的.我可能会确保将错误代码放入引发的异常字段中.如果框架会调用RaiseLastOSError,那就会发生.可悲的是,它没有使用EOSError. (5认同)
  • @TLama - 这并不意味着什么,它不是设置最后一个错误的RTL.您想知道的是我在评论中提到的作为对RTL错误持怀疑态度的理由.简单的事实是,RTL从不显式调用SetLastError.它纯粹是操作系统中的一个实现细节,当在dll中调用FormatMessage时,一些转到IsProcessorFeaturePresent的代码路径会导致SetLastError调用. (5认同)
  • @TLama - 没有.大卫的回答是正确答案.TFileStream类是一个抽象,它不保证保留最后一个错误或任何东西.实际上,它使用最后一个错误来使用适当的消息引发异常.除了我想知道RTL如何重置错误,它所做的只是用最后一个错误值调用FormatMessage.如果确实有错误,我想知道为什么可执行文件和库的行为会有所不同? (3认同)
  • 这实际上是由我在2004年向QC报告的RTL中的一个错误引起的([QC#8680](http://qc.embarcadero.com/wc/qcmain.aspx?d=8680))并关闭为在2010年修复. (2认同)
  • @TLama - 我同意David的观点,此外,Remy的报告并未说明重置上一次错误的原因. (2认同)