DllMain 진입점
DLL(동적 연결 라이브러리)에 대한 선택적 진입점입니다. 시스템이 프로세스 또는 스레드를 시작하거나 종료하면 프로세스의 첫 번째 스레드를 사용하여 로드된 각 DLL에 대한 진입점 함수를 호출합니다. 또한 시스템은 LoadLibrary 및 FreeLibrary 함수를 사용하여 로드되거나 언로드될 때 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.
}
Dynamic-Link 라이브러리 Entry-Point 함수의 예입니다.
경고
DLL 진입점에서 안전하게 수행할 수 있는 작업은 상당히 제한적입니다. DllMain에서 호출하기에 안전하지 않은 특정 Windows API에 대한 일반 모범 사례를 참조하세요. 가장 간단한 초기화가 필요한 경우가 아닌 한 DLL에 대한 초기화 함수에서 이를 수행합니다. DllMain이 실행된 후 및 DLL에서 다른 함수를 호출하기 전에 애플리케이션이 초기화 함수를 호출하도록 요구할 수 있습니다.
구문
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
매개 변수
-
hinstDLL [in]
-
DLL 모듈에 대한 핸들입니다. 값은 DLL의 기본 주소입니다. DLL의 HINSTANCE 는 DLL의 HMODULE 과 동일하므로 모듈 핸들이 필요한 함수에 대한 호출에서 hinstDLL 을 사용할 수 있습니다.
-
fdwReason [in]
-
DLL 진입점 함수가 호출되는 이유를 나타내는 이유 코드입니다. 이 매개 변수는 다음 값 중 하나일 수 있습니다.
값 의미 - DLL_PROCESS_ATTACH
- 1
DLL은 프로세스가 시작되거나 LoadLibrary 호출의 결과로 현재 프로세스의 가상 주소 공간에 로드됩니다. DLL은 이 기회를 사용하여 instance 데이터를 초기화하거나 TlsAlloc 함수를 사용하여 TLS(스레드 로컬 스토리지) 인덱스를 할당할 수 있습니다.
lpvReserved 매개 변수는 DLL이 정적으로 로드되는지 동적으로 로드되는지 여부를 나타냅니다.- DLL_PROCESS_DETACH
- 0
DLL이 성공적으로 로드되지 않았거나 참조 수가 0에 도달했기 때문에 호출 프로세스의 가상 주소 공간에서 DLL이 언로드되고 있습니다(프로세스는 LoadLibrary 라고 할 때마다 한 번 종료되거나 FreeLibrary라고 함).
lpvReserved 매개 변수는 FreeLibrary 호출, 로드 실패 또는 프로세스 종료로 인해 DLL이 언로드되는지 여부를 나타냅니다.
DLL은 이 기회를 사용하여 TlsFree 함수를 호출하여 TlsAlloc 를 사용하여 할당된 TLS 인덱스를 해제하고 스레드 로컬 데이터를 해제할 수 있습니다.
DLL_PROCESS_DETACH 알림을 받는 스레드가 반드시 DLL_PROCESS_ATTACH알림을 받은 스레드와 동일하지는 않습니다.- DLL_THREAD_ATTACH
- 2
현재 프로세스에서 새 스레드를 만들고 있습니다. 이 경우 시스템은 현재 프로세스에 연결된 모든 DLL의 진입점 함수를 호출합니다. 호출은 새 스레드의 컨텍스트에서 이루어집니다. DLL은 이 기회를 사용하여 스레드에 대한 TLS 슬롯을 초기화할 수 있습니다. DLL_PROCESS_ATTACH DLL 진입점 함수를 호출하는 스레드는 DLL_THREAD_ATTACH사용하여 DLL 진입점 함수를 호출하지 않습니다.
DLL의 진입점 함수는 프로세스에서 DLL을 로드한 후에 만든 스레드에 의해서만 이 값으로 호출됩니다. LoadLibrary를 사용하여 DLL을 로드하는 경우 기존 스레드는 새로 로드된 DLL의 진입점 함수를 호출하지 않습니다.- DLL_THREAD_DETACH
- 3
스레드가 완전히 종료됩니다. DLL이 할당된 메모리에 대한 포인터를 TLS 슬롯에 저장한 경우 이 기회를 사용하여 메모리를 해제해야 합니다. 시스템은 이 값을 사용하여 현재 로드된 모든 DLL의 진입점 함수를 호출합니다. 호출은 종료 스레드의 컨텍스트에서 이루어집니다. -
lpvReserved [in]
-
fdwReason이 DLL_PROCESS_ATTACH 경우 lpvReserved는 동적 로드의 경우 NULL이고 정적 로드의 경우 NULL이 아닌 경우 입니다.
fdwReason이 DLL_PROCESS_DETACH 경우 FreeLibrary가 호출되었거나 DLL 로드가 실패한 경우 lpvReserved가 NULL이고 프로세스가 종료되는 경우 비 NULL입니다.
반환 값
시스템에서 DLL_PROCESS_ATTACH 값을 사용하여 DllMain 함수를 호출하면 함수는 성공하면 TRUE를 반환하고 초기화가 실패하면 FALSE를 반환합니다. 프로세스에서 LoadLibrary 함수를 사용하기 때문에 DllMain이 호출되면 반환 값이 FALSE이면 LoadLibrary는 NULL을 반환합니다. (시스템은 DLL_PROCESS_DETACH 사용하여 진입점 함수를 즉시 호출하고 DLL을 언로드합니다.) 프로세스 초기화 중에 DllMain이 호출되면 반환 값이 FALSE이면 프로세스가 오류로 종료됩니다. 확장 오류 정보를 가져오려면 GetLastError를 호출합니다.
시스템에서 DLL_PROCESS_ATTACH 이외의 값으로 DllMain 함수를 호출하면 반환 값이 무시됩니다.
설명
DllMain 은 라이브러리 정의 함수 이름의 자리 표시자입니다. DLL을 빌드할 때 사용하는 실제 이름을 지정해야 합니다. 자세한 내용은 개발 도구에 포함된 설명서를 참조하세요.
초기 프로세스를 시작하는 동안 또는 LoadLibrary를 호출한 후 시스템은 로드된 DLL 목록을 검사합니다. DLL_PROCESS_ATTACH 값으로 아직 호출되지 않은 각 DLL에 대해 시스템은 DLL의 진입점 함수를 호출합니다. 이 호출은 프로세스의 기본 스레드 또는 LoadLibrary라는 스레드와 같이 프로세스 주소 공간이 변경된 스레드의 컨텍스트에서 수행됩니다. 진입점에 대한 액세스는 프로세스 전체에서 시스템에 의해 직렬화됩니다. DllMain의 스레드는 로더 잠금을 유지하므로 추가 DLL을 동적으로 로드하거나 초기화할 수 없습니다.
DLL의 진입점 함수가 DLL_PROCESS_ATTACH 알림에 따라 FALSE를 반환하면 DLL_PROCESS_DETACH 알림이 수신되고 DLL이 즉시 언로드됩니다. 그러나 DLL_PROCESS_ATTACH 코드에서 예외를 throw하는 경우 진입점 함수는 DLL_PROCESS_DETACH 알림을 받지 않습니다.
진입점 함수가 스레드에 대한 DLL_THREAD_ATTACH 사용하여 호출되지 않은 경우에도 종료 스레드에 대해 진입점 함수가 호출되는 경우가 있습니다.
- 스레드는 프로세스의 초기 스레드이므로 시스템은 DLL_PROCESS_ATTACH 값으로 진입점 함수를 호출했습니다.
- LoadLibrary 함수를 호출할 때 스레드가 이미 실행 중이었기 때문에 시스템에서 진입점 함수를 호출하지 않았습니다.
DLL 로드 실패, 프로세스 종료 또는 FreeLibrary 호출로 인해 프로세스에서 DLL이 언로드되는 경우 시스템은 프로세스의 개별 스레드에 대한 DLL_THREAD_DETACH 값을 사용하여 DLL의 진입점 함수를 호출하지 않습니다. 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이 사용되지 않습니다. 따라서 진입점 함수는 다른 DLL을 로드하지 않는 Kernel32.dll 함수를 호출할 수 있습니다. 예를 들어 DllMain은 중요한 섹션 및 뮤텍스와 같은 동기화 개체를 만들고 TLS를 사용할 수 있습니다. 아쉽게도 Kernel32.dll 안전한 함수의 포괄적인 목록은 없습니다.
Kernel32.dll 이외의 DLL이 필요한 함수를 호출하면 진단하기 어려운 문제가 발생할 수 있습니다. 예를 들어 사용자, 셸 및 COM 함수를 호출하면 일부 함수가 다른 시스템 구성 요소를 로드하기 때문에 액세스 위반 오류가 발생할 수 있습니다. 반대로, 종료 중에 이러한 함수를 호출하면 해당 구성 요소가 이미 언로드되거나 초기화되지 않았을 수 있으므로 액세스 위반 오류가 발생할 수 있습니다.
DLL 알림이 직렬화되므로 진입점 함수는 다른 스레드 또는 프로세스와 통신을 시도해서는 안 됩니다. 결과적으로 교착 상태가 발생할 수 있습니다.
DLL을 작성할 때 모범 사례에 대한 자세한 내용은 동적 링크 라이브러리 모범 사례를 참조하세요.
DLL이 CRT(C 런타임 라이브러리)와 연결된 경우 CRT에서 제공하는 진입점은 전역 및 정적 C++ 개체에 대한 생성자 및 소멸자를 호출합니다. 따라서 DllMain 에 대한 이러한 제한 사항은 생성자 및 소멸자 및 해당 코드에서 호출되는 모든 코드에도 적용됩니다.
DLL이 정적 C CRT(런타임 라이브러리)와 연결되지 않는 한 DLL_PROCESS_ATTACH 수신할 때 DisableThreadLibraryCalls를 호출하는 것이 좋습니다.
요구 사항
요구 사항 | 값 |
---|---|
지원되는 최소 클라이언트 |
Windows XP [데스크톱 앱만 해당] |
지원되는 최소 서버 |
Windows Server 2003 [데스크톱 앱만 해당] |
헤더 |
|