2012-01-24 1 views
4

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

Проблема заключается в том, что код пользователя также может быть написан на C++ и использовать ту же самую версию исполнения на C++ и, таким образом, совместно использовать обработчик terminate() с моей библиотекой. Этот код может также захотеть изменить обработчик 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. Одним из возможных решений является использование GetModuleHandleEx с GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, чтобы узнать, является ли адрес, возвращаемый set_terminate, действительным адресом в любом модуле.

+0

Я думаю, мы можем предположить, что если _get_terminate имеет значение null, ранее не существует обработчика завершения. – Ben

+0

Несомненно, но можем ли мы принять обратное, то есть непустой результат, указывающий на действительный обработчик? Я не так хорош на английском, чтобы точно сказать, но они говорят, что возвращаемое значение для случая без обработчика «может быть» NULL. Означает ли это, что это может быть «какое-то специальное значение, отличное от NULL»? –

+0

В нем говорится, что вы можете восстановить предыдущее поведение с помощью callilng '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 отлично, чистое решение. –