Точка входа DllMain

Необязательная точка входа в библиотеку динамических ссылок (DLL). При запуске или завершении процесса или потока система вызывает функцию точки входа для каждой загруженной библиотеки DLL с помощью первого потока процесса. Система также вызывает функцию точки входа для библиотеки DLL при загрузке или выгрузке с помощью функций LoadLibrary и FreeLibrary .

Предупреждение

В отношении операций, выполняемых в точке входа DLL, действуют серьезные ограничения. Ознакомьтесь с общими рекомендациями по определенным api-интерфейсам Windows, которые небезопасны для вызова в DllMain. Если требуется сделать что-то помимо простейшей инициализации, сделайте это в функции инициализации для DLL. Вы можете требовать от приложений вызывать функцию инициализации после запуска DllMain и перед вызовом других функций в библиотеке DLL.

Пример

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpvReserved )  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason ) 
    { 
        case DLL_PROCESS_ATTACH:
         // Initialize once for each new process.
         // Return FALSE to fail DLL load.
            break;

        case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;

        case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;

        case DLL_PROCESS_DETACH:
        
            if (lpvReserved != nullptr)
            {
                break; // do not do cleanup if process termination scenario
            }
            
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

Это пример функции Entry-Point библиотекиDynamic-Link.

Синтаксис

BOOL WINAPI DllMain(
  _In_ HINSTANCE hinstDLL,
  _In_ DWORD     fdwReason,
  _In_ LPVOID    lpvReserved
);

Parameters

hinstDLL [in]

Дескриптор модуля DLL. Это значение является базовым адресом библиотеки DLL. HINSTANCE библиотеки DLL совпадает с HMODULE библиотеки DLL, поэтому hinstDLL можно использовать в вызовах функций, требующих дескриптора модуля.

fdwReason [in]

Код причины, указывающий, почему вызывается функция точки входа DLL. Этот параметр может быть одним из следующих значений.

Ценность Значение
DLL_PROCESS_ATTACH
1
Библиотека DLL загружается в виртуальное адресное пространство текущего процесса в результате запуска процесса или в результате вызова LoadLibrary. Библиотеки DLL могут использовать эту возможность для инициализации данных экземпляра или использования функции TlsAlloc для выделения индекса локального хранилища потока (TLS).
Параметр lpvReserved указывает, загружается ли библиотека DLL статически или динамически.
DLL_PROCESS_DETACH
0
Библиотека DLL выгружается из виртуального адресного пространства вызывающего процесса, так как она была загружена неудачно или число ссылок достигло нуля (процессы либо завершаются, либо называются FreeLibrary один раз за каждый раз, когда он называется LoadLibrary).
Параметр lpvReserved указывает, выгрузится ли библиотека DLL в результате вызова FreeLibrary , сбоя загрузки или завершения процесса.
Библиотека DLL может использовать эту возможность для вызова функции TlsFree для освобождения всех индексов TLS, выделенных с помощью TlsAlloc , и для освобождения локальных данных потока.
Обратите внимание, что поток, получающий уведомление DLL_PROCESS_DETACH , не обязательно тот же поток, который получил уведомление DLL_PROCESS_ATTACH .
DLL_THREAD_ATTACH
2
Текущий процесс создает новый поток. При этом система вызывает функцию точки входа всех библиотек DLL, подключенных к процессу. Вызов выполняется в контексте нового потока. Библиотеки DLL могут использовать эту возможность для инициализации слота TLS для потока. Поток, вызывающий функцию точки входа DLL с DLL_PROCESS_ATTACH , не вызывает функцию точки входа DLL с DLL_THREAD_ATTACH.
Обратите внимание, что функция точки входа DLL вызывается только потоками, созданными после загрузки библиотекой DLL. При загрузке библиотеки DLL с помощью LoadLibrary существующие потоки не вызывают функцию точки входа только что загруженной библиотеки DLL.
DLL_THREAD_DETACH
3
Поток завершается чисто. Если библиотека DLL сохранила указатель на выделенную память в слоте TLS, она должна использовать эту возможность для освобождения памяти. Система вызывает функцию точки входа всех загруженных библиотек DLL с этим значением. Вызов выполняется в контексте выходного потока.

lpvReserved [in]

Если fdwReasonDLL_PROCESS_ATTACH, lpvReserved имеет значение NULL для динамических загрузок и не null для статических загрузок.

Если fdwReasonDLL_PROCESS_DETACH, lpvReserved имеет значение NULL , если freeLibrary был вызван или загрузка БИБЛИОТЕКи DLL завершилась сбоем и не имеет значения NULL , если процесс завершается.

Возвращаемое значение

Когда система вызывает функцию DllMain со значением DLL_PROCESS_ATTACH , функция возвращает значение TRUE , если оно успешно или FALSE , если инициализация завершается ошибкой. Если возвращаемое значение равно FALSE при вызове DllMain, так как процесс использует функцию LoadLibrary, LoadLibrary возвращает ЗНАЧЕНИЕ NULL. (Система немедленно вызывает функцию точки входа с DLL_PROCESS_DETACH и выгрузит библиотеку DLL.) Если возвращаемое значение равно FALSE при вызове DllMain во время инициализации процесса, процесс завершается ошибкой. Чтобы получить расширенные сведения об ошибке, вызовите GetLastError.

Когда система вызывает функцию DllMain с любым значением, кроме DLL_PROCESS_ATTACH, возвращаемое значение игнорируется.

Remarks

DllMain — это заполнитель для имени определяемой библиотекой функции. Необходимо указать фактическое имя, используемое при сборке библиотеки DLL. Дополнительные сведения см. в документации, включенной в средства разработки.

Во время начального запуска процесса или после вызова LoadLibrary система проверяет список загруженных БИБЛИОТЕК DLL для процесса. Для каждой библиотеки DLL, которая еще не была вызвана значением DLL_PROCESS_ATTACH , система вызывает функцию точки входа библиотеки DLL. Этот вызов выполняется в контексте потока, вызвавшего изменение адресного пространства процесса, например основного потока процесса или потока, который называется LoadLibrary. Доступ к точке входа сериализуется системой на основе процесса. Потоки в DllMain удерживают блокировку загрузчика, поэтому дополнительные библиотеки DLL не могут быть динамически загружены или инициализированы.

Если функция точки входа библиотеки DLL возвращает false после уведомления DLL_PROCESS_ATTACH , она получает уведомление DLL_PROCESS_DETACH и библиотека DLL выгрузится немедленно. Однако если код DLL_PROCESS_ATTACH вызывает исключение, функция точки входа не получит уведомление DLL_PROCESS_DETACH .

Существуют случаи, когда функция точки входа вызывается для конца потока, даже если функция точки входа никогда не вызывалась с DLL_THREAD_ATTACH для потока:

  • Поток был начальным потоком в процессе, поэтому система называется функцией точки входа со значением DLL_PROCESS_ATTACH .
  • Поток уже выполнялся при вызове функции LoadLibrary , поэтому система никогда не вызывала функцию точки входа для нее.

Если библиотека DLL выгружается из процесса в результате неудачной загрузки библиотеки DLL, завершения процесса или вызова FreeLibrary, система не вызывает функцию точки входа библиотеки DLL со значением DLL_THREAD_DETACH для отдельных потоков процесса. Библиотека DLL отправляется только DLL_PROCESS_DETACH уведомления. Библиотеки DLL могут использовать эту возможность для очистки всех ресурсов для всех потоков, известных библиотеке DLL.

При обработке DLL_PROCESS_DETACH библиотека DLL должна освободить ресурсы, такие как память кучи, только если библиотека DLL выгрузится динамически (параметр lpvReserved имеет значение NULL). Если процесс завершается (параметр lpvReserved не null), все потоки в процессе, кроме текущего потока либо завершились уже или были явно завершены вызовом функции ExitProcess , что может оставить некоторые ресурсы процесса, такие как кучи в несогласованном состоянии. В этом случае библиотека DLL не безопасна для очистки ресурсов. Вместо этого библиотека DLL должна разрешить операционной системе освободить память.

При завершении процесса путем вызова TerminateProcess или TerminateJobObject библиотеки DLL этого процесса не получают DLL_PROCESS_DETACH уведомления. При завершении потока путем вызова TerminateThread библиотеки DLL этого потока не получают DLL_THREAD_DETACH уведомления.

Функция точки входа должна выполнять только простые задачи инициализации или завершения. Он не должен вызывать функцию LoadLibrary или LoadLibraryEx (или функцию, которая вызывает эти функции), так как это может создавать циклы зависимостей в порядке загрузки DLL. Это может привести к использованию библиотеки DLL, прежде чем система выполнила свой код инициализации. Аналогичным образом функция точки входа не должна вызывать функцию FreeLibrary (или функцию, которая вызывает FreeLibrary) во время завершения процесса, так как это может привести к использованию библиотеки DLL после выполнения системой кода завершения.

Так как Kernel32.dll гарантированно загружается в адресное пространство процесса при вызове функции точки входа, вызов функций в Kernel32.dll не приводит к использованию библиотеки DLL до выполнения кода инициализации. Поэтому функция точки входа может вызывать функции в Kernel32.dll, которые не загружают другие библиотеки DLL. Например, DllMain может создавать объекты синхронизации , такие как критические разделы и мьютексы, и использовать TLS. К сожалению, в Kernel32.dllотсутствует полный список безопасных функций.

Вызов функций, требующих библиотек DLL, отличных от Kernel32.dll, может привести к проблемам, которые сложно диагностировать. Например, вызов функций User, Shell и COM может привести к ошибкам нарушения доступа, так как некоторые функции загружают другие системные компоненты. И наоборот, вызовы таких функций, как эти во время завершения, могут привести к ошибкам нарушения доступа, так как соответствующий компонент уже был выгружен или неинициализирован.

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

Сведения о рекомендациях по написанию библиотеки DLL см. в рекомендациях по библиотеке динамического канала.

Если библиотека DLL связана с библиотекой времени выполнения C (CRT), точка входа, предоставляемая CRT, вызывает конструкторы и деструкторы для глобальных и статических объектов C++. Таким образом, эти ограничения для DllMain также применяются к конструкторам и деструкторам и любому коду, вызываемому из них.

Рассмотрите возможность вызова DisableThreadLibraryCalls при получении DLL_PROCESS_ATTACH, если библиотека DLL не связана со статической библиотекой времени выполнения C (CRT).

Требования

Требование Ценность
Минимальный поддерживаемый клиент
Windows XP [только классические приложения]
Минимальный поддерживаемый сервер
Windows Server 2003 [только классические приложения]
Header
Process.h

См. также

Функция Entry-Point библиотекиDynamic-Link

Функции библиотеки Dynamic-Link

FreeLibrary

GetModuleFileName

LoadLibrary

TlsAlloc

TlsFree

DisableThreadLibraryCalls