Função Entry-Point da Biblioteca Dynamic-Link

Opcionalmente, uma DLL pode especificar uma função de ponto de entrada. Se presente, o sistema chama a função de ponto de entrada sempre que um processo ou thread carrega ou descarrega a DLL. Ele pode ser usado para executar tarefas simples de inicialização e limpeza. Por exemplo, ele pode configurar o armazenamento local do thread quando um novo thread é criado e limpo-lo quando o thread é encerrado.

Se você estiver vinculando sua DLL à biblioteca de tempo de execução C, ela poderá fornecer uma função de ponto de entrada para você e permitir que você forneça uma função de inicialização separada. Verifique a documentação da biblioteca em tempo de execução para obter mais informações.

Se você estiver fornecendo seu próprio ponto de entrada, consulte a função DllMain . O nome DllMain é um espaço reservado para uma função definida pelo usuário. Você deve especificar o nome real usado ao criar sua DLL. Para obter mais informações, consulte a documentação incluída em suas ferramentas de desenvolvimento.

Chamando a função Entry-Point

O sistema chama a função de ponto de entrada sempre que qualquer um dos seguintes eventos ocorre:

  • Um processo carrega a DLL. Para processos que usam vinculação dinâmica de tempo de carga, a DLL é carregada durante a inicialização do processo. Para processos que usam vinculação em tempo de execução, a DLL é carregada antes que LoadLibrary ou LoadLibraryEx retorne.
  • Um processo descarrega a DLL. A DLL é descarregada quando o processo termina ou chama a função FreeLibrary e a contagem de referência se torna zero. Se o processo terminar como resultado da função TerminateProcess ou TerminateThread , o sistema não chamará a função de ponto de entrada DLL.
  • Um novo thread é criado em um processo que carregou a DLL. Você pode usar a função DisableThreadLibraryCalls para desabilitar a notificação quando os threads são criados.
  • Um thread de um processo que carregou a DLL termina normalmente, não usando TerminateThread ou TerminateProcess. Quando um processo descarrega a DLL, a função de ponto de entrada é chamada apenas uma vez para todo o processo, em vez de uma vez para cada thread existente do processo. Você pode usar DisableThreadLibraryCalls para desabilitar a notificação quando os threads forem encerrados.

Somente um thread por vez pode chamar a função de ponto de entrada.

O sistema chama a função de ponto de entrada no contexto do processo ou thread que fez com que a função fosse chamada. Isso permite que uma DLL use sua função de ponto de entrada para alocar memória no espaço de endereço virtual do processo de chamada ou para abrir identificadores acessíveis ao processo. A função de ponto de entrada também pode alocar memória privada para um novo thread usando o TLS (armazenamento local de thread). Para obter mais informações sobre o armazenamento local do thread, consulte Armazenamento local de thread.

Definição da função Entry-Point

A função de ponto de entrada DLL deve ser declarada com a convenção de chamada de chamada padrão. Se o ponto de entrada da DLL não for declarado corretamente, a DLL não será carregada e o sistema exibirá uma mensagem indicando que o ponto de entrada da DLL deve ser declarado com WINAPI.

No corpo da função, você pode manipular qualquer combinação dos seguintes cenários em que o ponto de entrada de DLL foi chamado:

  • Um processo carrega a DLL (DLL_PROCESS_ATTACH).
  • O processo atual cria um novo thread (DLL_THREAD_ATTACH).
  • Um thread sai normalmente (DLL_THREAD_DETACH).
  • Um processo descarrega a DLL (DLL_PROCESS_DETACH).

A função de ponto de entrada deve executar apenas tarefas de inicialização simples. Ele não deve chamar a função LoadLibrary ou LoadLibraryEx (ou uma função que chama essas funções), pois isso pode criar loops de dependência na ordem de carregamento da DLL. Isso pode fazer com que uma DLL seja usada antes que o sistema execute seu código de inicialização. Da mesma forma, a função de ponto de entrada não deve chamar a função FreeLibrary (ou uma função que chama FreeLibrary) durante o encerramento do processo, pois isso pode resultar em uma DLL sendo usada depois que o sistema executou seu código de encerramento.

Como Kernel32.dll tem a garantia de ser carregada no espaço de endereço do processo quando a função de ponto de entrada é chamada, chamar funções no Kernel32.dll não resulta no uso da DLL antes da execução do código de inicialização. Portanto, a função de ponto de entrada pode criar objetos de sincronização , como seções críticas e mutexes, e usar TLS, pois essas funções estão localizadas em Kernel32.dll. Não é seguro chamar as funções do Registro, por exemplo, porque elas estão localizadas em Advapi32.dll.

Chamar outras funções pode resultar em problemas difíceis de diagnosticar. Por exemplo, chamar funções User, Shell e COM pode causar erros de violação de acesso, pois algumas funções em suas DLLs chamam LoadLibrary para carregar outros componentes do sistema. Por outro lado, chamar essas funções durante o encerramento pode causar erros de violação de acesso porque o componente correspondente pode já ter sido descarregado ou não inicializado.

O exemplo a seguir demonstra como estruturar a função de ponto de entrada da 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.
}

Valor retornado da função Entry-Point

Quando uma função de ponto de entrada DLL é chamada porque um processo está sendo carregado, a função retorna TRUE para indicar êxito. Para processos que usam vinculação de tempo de carga, um valor retornado de FALSE faz com que a inicialização do processo falhe e o processo seja encerrado. Para processos que usam vinculação em tempo de execução, um valor retornado de FALSE faz com que a função LoadLibrary ou LoadLibraryEx retorne NULL, indicando falha. (O sistema chama imediatamente sua função de ponto de entrada com DLL_PROCESS_DETACH e descarrega a DLL.) O valor retornado da função de ponto de entrada é desconsiderado quando a função é chamada por qualquer outro motivo.