TN011: usando MFC como parte de uma DLL

Esta observação descreve DLLs regulares do MFC, que permitem que você use a biblioteca do MFC como parte de uma biblioteca de vínculo dinâmico do Windows (DLL). Ela pressupõe que você esteja familiarizado com as DLLs do Windows e como compilá-las. Para obter informações sobre DLLs de extensão do MFC com as quais você pode criar extensões para a biblioteca MFC, consulte a Versão de DLL do MFC.

Interfaces de DLL

As DLLs regulares do MFC pressupõem que as interfaces entre o aplicativo e a DLL sejam especificadas em funções semelhantes a C ou classes explicitamente exportadas. As interfaces de classe MFC não podem ser exportadas.

Se uma DLL e um aplicativo desejarem usar o MFC, ambos terão a opção de usar a versão compartilhada das bibliotecas MFC ou vincular estaticamente a uma cópia das bibliotecas. O aplicativo e a DLL podem usar uma das versões padrão da biblioteca MFC.

As DLLs regulares do MFC têm várias vantagens:

  • O aplicativo que usa a DLL não precisa usar o MFC e não precisa ser um aplicativo Visual C++.

  • Com DLLs regulares do MFC que vinculam estaticamente ao MFC, o tamanho da DLL depende apenas das rotinas de runtime do MFC e C que são usadas e vinculadas.

  • Com DLLs regulares do MFC que vinculam dinamicamente ao MFC, a economia na memória do uso da versão compartilhada do MFC pode ser significativa. No entanto, você deve distribuir as DLLs compartilhadas, a Mfc<version>.dll e a Msvvcrt<version>.dll, com sua DLL.

  • O design de DLL é independente de como as classes são implementadas. Seu design de DLL exporta somente para as APIs desejadas. Como resultado, se a implementação for alterada, as DLLs regulares do MFC ainda serão válidas.

  • Com DLLs regulares do MFC que vinculam estaticamente ao MFC, se a DLL e o aplicativo usarem o MFC, não haverá problemas com o aplicativo que queira uma versão diferente do MFC do que a DLL ou vice-versa. Como a biblioteca MFC está estaticamente vinculada a cada DLL ou EXE, não há dúvida sobre qual versão você tem.

Limitações de API

Algumas funcionalidades do MFC não se aplicam à versão da DLL, seja devido a limitações técnicas ou porque esses serviços geralmente são fornecidos pelo aplicativo. Com a versão atual do MFC, a única função que não é aplicável é a CWinApp::SetDialogBkColor.

Compilando sua DLL

Ao compilar DLLs regulares do MFC que vinculam estaticamente ao MFC, os símbolos _USRDLL e _WINDLL devem ser definidos. O código DLL também deve ser compilado com as seguintes opções do compilador:

  • /D_WINDLL significa que a compilação é para uma DLL

  • /D_USRDLL especifica que você está criando uma DLL normal do MFC

Você também deve definir esses símbolos e usar esses comutadores de compilador ao compilar DLLs regulares do MFC que vinculam dinamicamente ao MFC. Além disso, o símbolo _AFXDLL deve ser definido e seu código DLL deve ser compilado com:

  • /D_AFXDLL especifica que você está criando uma DLL normal do MFC que é vinculada dinamicamente ao MFC

As interfaces (APIs) entre o aplicativo e a DLL devem ser exportadas explicitamente. Recomendamos que você defina suas interfaces como de baixa largura de banda e use apenas interfaces C se puder. As interfaces C diretas são mais fáceis de manter do que classes C++ mais complexas.

Coloque suas APIs em um cabeçalho separado que possa ser incluído por arquivos C e C++. Consulte o cabeçalho ScreenCap.h no exemplo de Conceitos Avançados do MFC DLLScreenCap para obter um exemplo. Para exportar suas funções, insira-as na seção EXPORTS do arquivo de definição do módulo (.DEF) ou inclua __declspec(dllexport) em suas definições de função. Use __declspec(dllimport) para importar essas funções para o executável do cliente.

Você deve adicionar a macro AFX_MANAGE_STATE no início de todas as funções exportadas em DLLs regulares do MFC que vinculam dinamicamente ao MFC. Essa macro define o estado do módulo atual para o da DLL. Para usar essa macro, adicione a seguinte linha de código ao início das funções exportadas da DLL:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

WinMain -> DllMain

A biblioteca MFC define o ponto de entrada DllMain padrão do Win32 que inicializa o objeto derivado do CWinApp como em um aplicativo MFC típico. Coloque toda a inicialização específica de DLL no método InitInstance como em um aplicativo MFC típico.

Observe que o mecanismo CWinApp::Run não se aplica a uma DLL, pois o aplicativo é proprietário do bombeador de mensagens principal. Se a DLL exibir diálogos sem janela restrita ou tiver uma janela de quadro principal própria, a bomba de mensagens principal do aplicativo deverá chamar uma rotina exportada por DLL que chama CWinApp::PreTranslateMessage.

Consulte o exemplo DLLScreenCap para usar essa função.

A função DllMain fornecida pelo MFC chamará o método CWinApp::ExitInstance de sua classe derivado de CWinApp antes de a DLL ser descarregada.

Vincular sua DLL

Com DLLs regulares do MFC que vinculam estaticamente ao MFC, você deve vincular sua DLL com Nafxcwd.lib ou Nafxcw.lib e com a versão dos runtimes C chamados Libcmt.lib. Essas bibliotecas são pré-criadas e podem ser instaladas especificando-as quando você executa a instalação do Visual C++.

Exemplo de código

Consulte o programa de exemplo de Conceitos Avançados do MFC DLLScreenCap para obter um exemplo completo. Há várias coisas interessantes a serem observadas neste exemplo, descritas a seguir:

  • Os sinalizadores do compilador da DLL e os do aplicativo são diferentes.

  • As linhas de link e os arquivos .DEF para a DLL e aqueles para o aplicativo são diferentes.

  • O aplicativo que usa a DLL não precisa estar em C++.

  • A interface entre o aplicativo e a DLL é uma API utilizável por C ou C++ e é exportada com DLLScreenCap.def.

O exemplo a seguir ilustra uma API que é definida em uma DLL normal do MFC que é vinculada estaticamente ao MFC. Neste exemplo, a declaração é colocada em um bloco extern "C" { } para usuários do C++. Isso possui várias vantagens. Primeiro, ele torna as APIs de DLL utilizáveis por aplicativos cliente que não sejam C++. Em segundo lugar, reduz a sobrecarga de DLL porque a desconfiguração do nome C++ não será aplicado ao nome exportado. Por fim, torna mais fácil adicionar explicitamente a um arquivo .DEF (para exportação por ordinal) sem precisar se preocupar com a desconfiguração de nome.

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

struct TracerData
{
    BOOL bEnabled;
    UINT flags;
};

BOOL PromptTraceFlags(TracerData FAR* lpData);

#ifdef __cplusplus
}
#endif

As estruturas usadas pela API não são derivadas de classes MFC e são definidas no cabeçalho da API. Isso reduz a complexidade da interface entre a DLL e o aplicativo e torna a DLL utilizável por programas C.

Confira também

Observações técnicas por número
Observações técnicas por categoria