Partilhar via


DLLs de extensão MFC

Uma DLL de extensão MFC é uma DLL que normalmente implementa classes reutilizáveis derivadas das classes existentes da Microsoft Foundation Class Library.

Uma DLL de extensão MFC tem os seguintes recursos e requisitos:

  • O executável do cliente deve ser um aplicativo MFC compilado com _AFXDLL definido.

  • Uma DLL de extensão MFC também pode ser usada por uma DLL MFC regular que está dinamicamente ligada ao MFC.

  • As DLLs de extensão MFC devem ser compiladas com _AFXEXT definido. Isso força _AFXDLL a ser definido também e garante que as declarações apropriadas sejam extraídas dos arquivos de cabeçalho MFC. Ele também garante que AFX_EXT_CLASS é definido como __declspec(dllexport) durante a criação da DLL, que é necessário se você estiver usando essa macro para declarar as classes em sua extensão MFC DLL.

  • As DLLs de extensão MFC não devem instanciar uma classe derivada de CWinApp, mas devem confiar no aplicativo cliente (ou DLL) para fornecer esse objeto.

  • As DLLs de extensão MFC devem, no entanto, fornecer uma função DllMain e realizar qualquer inicialização necessária ali.

DLLs de extensão são criadas usando a versão de biblioteca de vínculo dinâmico do MFC (também conhecida como a versão compartilhada do MFC). Somente executáveis MFC (aplicativos ou DLLs MFC regulares) que são criados com a versão compartilhada do MFC podem usar uma DLL de extensão MFC. O aplicativo cliente e a DLL de extensão MFC devem usar a mesma versão do MFCx0.dll. Com uma DLL de extensão MFC, você pode derivar novas classes personalizadas do MFC e, em seguida, oferecer esta versão estendida do MFC para aplicativos que chamam sua DLL.

DLLs de extensão também podem ser usadas para passar objetos derivados de MFC entre o aplicativo e a DLL. As funções de membro associadas ao objeto passado existem no módulo onde o objeto foi criado. Como essas funções são exportadas corretamente ao usar a versão DLL compartilhada do MFC, você pode passar livremente ponteiros de objeto MFC ou MFC derivados entre um aplicativo e as DLLs de extensão MFC que ele carrega.

Uma DLL de extensão MFC usa uma versão compartilhada do MFC da mesma forma que um aplicativo usa a versão DLL compartilhada do MFC, com algumas considerações adicionais:

  • Ele não tem um CWinAppobjeto derivado. Ele deve trabalhar com o CWinAppobjeto derivado do aplicativo cliente. Isso significa que o aplicativo cliente possui a bomba de mensagem principal, o loop ocioso e assim por diante.

  • Chama AfxInitExtensionModule na sua DllMain função. O valor de retorno desta função deve ser verificado. Se um valor zero for retornado de AfxInitExtensionModule, retorne 0 da sua DllMain função.

  • Ele cria um objeto CDynLinkLibrary durante a inicialização se a DLL de extensão MFC deseja exportar CRuntimeClass objetos ou recursos para o aplicativo.

Antes da versão 4.0 do MFC, esse tipo de DLL era chamado de AFXDLL. AFXDLL refere-se ao símbolo do _AFXDLL pré-processador que é definido ao criar a DLL.

As bibliotecas de importação para a versão compartilhada do MFC são nomeadas de acordo com a convenção descrita em Convenções de nomenclatura para DLLs MFC. O Visual Studio fornece versões pré-criadas das DLLs MFC, além de várias DLLs não MFC que você pode usar e distribuir com seus aplicativos. Eles estão documentados no Redist.txt, que é instalado na pasta Arquivos de Programas\Microsoft Visual Studio.

Se você estiver exportando usando um arquivo .def, coloque o seguinte código no início e no final do arquivo de cabeçalho:

#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA

Essas quatro linhas garantem que seu código seja compilado corretamente para uma DLL de extensão MFC. Deixar de fora essas quatro linhas pode fazer com que sua DLL seja compilada ou vinculada incorretamente.

Se você precisar passar um ponteiro de objeto MFC ou derivado de MFC para ou de uma DLL MFC, a DLL deve ser uma DLL de extensão MFC. As funções de membro associadas ao objeto passado existem no módulo onde o objeto foi criado. Como essas funções são exportadas corretamente ao usar a versão DLL compartilhada do MFC, você pode passar livremente ponteiros de objeto MFC ou MFC derivados entre um aplicativo e as DLLs de extensão MFC que ele carrega.

