Я только что добавил проект C++ Windows DLL в решение Visual Studio (2022). Волшебник поставил DllMain
там. Это бросилось мне в глаза; Я не помню, чтобы в других моих DLL были функции DllMain
;
При поиске в моем коде оказалось, что ни одна из моих 9 DLL не имеет функций DllMain. Тем не менее, все они строятся и работают нормально. Я проверил настройки проекта для всех этих проектов:
/NOENTRY
./SUBSYSTEM:WINDOWS
набор./NODEFAULTLIB
.Поэтому я закомментировал этот DllMain в новом проекте, который я только что добавил. До сих пор нормально строится.
Мои знания явно устарели. Я думал, что DllMain
раньше требовалось. Я помню, как много лет назад у меня возникали ошибки компоновщика в моих библиотеках DLL, когда я не мог добавить DllMain
.
Итак, мои вопросы:
(Обратите внимание, что все эти библиотеки DLL экспортируют классы C++. Ни одна из них не является ресурсной библиотекой DLL. Все работают нормально в течение 6 лет. Некоторые из них используют локальное хранилище потока. Некоторые из них имеют статические переменные внутри функций. Я всегда думал, что использование такие вещи требовали DllMain)
Библиотека времени выполнения («CRT» = библиотека времени выполнения C/C++) предоставляет точку входа настоящий DLL _DllMainCRTStartup
, которая делает такие вещи, как инициализация глобальных переменных перед вызовом вашего DllMain
. В MSDN есть документация, которая описывает это:
Также актуальна документация опции компоновщика /ENTRY
:
Существует также предоставляемый библиотекой слабый символ для вашего DllMain
, поэтому вызов из реальной точки входа в DllMain
не завершается ошибкой во время компоновки с неразрешенным внешним. Из первого документа выше:
By default, if you do not provide a
DllMain
function, Visual Studio provides one for you and links it in so that_DllMainCRTStartup
always has something to call.
Упомянутые вами вещи, такие как локальное хранилище потока, требуют использования точки входа, предоставляемой библиотекой; они сломаются, если вы используете опцию /ENTRY
для link.exe, чтобы заменить точку входа в библиотеку своей собственной, или /NOENTRY
, чтобы отключить ее. Ни один из них не требует каких-либо действий со стороны DllMain
, которую вызывает точка входа в библиотеку.
@Joe: Написание собственного DllMain
никогда не было необходимо, если поведение, предоставляемое библиотекой, было достаточно хорошим.
Хорошо, тогда весь этот вопрос был важным моментом. Спасибо, что нашли время ответить
@Joe: Я думаю, вы, возможно, помните поведение, связанное с файлом .DEF, который мастера использовали для создания (до того, как существовала система __declspec(dllexport)
, там должен был быть указан экспорт). Если вы удалите какие-либо функции, созданные мастером (например, DllCanUnloadNow
или DllRegisterServer
) из исходного кода C/C++, но не удалите их из файла .DEF, вы получите ошибки ссылок.
Итак, если я помню, что мне нужно определить DllMain, чтобы заставить DLL работать, это просто плохая память с моей стороны? Я мог бы поклясться, что так оно и было. Но я не возился с DllMain почти 20 лет.