如何在DLL中创建全局异常处理程序?

时间:2011-06-06 01:02:44

标签: delphi delphi-xe

我正在使用DLL,它有时会引发未处理的异常。我使用madExcept来检测和调试有缺陷的代码,但是当我最终部署我的DLL时,我希望在DLL中包含我自己的全局异常处理程序来记录异常。

所以问题是如何在我的Delphi DLL中设置全局异常处理程序?

2 个答案:

答案 0 :(得分:10)

“全局异常处理程序”的概念在DLL中并不像VCL中存在的那样存在。要理解原因,请记住异常通过展开堆栈来传播,直到找到处理程序。 VCL可以安装一个全局异常处理程序,因为在VCL应用程序中,发生的所有事情(不包括启动和关闭)都会在调用堆栈中的某处出现TApplication.Run,这就是它放置异常处理程序的地方。由于你的DLL没有这样的单一中心点,你不能这样做。

你可以做的是在你的DLL中的某个地方设置一个“中央异常处理程序例程”。它应该将Exception对象作为参数。然后对所有导出的例程执行类似的操作:

procedure MyExportedRoutine(param: integer);
begin
  try
    //do normal stuff
  except
    on E: Exception do
      CentralExeptionHandler(E);
  end;
end;

除非你使用COM,否则这是你能做的最好的事情。如果您正在编写COM DLL,请使用safecall调用约定标记您的接口方法,编译器将为您静默生成负责异常传播的代码。

答案 1 :(得分:10)

“全局异常处理程序”究竟是什么意思?

Windows结构化异常处理(SEH),32位,通过遍历发生异常的线程的异常处理程序链来查找处理程序。异常处理程序链是一个链接的记录列表,其头部位于FS:[0];记录通常在堆栈上分配,每隔try按下一次,并在退出受保护块时弹出。每个异常记录都有一个回调例程; Windows在其搜索阶段调用此例程以及异常的详细信息,以确定链的这个“级别”是否将“处理”异常。 Windows然后通过再次遍历异常链将调用堆栈展开到该点,使用不同的值调用每个回调,让它知道展开正在进行,直到它到达选择处理异常的处理程序。如果没有找到处理程序,则该过程很难终止,无需通知。通常这不会发生;操作系统在堆栈底部(链中的最后一个元素)安装自己的最后机会处理程序,这通常会弹出熟悉的Windows“此程序遇到问题”对话框。但是如果事情已经变得非常腐败,或者异常处理程序链已经被删除了,那么这个过程会很难实现。

因此,从这个简短的Windows异常处理概述中,应该清楚的是没有单一的“全局”处理程序,只有一个处理程序列表,每个线程一个列表(FS寄存器是线程上下文的一部分);并且“最后机会”处理程序是最早安装在堆栈中的处理程序。捕获DLL中发生的异常的最简单方法是在每个入口点立即安装异常处理程序。有关如何执行此操作的详细信息,请参阅梅森的答案(与try / except一致);但要注意,如果你的DLL回调到其他地方(例如通过回调例程),那么你可能会捕获那些并非“意味着”的异常,而不是由你的代码引起的异常。 (期望异常通过DLL级别的第三方代码进行传播是不好的方式,但它可能会发生。)