Devido a problemas de gerenciamento e exportação de nomes C++, a lista de exportação de uma DLL de extensão MFC pode ser diferente entre as versões de depuração e varejo da mesma DLL e DLLs para plataformas diferentes. O MFCx0.dll de varejo tem cerca de 2.000 pontos de entrada exportados; O MFCx0D.dll de depuração tem cerca de 3.000 pontos de entrada exportados.

Gerenciamento de memória

MFCx0.dll e todas as DLLs de extensão MFC carregadas no espaço de endereçamento de um aplicativo cliente usam o mesmo alocador de memória, carregamento de recursos e outros estados globais MFC como se estivessem no mesmo aplicativo. Isso é significativo porque as bibliotecas de DLL não-MFC e as DLLs MFC regulares fazem exatamente o oposto e têm cada DLL alocando fora de seu próprio pool de memória.

Se uma DLL de extensão MFC aloca memória, essa memória pode se misturar livremente com qualquer outro objeto alocado pelo aplicativo. Além disso, se um aplicativo que se vincula dinamicamente ao MFC falhar, a proteção do sistema operacional mantém a integridade de qualquer outro aplicativo MFC compartilhando a DLL.

Da mesma forma, outros estados MFC globais, como o arquivo executável atual para carregar recursos, também são compartilhados entre o aplicativo cliente e todas as DLLs de extensão MFC, bem como MFCx0.dll em si.

Compartilhando recursos e classes

A exportação de recursos é feita através de uma lista de recursos. Cada aplicativo contém uma lista vinculada individualmente de objetos CDynLinkLibrary . Ao procurar um recurso, a maioria das implementações padrão do MFC que carregam recursos examina primeiro o módulo de recurso atual (AfxGetResourceHandle) e, se o recurso não for encontrado, percorre a lista de objetos do CDynLinkLibrary tentando carregar o recurso solicitado.

Percorrer a lista tem as desvantagens de ser um pouco mais lento e exigir o gerenciamento de intervalos de ID de recursos. Ele tem a vantagem de que um aplicativo cliente que se vincula a várias DLLs de extensão MFC pode usar qualquer recurso fornecido pela DLL sem ter que especificar o identificador de instância da DLL. AfxFindResourceHandle é uma API usada para percorrer a lista de recursos para procurar uma determinada correspondência. Ele usa o nome e o tipo de um recurso e retorna o identificador de recurso onde ele foi encontrado pela primeira vez (ou NULL).

Se você não quiser percorrer a lista e carregar apenas recursos de um local específico, use as funções AfxGetResourceHandle e AfxSetResourceHandle para salvar a alça antiga e definir a nova alça. Certifique-se de restaurar o identificador de recurso antigo antes de retornar ao aplicativo cliente. Para obter um exemplo de como usar essa abordagem para carregar explicitamente um menu, consulte Testdll2 .cpp no exemplo MFC DLLHUSK.

A criação dinâmica de objetos MFC com um nome MFC é semelhante. O mecanismo de desserialização de objetos MFC precisa ter todos os CRuntimeClass objetos registrados para que possa ser reconstruído criando dinamicamente objetos C++ do tipo necessário com base no que foi armazenado anteriormente.

No caso do exemplo MFC DLLHUSK, a lista se parece com:

head ->   DLLHUSK.EXE   - or -   DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL           TESTDLL2.DLL
               |                      |
          TESTDLL1.DLL           TESTDLL1.DLL
               |                      |
           MFCOxxD.DLL                |
               |                      |
           MFCDxxD.DLL                |
               |                      |
            MFCxxD.DLL            MFCxx.DLL

onde xx é o número da versão; por exemplo, 42 representa a versão 4.2.

O MFCxx.dll geralmente é o último na lista de recursos e classes. MFCxx.dll inclui todos os recursos MFC padrão, incluindo cadeias de caracteres de prompt para todas as IDs de comando padrão. Colocá-lo no final da lista permite que as DLLs e o próprio aplicativo cliente não tenham sua própria cópia dos recursos MFC padrão, mas dependam dos recursos compartilhados no MFCxx.dll em vez disso.

Mesclar os recursos e nomes de classe de todas as DLLs no espaço de nome do aplicativo cliente tem a desvantagem de exigir que você tenha cuidado com quais IDs ou nomes você escolhe.

O exemplo DLLHUSK gerencia o espaço de nome de recurso compartilhado usando vários arquivos de cabeçalho.

Se sua DLL de extensão MFC precisa manter dados extras para cada aplicativo, você pode derivar uma nova classe de CDynLinkLibrary e criá-la em DllMain. Durante a execução, a DLL pode verificar a lista atual da aplicação de objetos CDynLinkLibrary para encontrar aquele que pertence a essa DLL específica de extensão MFC.

O que pretende fazer?

Sobre o que quer saber mais?

Ver também

criar DLLs C/C++ no Visual Studio