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