Вызывается ли DllGetClassObject до или после статической инициализации C ++ - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть DLL, которая загружается в консоль управления (MMC).Кажется, что ее функция DllGetClassObject вызывает некоторую функцию инициализации сторонней библиотеки, которая, как известно, зависит от завершения статической инициализации (поэтому ее нельзя вызывать до main() в обычной программе на C ++).Эта функция, похоже, не работает, а оснастка не отображается в MMC.Как ни странно, он успешно загружается, если я удаляю его из MMC и добавляю снова.

Информация о том, когда именно статическая инициализация C ++ происходит в DLL (до и после которой обратный вызов), кажется разреженной, и Microsoft, похоже,удалил свою статью «DLL Best Practices», на которую ссылаются во многих ответах и ​​статьях, касающихся таких проблем.

Есть ли где-нибудь авторитетная информация (предпочтительно в MSDN) о порядке статической инициализации C ++ и DLLобратные вызовы?

(я уже пробовал https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-dllgetclassobject,, где я ожидал, что это будет задокументировано)

РЕДАКТИРОВАТЬ: перемещение проблемного вызова функции из DllGetClassObject в DllMain кажетсярешать проблему.Тем не менее, все еще ищите достоверную документацию.

РЕДАКТИРОВАТЬ: Исходя из этого результата и ответов, проблемы, с которыми я столкнулся при использовании сторонней функции инициализации, не могли быть вызваны статической инициализацией, поскольку предполагается, что статическая инициализациязакончено до DllMain и, следовательно, до DllGetClassObject.

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Не потворствуя или избегая использования объектов C ++ в качестве глобальных переменных / статики в вашей DLL, вот информация, которую вы ищете.Порядок операций:

  1. C / C ++ глобальная / статическая инициализация
  2. DllMain
  3. DllGetClassObject

документация здесь описывает взаимосвязь между глобальной / статической инициализацией C / C ++ и DllMain.

... При связывании с DLL код VCRuntime предоставляет внутреннюю запись DLL-точечная функция с именем _DllMainCRTStartup, которая обрабатывает сообщения ОС Windows в DLL для присоединения или отсоединения от процесса или потока.Функция _DllMainCRTStartup выполняет важные задачи, такие как настройка безопасности стекового буфера, инициализация и завершение C-библиотеки времени выполнения (CRT) и вызовы конструкторов и деструкторов для статических и глобальных объектов ._DllMainCRTStartup также вызывает функции подключения для других библиотек, таких как WinRT, MFC и ATL, для выполнения их собственной инициализации и завершения.Без этой инициализации CRT и другие библиотеки, а также ваши статические переменные остались бы в неинициализированном состоянии ...

... При подключении к процессу функция _DllMainCRTStartup устанавливает проверки безопасности буфераинициализирует CRT и другие библиотеки, инициализирует информацию о типе времени выполнения, инициализирует и вызывает конструкторы для статических и нелокальных данных , инициализирует локальное хранилище потока, увеличивает внутренний статический счетчик для каждого присоединения и *Затем 1029 * вызывает пользовательского или библиотечного DllMain ...

Вы можете увидеть все это самостоятельно, установив точку останова в вашем DllMain, а затем посмотрев на стеккадры, которые приводят к вызову DllMain.Вы обнаружите, что много интересного сделано еще до того, как ваш DllMain даже вызван.

Что касается DllGetClassObject: эта экспортированная функция не вызывается магией.Вызывающий эту функцию должен сделать 3 вещи - загрузить вашу DLL (например, LoadLibrary), найти адрес функции, загруженной из DLL (например, GetProcAddress), а затем вызвать этот адрес, используя известную сигнатурудля DllGetClassObject реализаций.Вы можете делать все это вручную, но такие функции, как CoCreateInstance, автоматически выполняют эти три действия в порядке, описанном здесь.DllMain вызывается автоматически при вызове LoadLibrary, а LoadLibrary не возвращается до тех пор, пока не вернется DllMain.Если DllMain возвращает код успеха, то вызывающий LoadLibrary получит HMODULE для DLL.Если DllMain возвращает код ошибки, у вызывающего абонента никогда не будет HMODULE для DLL (LoadLibrary вернет NULL), и, следовательно, вызывающий не сможет даже найти вашу функцию DllGetClassObject, тем более вызвать ее.

0 голосов
/ 15 февраля 2019

РЕДАКТИРОВАТЬ: не делать ничего"интересного" в DllGetClassObject или DllMain.Если вы можете, назовите свой код инициализации «по требованию» или на более позднем этапе.Делать что-либо в обратных вызовах следует только в крайнем случае (но, скорее всего, это вызовет проблемы, которые вы могли не заметить во время первого тестирования).

После прочтения некоторых материалов, предложенных в комментариях, я пришел к выводу, что

  1. Нет достоверной информации.Что касается Microsoft, то C ++ и DLL не существуют в одной и той же вселенной.

  2. Любая неавторизованная информация (например, https://blogs.msdn.microsoft.com/oldnewthing/20040127-00/?p=40873/) предполагает, что вся проблемаC ++ и DLL - полный беспорядок, и что трудно рекомендовать какие-либо общие рекомендации.

В моей конкретной ситуации (Native DLL загружается как оснастка MMC), казалось,чтобы помочь просто переместить «проблемный» код в DllMain. Однако позже выяснилось, что это вызывает проблемы (взаимоблокировку) при выходе из процесса.

...