c++ - DLL 的 std::set_terminate 吗?

标签 c++ winapi dll try-catch

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

我试图弄清楚我是否可以捕获我自己的 DLL 生成的任何/所有异常。

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

有没有一种方法可以让我创建这样一个覆盖,只应用我自己的代码,而不做一些令人讨厌的事情,比如将我的应用程序的每个函数都放在 try/catch block 或其他东西中?

最佳答案

设计 DLL 时,应确保绝不让异常从入口点逃逸。跨模块边界的异常会变得很棘手(如果它们确实有效的话),并且您最好避免它们。

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

Item 62: Don't allow exceptions to propagate across module boundaries.

Don't throw stones into your neighbor's garden: There is no ubiquitous binary standard for C++ exception handling. Don't allow exceptions to propagate between two pieces of code unless you control the compiler and compiler options used to build both sides; otherwise, the modules might not support compatible implementations for exception propagation. Typically, this boils down to: Don't let exceptions propagate across module/subsystem boundaries.

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

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

您提出的解决方案基本上是连接一个全局的、未处理的异常处理程序,该处理程序将在 DLL 抛出的任何和所有异常穿过模块边界之前捕获它们。那实际上并不存在。 DLL 没有全局异常处理程序。异常通过展开(向上遍历)调用堆栈来传播,直到找到合适的处理程序。如果没有处理程序,它们将一直传播到入口点(main),如果没有在那里处理,它们将导致应用程序终止,并且操作系统将呈现一个“友好”对话框。这就是为什么在应用程序中安装未处理的异常处理程序很容易。 DLL 没有这样的等价物,因为 DLL 没有自己的单一中央 main 函数。相反,它拥有一系列入口点:由客户端应用程序调用的导出函数。因此,您的未处理异常处理程序应该位于这些入口点中。

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

将 DLL 提供的每个入口点(导出函数)视为其自己的main 函数,因为它基本上就是这样。 DllMain 函数(Windows 上的传统名称)完全不同。您在那里可以执行的操作受到严格限制,因此您永远不应该调用可能引发异常的代码。

另外一点,您可能不希望从 DLL 中的代码调用 abortstd::terminate,因为这会终止 整个过程,包括客户端应用程序。 When you're a guest in someone else's house , you shouldn't call the demolition company to have their house destroyed 。在内部记录您的异常,但尽一切努力保持一致的外部状态,并且仅仅因为遇到内部错误而导致客户端应用程序崩溃。

关于c++ - DLL 的 std::set_terminate 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55054744/

相关文章:

c# - ILMerge 的问题

c++ - 在 Qt 项目中使用 STXXL

c++ - ldd 显示 ELF 解释器存在,但我仍然得到 "No such file or directory"

winapi - DuplicateHandle 的 DUPLICATE_CLOSE_HANDLE 标志有什么意义?

c++使用头文件和cpp文件创建类

api - SetConsoleTextAttribute 的可用颜色

c++ - 从构造函数跨 DLL 边界抛出异常

C# DLL 的插件架构

c++ - MFTEnumEx在Windows 7上找不到MFAudioFormat_MP3解码器?

python - 为什么使用 Armadillo 矩阵和 pybind11 可能会导致堆损坏?