Как определить, установлен ли пользовательский обработчик terminate ()? - PullRequest
4 голосов
/ 24 января 2012

Мой код скомпилирован как Windows DLL с Visual C ++.Я хочу регистрировать редкие случаи, когда вызывается terminate(), поэтому я установил свой обработчик terminate() в функцию инициализации библиотеки, и последний вызывается кодом пользователя перед использованием моей библиотеки.Мой обработчик пишет в журнал и вызывает abort(), имитируя поведение terminate() по умолчанию.

Проблема в том, что пользовательский код также может быть написан на C ++ и использовать ту же самую версию C ++ во время выполнения, и поэтому использовать terminate() обработчик с моей библиотекой.Этот код может также захотеть изменить обработчик terminate(), чтобы он регистрировал их.Поэтому они будут вызывать set_terminate(), затем загружать и инициализировать мою библиотеку, а моя библиотека также будет вызывать set_terminate() и переопределять их обработчик terminate(), и это будет очень трудно для них обнаружить, так как обработчик terminate() является последнимЯ думаю, они проверят.

Так что я хочу следующее.Внутри функции инициализации библиотеки я получу текущий обработчик terminate() , выясню, является ли он стандартным, затем, если он окажется нестандартным, я сохраню его адрес и позже (еслинеобходимо) мой обработчик terminate() запишет в журнал и затем перенаправит вызов этому пользовательскому обработчику terminate().

Можно ли определить, является ли установленный обработчик terminate() установленным по умолчанию, илизаказной?

Ответы [ 2 ]

2 голосов
/ 24 января 2012

Сделайте это через 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 голосов
/ 24 января 2012

MSDN смутно говорит, что

Если предыдущая функция не была установлена, возвращаемое значение (set_terminate) может использоваться для восстановления поведения по умолчанию;это значение может быть NULL;

и одинаковым для _get_terminate.Я считаю, что это не очень полезно, потому что, если возвращаемое значение не NULL, тем не менее, нет никакой гарантии, что он является действительным обработчиком terminate.Одним из возможных решений является использование GetModuleHandleEx с GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, чтобы выяснить, является ли адрес, возвращаемый set_terminate, действительным адресом в любом модуле.

...