2012-01-24 16 views
4

我的代码被编译为Windows DLL与Visual C++。我想在调用terminate()时记录罕见情况,因此我在库初始化函数中设置了terminate()处理程序,后者在使用我的库之前由用户代码调用。我的处理程序写入日志并调用abort()来模拟默认的terminate()行为。如何检测是否安装了自定义的terminate()处理程序?

问题是用户代码也可能用C++编写,并使用相同的C++运行时版本,因此与我的库共享terminate()处理程序。该代码可能还希望更改terminate()处理程序以进行日志记录。所以他们会打电话set_terminate(),然后加载并初始化我的库,我的库也会调用set_terminate()并覆盖它们的terminate()处理程序,这对他们来说很难检测到,因为terminate()处理程序是他们将要测试的最后一个东西。

所以我想要以下内容。在库初始化函数中,我将retrieve the current terminate() handler,找到它是否是一个标准的,然后如果它碰巧是一个非标准的函数,我将存储它的地址,稍后(如果需要)我的terminate()处理程序将写入日志,然后将呼叫转移到该自定义terminate()处理程序。

是否有可能找到当前安装的terminate()处理程序是默认还是自定义程序?

+3

如果你打算反正调用'abort',为什么不总是链接到前一个终止处理程序而不是调用'abort'? –

+0

FWIW,我不认为链接以前的终止处理程序是一个好主意。如果程序死于代码中,请调用您的处理程序,如果在主机代码中,则调用主机处理程序。请参阅下面我的RAII答案以了解如何实现此目的。 – Ben

回答

0

MSDN隐约说

如果没有以前的功能设置,(的set_terminate)的返回值可以用来恢复默认的行为;这个值可能是NULL;

_get_terminate相同。我发现它并不真正有用,因为如果返回的值不是NULL,仍然不能保证它是有效的terminate处理程序。一种可能的解决方案是使用GetModuleHandleExGET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS来确定set_terminate返回的地址是否是任何模块中的有效地址。

+0

我认为我们可以假设,如果_get_terminate为null,则不存在预先存在的终止处理程序。 – Ben

+0

当然,但我们可以假设相反的,即指向有效处理程序的非空结果吗?我不太善于用英语来说明,但他们说没有处理程序的情况下返回的值可能是“NULL”。这是否意味着它“可能”有一些特殊的非NULL值? –

+0

它表示您可以通过调用'set_terminate'来恢复以前的行为,并返回之前调用'set_terminate'的返回值。这并不排除可能是特殊情况的“特殊”返回值(例如0xffffffff)。但只要你把它当作不透明就没有问题。不知道他为什么想连锁前一个,但我不认为这是一个好主意。 – Ben

2

通过RAII做这样的:

class terminate_scope 
{ 
public: 
    terminate_function _prev; 
    terminate_scope(terminate_function f = NULL){ 
    _prev = set_terminate(f); 
    } 
    ~terminate_scope(){ 
    set_terminate(_prev); 
    } 
}; 

要使用:

void MyFunctionWantsOwnTerminateHandler(){ 
    terminate_scope termhandler(&OwnTerminateHandler); 
    // terminate handler now set 
    // All my code will use that terminate handler 
    // On end of scope, previous terminate handler will be restored automatically 
} 

你可以有终止处理程序链上一个,如果你有绝对的把握,你需要。

+0

+1优秀,干净的解决方案。 –

相关问题