DLL的std :: set_terminate吗?

Tys*_*son 2 c++ dll winapi try-catch

我有一个将由另一个第三方应用程序加载的DLL。

我试图找出是否有可能捕获到我自己的DLL生成的任何/所有异常。

如果我负责应用程序的代码,则可以在main()中使用std :: set_terminate来设置一个包罗万象的错误处理函数。但是由于我的DLL将位于其他人的应用程序中,因此无法在main()中调用std :: set_terminate。

有没有办法让我创建一个仅应用我自己的代码的覆盖,而又不做麻烦的工作,例如将我的应用程序的每个功能都放在try / catch块之内?

Cod*_*ray 5

设计DLL时,应确保切勿让异常从入口点逸出。如果跨模块边界正常工作,那么跨模块边界的异常将变得棘手,而您最好避免它们。

引用C ++编码标准: Herb Sutter和Andrei Alexandrescu的101条规则,指南和最佳实践

条款62:不允许异常跨越模块边界传播。

不要扔石头到邻居的花园:C ++异常处理没有通用的二进制标准。除非您控制用于构建双方的编译器和编译器选项,否则不允许在两段代码之间传播异常。否则,这些模块可能不支持用于异常传播的兼容实现。通常,这可以归结为:不要让异常跨越模块/子系统边界传播。

当您处理DLL(而不是静态库)时,您没有任何保证。占用您的DLL的第三方应用程序是外部模块(邻居的花园)。您无法保证这两个模块将使用相同的编译器和编译器选项进行编译,因此您不知道它们是否将以相同的方式对待异常。实际上,您甚至都不知道两个模块是否都将用C ++编写,因此让C ++异常传播是正确的。您可以通过多种方法使用Windows的结构化异常处理(SEH)在模块边界之间成功传播异常,但您不应该这样做。

但是,除了技术和实现方面的问题外,从DLL抛出异常只会创建一个错误的接口。客户端应用程序不必处理DLL例程中的异常。例外是实现细节:您应该在内部处理它们。如果您需要指示成功或失败,请返回错误代码。可以使用任何可能消耗您的DLL的语言(从C到BASIC到Python)来轻松地处理这些问题。

建议的解决方案是基本上挂接一个全局的,未处理的异常处理程序,该异常处理程序将在DLL 跨越模块边界之前捕获DLL引发的所有异常。那真的不存在。DLL没有全局异常处理程序。异常通过展开(遍历)调用堆栈(直到找到合适的处理程序)来传播。如果没有处理程序,它们将一直传播到入口点(main),如果没有处理程序,它们将导致应用程序终止,并且操作系统将显示一个“友好”对话框。这就是为什么在应用程序中轻松安装未处理的异常处理程序的原因。DLL没有这样的等效项,因为DLL没有自己的单个集中式main功能。相反,它具有一系列入口点:客户端应用程序调用的导出函数。因此,您未处理的异常处理程序应位于这些入口点中。

每个入口点都有自己的异常处理程序。如果需要,您基本上可以将整个入口点包装在一个大的try-catch中。这样,您所有的内部实现函数都可以抛出异常而肆无忌a地抛出异常,但是在允许它们传播到模块外部之前,它们都会被困在入口点中。

将DLL提供的每个入口点(导出的函数)都视为其自己的main函数,因为基本上就是它的本质。该DllMain功能(因为它是传统的Windows已知的)是完全不同的。在允许您在那里执行的操作方面,您受到了如此严格的限制,以至于永远不要调用可能引发异常的代码。

另外,您可能仍然不想在DLL中调用代码abortstd::terminate从其中调用代码,因为这将终止整个过程,包括客户端应用程序。当您在别人家中做客时您不应该打电话给拆迁公司摧毁他们的房屋。在内部记录您的异常,但是要尽一切努力保持一致的外部状态,而不会因为遇到内部错误而使客户端应用程序崩溃。