DLL的std :: set_terminate?

问题描述 投票:2回答:1

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

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

如果我负责应用程序的代码,我会在main()中使用std :: set_terminate来设置一个catch-all错误处理函数。但由于我的DLL将在其他人的应用程序中,我不能在main()中调用std :: set_terminate。

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

c++ winapi dll try-catch
1个回答
4
投票

在设计DLL时,您应该确保永远不会让异常从您的入口点逃脱。跨越模块边界的例外变得棘手,如果它们起作用的话,你最好避开它们。

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

第62项:不允许异常跨模块边界传播。

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

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

但是,除了技术和实现问题之外,从DLL中抛出异常只会创建一个糟糕的接口。客户端应用程序不应该处理DLL例程中的异常。例外是实现细节:您应该在内部处理它们。如果需要指示成功或失败,请返回错误代码。这些可以通过任何可能消耗你的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 houseyou shouldn't call the demolition company to have their house destroyed。在内部记录您的异常,但是只需要因为遇到内部错误而保持一致的外部状态并且不会使客户端应用程序崩溃。

© www.soinside.com 2019 - 2024. All rights reserved.