Dynamic-Link 라이브러리 Entry-Point 함수

DLL은 필요에 따라 진입점 함수를 지정할 수 있습니다. 있는 경우 프로세스 또는 스레드가 DLL을 로드하거나 언로드할 때마다 시스템은 진입점 함수를 호출합니다. 간단한 초기화 및 정리 작업을 수행하는 데 사용할 수 있습니다. 예를 들어 새 스레드를 만들 때 스레드 로컬 스토리지를 설정하고 스레드가 종료될 때 클린 수 있습니다.

DLL을 C 런타임 라이브러리와 연결하는 경우 진입점 함수를 제공하고 별도의 초기화 함수를 제공할 수 있습니다. 자세한 내용은 런타임 라이브러리에 대한 설명서를 확인하세요.

고유한 진입점을 제공하는 경우 DllMain 함수를 참조하세요. 이름 DllMain은 사용자 정의 함수의 자리 표시자입니다. DLL을 빌드할 때 사용하는 실제 이름을 지정해야 합니다. 자세한 내용은 개발 도구에 포함된 설명서를 참조하세요.

Entry-Point 함수 호출

시스템은 다음 이벤트 중 하나가 발생할 때마다 진입점 함수를 호출합니다.

  • 프로세스는 DLL을 로드합니다. 부하 시간 동적 연결을 사용하는 프로세스의 경우 프로세스 초기화 중에 DLL이 로드됩니다. 런타임 연결을 사용하는 프로세스의 경우 LoadLibrary 또는 LoadLibraryEx가 반환되기 전에 DLL이 로드됩니다.
  • 프로세스는 DLL을 언로드합니다. 프로세스가 종료되거나 FreeLibrary 함수를 호출하고 참조 수가 0이 되면 DLL이 언로드됩니다. TerminateProcess 또는 TerminateThread 함수의 결과로 프로세스가 종료되는 경우 시스템은 DLL 진입점 함수를 호출하지 않습니다.
  • DLL을 로드한 프로세스에서 새 스레드가 만들어집니다. DisableThreadLibraryCalls 함수를 사용하여 스레드를 만들 때 알림을 사용하지 않도록 설정할 수 있습니다.
  • DLL을 로드한 프로세스의 스레드는 TerminateThread 또는 TerminateProcess를 사용하지 않고 정상적으로 종료됩니다. 프로세스가 DLL을 언로드할 때 진입점 함수는 프로세스의 각 기존 스레드에 대해 한 번이 아닌 전체 프로세스에 대해 한 번만 호출됩니다. DisableThreadLibraryCalls를 사용하여 스레드가 종료될 때 알림을 사용하지 않도록 설정할 수 있습니다.

한 번에 하나의 스레드만 진입점 함수를 호출할 수 있습니다.

시스템은 함수를 호출한 프로세스 또는 스레드의 컨텍스트에서 진입점 함수를 호출합니다. 이를 통해 DLL은 호출 프로세스의 가상 주소 공간에서 메모리를 할당하거나 프로세스에 액세스할 수 있는 핸들을 열기 위해 진입점 함수를 사용할 수 있습니다. 진입점 함수는 TLS(스레드 로컬 스토리지)를 사용하여 새 스레드에 프라이빗 메모리를 할당할 수도 있습니다. 스레드 로컬 스토리지에 대한 자세한 내용은 스레드 로컬 스토리지를 참조하세요.

Entry-Point 함수 정의

DLL 진입점 함수는 표준 호출 호출 규칙을 사용하여 선언해야 합니다. DLL 진입점이 올바르게 선언되지 않은 경우 DLL이 로드되지 않고 시스템에서 WINAPI를 사용하여 DLL 진입점을 선언해야 한다는 메시지를 표시합니다.

함수 본문에서 DLL 진입점이 호출된 다음 시나리오의 조합을 처리할 수 있습니다.

  • 프로세스는 DLL(DLL_PROCESS_ATTACH)을 로드합니다.
  • 현재 프로세스는 새 스레드(DLL_THREAD_ATTACH)를 만듭니다.
  • 스레드가 정상적으로 종료됩니다(DLL_THREAD_DETACH).
  • 프로세스는 DLL(DLL_PROCESS_DETACH)을 언로드합니다.

진입점 함수는 간단한 초기화 작업만 수행해야 합니다. 부하 부하 순서에서 종속성 루프를 만들 수 있으므로 LoadLibrary 또는 LoadLibraryEx 함수(또는 이러한 함수를 호출하는 함수)를 호출해서는 안 됩니다. 이로 인해 시스템에서 초기화 코드를 실행하기 전에 DLL이 사용될 수 있습니다. 마찬가지로 진입점 함수는 프로세스가 종료되는 동안 FreeLibrary 함수(또는 FreeLibrary를 호출하는 함수)를 호출해서는 안 됩니다. 시스템이 종료 코드를 실행한 후 DLL이 사용될 수 있기 때문입니다.

Kernel32.dll 진입점 함수가 호출될 때 프로세스 주소 공간에 로드되도록 보장되므로 Kernel32.dll 함수를 호출해도 초기화 코드가 실행되기 전에 DLL이 사용되지 않습니다. 따라서 진입점 함수는 중요한 섹션 및 뮤텍스와 같은 동기화 개체를 만들고 TLS를 사용할 수 있습니다. 이러한 함수는 Kernel32.dll 위치하기 때문입니다. 레지스트리 함수는 Advapi32.dll 있으므로 레지스트리 함수를 호출하는 것은 안전하지 않습니다.

다른 함수를 호출하면 진단하기 어려운 문제가 발생할 수 있습니다. 예를 들어 사용자, 셸 및 COM 함수를 호출하면 DLL의 일부 함수가 LoadLibrary 를 호출하여 다른 시스템 구성 요소를 로드하기 때문에 액세스 위반 오류가 발생할 수 있습니다. 반대로, 종료 중에 해당 함수를 호출하면 해당 구성 요소가 이미 언로드되거나 초기화되지 않았을 수 있으므로 액세스 위반 오류가 발생할 수 있습니다.

다음 예제에서는 DLL 진입점 함수를 구성하는 방법을 보여 줍니다.

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpReserved )  // 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:
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

Entry-Point 함수 반환 값

프로세스가 로드 중이기 때문에 DLL 진입점 함수가 호출되면 함수는 TRUE 를 반환하여 성공을 나타냅니다. 로드 시간 연결을 사용하는 프로세스의 경우 FALSE 의 반환 값으로 인해 프로세스 초기화가 실패하고 프로세스가 종료됩니다. 런타임 연결을 사용하는 프로세스의 경우 FALSE의 반환 값으로 인해 LoadLibrary 또는 LoadLibraryEx 함수가 NULL을 반환하여 실패를 나타냅니다. (시스템은 DLL_PROCESS_DETACH 사용하여 진입점 함수를 즉시 호출하고 DLL을 언로드합니다.) 진입점 함수의 반환 값은 다른 이유로 함수가 호출될 때 무시됩니다.