Подтвердить что ты не робот

Выяснение, закончилась ли статическая инициализация

Сокращенная проблема (Y)

Предположим, вам нужно знать, изнутри функции, была ли эта функция вызвана как часть инициализации статического объекта или нет. Существует ли стандартный или платформенный способ для этого?

История предыстории (X)

Я вкопался в исходный код DLL, который используется многими приложениями. Эта DLL предоставляет функцию Init, и эта функция должна построить boost::asio::deadline_timer, которая будет использоваться позже (но DLL может работать без нее в деградированном режиме).

Проблема заключается в том, что таймер не может быть создан во время инициализации статических объектов (время загрузки DLL), для того, чтобы его тупик конструктора.

Конечно, каждый и их кошка называет Init всюду (да, несколько раз!), включая статические конструкторы из исходного кода, которые я не буду редактировать, следовательно, необходимо обнаружить эту ситуацию и выручить.

После того, как прагматизм преодолел отвращение, я в итоге поднялся по стоп-косту, чтобы найти wWinMain и вывести, что статическая инициализация завершена. Это ужасно и не работает с динамически загруженными двоичными файлами, что, к счастью, выходит за рамки моего конкретного случая. Я уверен, что есть более чистый способ.

4b9b3361

Ответ 1

На данный момент предположим, что ваша DLL имеет две точки входа: Init и Frobnicate.

Init ничего не делает. Frobnicate проверяет глобальное логическое значение, чтобы узнать, действительно ли DLL инициализирована. Если нет, сначала выполняется реальная инициализация, которая также устанавливает флаг I've-initial-initialized, прежде чем на самом деле frobnicating.

Вероятно, у вас больше точек входа (Frobnicate2, Fronbnicate3,...), поэтому вам придется добавить эту логику в каждую из них. Это утомительно, но не неслыханно. В тот же день нам приходилось писать собственные механизмы задержки, которые были очень похожи. Конечно, мы только представляли интерфейсы C-стиля из DLL тогда, а не объекты стиля С++ с искаженными именами методов, но они все равно должны быть работоспособными.

Предполагается, что он будет нормально откладывать инициализацию до первого вызова Init в DLL. Это может быть или не быть хорошим предположением.

Другие хакерские идеи:

  • Найдите способ обнаружения блокировки загрузчика (кроме фактической блокировки). Если блокировка загрузчика удерживается при вызове Init, то это один из тех "слишком быстрых" моментов. Это находится на одном уровне с вашим решением walk-the-stack-to-find-WinMain.
  • Сделайте что-то, что гарантирует тупик, когда Init будет вызван слишком рано и заставит ваших клиентов исправить свой проклятый код.
  • Создайте скрытое окно только для сообщений и опубликуйте сообщение. Предполагая, что клиент является традиционным графическим интерфейсом, которое будет перекачивать сообщения в одном и том же потоке, то к тому моменту, когда вы получите сообщение, должно быть безопасно выполнять настоящую инициализацию (и, надеюсь, не слишком поздно).