TN033: Versão DLL do MFC
Esta nota descreve como você pode usar o MFCxx.DLL e MFCxxD.DLL (onde x é o número de versão MFC) compartilhada bibliotecas de vínculo dinâmico com aplicativos MFC e DLLs de extensão.Para obter mais informações sobre DLLs regulares, consulte Usando o MFC como parte de uma DLL.
Esta nota técnica abrange três aspectos das DLLs.Os dois últimos são para usuários mais avançados:
Como criar uma DLL de extensão do MFC
Como criar um aplicativo MFC que usa a versão DLL do MFC
Como o MFC compartilhada bibliotecas de vínculo dinâmico são implementados
Se você estiver interessado na criação de uma DLL usando MFC que pode ser usado com aplicativos não-MFC (é chamado uma DLL regular), consulte técnico nota 11.
Visão geral do suporte MFCxx.DLL: terminologia e arquivos
DLL regular: usar uma DLL regular para criar uma DLL autônoma usando algumas das classes MFC.Interfaces entre o limite do App/DLL são interfaces de "C" e o aplicativo cliente não precisa ser um aplicativo MFC.
Esta é a versão de DLL suporte suportado no MFC 1.0.Descrito em técnico nota 11 e o MFC avançado conceitos exemplo DLLScreenCap.
Observação |
---|
Como do Visual C++ versão 4.0, o termo USRDLL é obsoleto e foi substituído por uma DLL regular que vincula estaticamente ao MFC.Você também pode criar uma DLL regular que vincula dinamicamente a MFC. |
MFC 3.0 (e acima) oferece suporte a DLLs normais com todos os novos recursos incluindo as classes OLE e banco de dados.
AFXDLL: isso também é conhecido como a versão compartilhada das bibliotecas MFC.Este é o novo suporte a DLL adicionado no MFC 2.0.A biblioteca MFC propriamente dito é um número de DLLs (descrita abaixo) e um aplicativo cliente ou DLL dinamicamente vincula DLLs que ele necessita.Interfaces entre o limite de aplicativo/DLL são C + + / interfaces de classe do MFC.O aplicativo cliente deve ser um aplicativo MFC.Isso oferece suporte a todas as funcionalidades do MFC 3.0 (exceção: não há suporte para UNICODE para as classes de banco de dados).
Observação |
---|
Como do Visual C++ versão 4.0, esse tipo de DLL é chamado de "Extensão DLL." |
Esta nota usará MFCxx.DLL para se referir a todo o conjunto de DLL do MFC, que inclui:
Debug: MFCxxD.DLL (combinado) e MFCSxxD.LIB (estático).
Versão: MFCxx.DLL (combinado) e MFCSxx.LIB (estático).
Depurar Unicode: MFCxxUD.DLL (combinado) e MFCSxxD.LIB (estático).
Versão Unicode: MFCxxU.DLL (combinado) e MFCSxxU.LIB (estático).
Observação |
---|
O MFCSxx [U] [D].LIB bibliotecas são usadas em conjunto com o MFC DLLs compartilhadas.Essas bibliotecas contêm código que deve estar vinculado estaticamente para o aplicativo ou DLL. |
Links um aplicativo para bibliotecas de importação correspondentes:
Depurar: MFCxxD.LIB
Versão: MFCxx.LIB
Depurar Unicode: MFCxxUD.LIB
Versão Unicode: MFCxxU.LIB
Um "extensão do MFC DLL" é uma DLL construída MFCxx.DLL (e/ou outro MFC DLLs compartilhadas).Entra aqui a arquitetura de componentes do MFC em ação.Se você deriva uma classe útil de uma classe do MFC ou criar outro como MFC toolkit, coloque-o em uma DLL.DLL usa o MFCxx.DLL, como faz o aplicativo do cliente final.Isso permite que classes reutilizáveis folha reutilizáveis classes base e classes de documento/modo de exibição reutilizáveis.
Prós e contras
Por que você deve usar a versão compartilhada do MFC?
Usando a biblioteca compartilhada pode resultar em aplicativos menores (um aplicativo mínimo que usa a maioria da biblioteca MFC é menor que 10 K).
A versão compartilhada do MFC oferece suporte a DLLs de extensão do MFC e DLLs normais.
Criando um aplicativo que usa as bibliotecas MFC compartilhadas é mais rápido do que criar um aplicativo MFC vinculado estaticamente, pois não é necessário vincular MFC propriamente dito.Isso é especialmente verdadeiro em DEBUG onde o vinculador deve compactar as informações de depuração de compilações — vinculando-se com uma DLL que já contém as informações de depuração, há menos informações de depuração para compactar dentro de seu aplicativo.
Por que você não deve usar a versão compartilhada do MFC:
- Remessa de um aplicativo que usa a biblioteca compartilhada exige que você enviar a MFCxx.DLL (e outros) biblioteca com seu programa.MFCxx.DLL é redistribuível gratuitamente como várias DLLs, mas você ainda deve instalar a DLL no seu programa de instalação.Além disso, você deve entregar a MSVCRTxx.DLL, que contém a biblioteca c runtime que é usada tanto pelo seu programa e as DLLs de MFC próprios.
Como escrever uma DLL de extensão do MFC
Uma DLL de extensão do MFC é uma DLL que contém classes e funções escritas para aprimorar a funcionalidade das classes MFC.Uma DLL de extensão do MFC usa as DLLs de MFC compartilhada da mesma forma que um aplicativo usa, com algumas considerações adicionais:
O processo de compilação é semelhante à criação de um aplicativo que usa as bibliotecas MFC compartilhadas com alguns adicionais do compilador e vinculador opções.
Uma DLL de extensão do MFC não tem um CWinApp-classe derivada.
Uma DLL de extensão do MFC deve fornecer um especial DllMain.AppWizard fornece um DllMain função pode modificar.
Uma DLL de extensão do MFC geralmente fornece uma rotina de inicialização para criar um CDynLinkLibrary se a extensão DLL desejar exportar CRuntimeClasses ou recursos para o aplicativo.Uma classe derivada de CDynLinkLibrary podem ser usados se os dados de cada aplicativo devem ser mantidos pela extensão DLL.
Essas considerações são descritas mais detalhadamente abaixo.Você também deve consultar a amostra de MFC avançado conceitos DLLHUSK desde que ele ilustra:
Criando um aplicativo usando bibliotecas compartilhadas.(DLLHUSK.EXE é um aplicativo do MFC dinamicamente links para as bibliotecas MFC também outras DLLs).
Criando uma DLL de extensão do MFC.(Observe os sinalizadores especiais como _AFXEXT que são usados na criação de uma DLL de extensão)
Dois exemplos de DLLs de extensão do MFC.Mostra a estrutura básica de uma DLL de extensão do MFC com exportações limitadas (TESTDLL1) e outras mostra a exportação de uma interface de classe inteira (TESTDLL2).
O aplicativo cliente e quaisquer DLLs de extensão devem usar a mesma versão do MFCxx.DLL.Deve seguem a convenção de DLL do MFC e fornecer tanto uma depuração e varejo (/Release) versão da DLL de extensão.Isso permite que programas cliente para criar versões de depuração e varejo de seus aplicativos e vinculá-las com a versão de varejo de todas as DLLs ou debug apropriado.
Observação |
---|
Como C++ nome desconfiguração e problemas de exportar, Exportar lista de uma DLL de extensão pode ser diferente entre as versões de depuração e varejo da mesma DLL e DLLs para diferentes plataformas.Varejo MFCxx.DLL tem cerca de 2000 exportados pontos de entrada; debug MFCxxD.DLL sobre 3000 tem exportado pontos de entrada. |
Anotação rápida no gerenciamento de memória
A seção "Gerenciamento de memória," próximo ao final desta nota técnica descreve a implementação de MFCxx.DLL com a versão compartilhada do MFC.As informações que você precisa saber para implementar uma extensão DLL são descritas aqui.
MFCxx.DLL e todas as DLLs de extensão carregadas no espaço de endereço de um aplicativo cliente usará o mesmo alocador de memória, carregamento de recursos e outros estados MFC "globais" como se estivessem no mesmo aplicativo.Isso é significativo porque as bibliotecas não - MFC DLL e regulares DLLs vinculadas estaticamente a MFC fazer exatamente o oposto e tem alocar cada DLL fora do seu próprio pool de memória.
Se uma extensão DLL aloca memória, que a memória pode livremente intermix com qualquer outro objeto alocado pelo aplicativo.Além disso, se um aplicativo que usa as bibliotecas MFC compartilhadas falhar, a proteção do sistema operacional manterá a integridade de qualquer outro aplicativo do MFC a DLL de compartilhamento.
Da mesma forma outros estados MFC "globais", como o atual arquivo executável para carregar recursos, também são compartilhados entre o aplicativo cliente e todas as DLLs de extensão do MFC, bem como MFCxx.DLL si mesmo.
Criando uma DLL de extensão
Você pode usar AppWizard para criar um projeto DLL de extensão do MFC e irá gerar automaticamente as configurações do vinculador e o compilador apropriado.Foi também gerar uma DllMain função pode modificar.
Se você estiver convertendo um projeto existente para uma DLL de extensão do MFC, comece com as regras padrão para a criação de um aplicativo usando a versão compartilhada do MFC e faça o seguinte:
Adicionar /D_AFXEXT os sinalizadores de compilador.Na caixa de diálogo Propriedades do projeto, selecione o nó C/C++.Selecione a categoria de pré-processador.Adicionar _AFXEXT campo definir Macros, separando cada um dos itens com ponto e vírgula.
Remover o /Gy opção de compilador.Na caixa de diálogo Propriedades do projeto, selecione o nó C/C++.Selecione a categoria de geração de código.Verifique se a opção "Ativar a vinculação do nível de função" não está ativada.Isso tornará mais fácil exportar classes porque o vinculador não irá remover funções não referenciadas.Se o projeto original é usado para criar uma DLL Regular estaticamente vinculadas ao MFC, alterar o /MT [d opção de compilador para [d] /MD.
Criar uma biblioteca de exportação com o /DLL opção de LINK.Isso será definido quando você cria um novo destino, especificando a biblioteca de vínculo dinâmico do Win32 como o tipo de destino.
Alterando os arquivos de cabeçalho
O objetivo de uma extensão DLL é geralmente exportar algumas funcionalidades comuns para um ou mais aplicativos podem usar essa funcionalidade.Isso se resume à exportação de classes e funções globais estão disponíveis para aplicativos cliente.
Para fazer isso, você deve garantir que cada uma das funções de membro marcada como importar ou exportar, conforme apropriado.Isso requer declarações especiais: __declspec(dllexport) e __declspec(dllimport).Quando as classes são usadas por aplicativos cliente, você deseja que seja declarado como __declspec(dllimport).Quando a extensão DLL próprio está sendo criada, deve ser declarados como __declspec(dllexport).Além disso, as funções devem ser realmente exportadas, para que os programas cliente vinculá-las no tempo de carregamento.
Para exportar sua classe inteira, use AFX_EXT_CLASS na definição de classe.Essa macro é definida pela estrutura como __declspec(dllexport) quando _AFXDLL e _AFXEXT é definida, mas definido como __declspec(dllimport) quando _AFXEXT não definido._AFXEXTconforme descrito acima, só é definido ao criar sua DLL de extensão.Por exemplo:
class AFX_EXT_CLASS CExampleExport : public CObject
{ ... class definition ... };
Não exportando a classe inteira
Às vezes, você poderá exportar apenas os necessários membros individuais da sua classe.Por exemplo, se você estiver exportando uma CDialog-derivado classe, apenas talvez seja necessário exportar o construtor e o DoModal chamar.Você pode exportar esses membros usando a DLL.Arquivo DEF, mas você também pode usar AFX_EXT_CLASS da mesma maneira em membros individuais, você precisa exportar.
Por exemplo:
class CExampleDialog : public CDialog
{
public:
AFX_EXT_CLASS CExampleDialog();
AFX_EXT_CLASS int DoModal();
// rest of class definition
.
.
.
};
Quando você fizer isso, você pode ter um problema adicional porque você não estiver exportando todos os membros da classe.O problema é a maneira que funcionam as macros do MFC.Várias macros do auxiliar do MFC realmente declarar ou definem os membros de dados.Portanto, esses membros de dados também precisará ser exportado de sua DLL.
Por exemplo, o DECLARE_DYNAMIC macro é definida da seguinte maneira quando estiver criando uma DLL de extensão:
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
A linha que começa "estático AFX_DATA" é declarar um objeto estático dentro de sua classe.Para exportar essa classe corretamente e acessar as informações de tempo de execução de um cliente.EXE, você precisa exportar esse objeto estático.Porque o objeto estático é declarado com o modificador AFX_DATA, você precisará definir AFX_DATA ser __declspec(dllexport) ao criar sua DLL e defina-o como __declspec(dllimport) ao criar o executável do cliente.
Como discutido acima, AFX_EXT_CLASS já definidas dessa maneira.Basta sendo AFX_DATA o mesmo que AFX_EXT_CLASS em torno de sua definição de classe.
Por exemplo:
#undef AFX_DATA
#define AFX_DATA AFX_EXT_CLASS
class CExampleView : public CView
{
DECLARE_DYNAMIC()
// ... class definition ...
};
#undef AFX_DATA
#define AFX_DATA
MFC sempre usa o AFX_DATA símbolo de itens de dados define dentro de suas macros, portanto, essa técnica funcionará para todas as situações.Por exemplo, funcionará para DECLARE_MESSAGE_MAP.
Observação |
---|
Se você estiver exportando a classe inteira em vez de membros selecionados da classe, os membros de dados estáticos são automaticamente exportados. |
Você pode usar a mesma técnica para exportar automaticamente o CArchive operador de extração de classes que usam o DECLARE_SERIAL e IMPLEMENT_SERIAL macros.Exportar o operador de arquivamento por cercando as declarações de classe (localizado na.Arquivo H) com o seguinte código:
#undef AFX_API
#define AFX_API AFX_EXT_CLASS
<your class declarations here>
#undef AFX_API
#define AFX_API
Limitações do _AFXEXT
Você pode usar o _AFXEXT pre-processor símbolo de sua extensão DLLs desde que você não tem várias camadas de DLLs de extensão.Se você tiver extensão DLLs que chamar ou derivam de classes em sua própria extensão DLLs, que então derivar classes MFC, você deve usar seu próprio símbolo do pré-processador para evitar ambigüidade.
O problema é que no Win32, você deve explicitamente declarar todos os dados como __declspec(dllexport) se estiver a ser exportado de uma DLL, e __declspec(dllimport) se estiver a ser importado de uma DLL.Quando você definir _AFXEXT, os cabeçalhos MFC, certifique-se AFX_EXT_CLASS está definido corretamente.
Quando você tiver várias camadas, um símbolo, como AFX_EXT_CLASS não é suficiente, pois uma DLL de extensão pode ser exportando novas classes, bem como a importação de outras classes de outra extensão DLL.Para lidar com esse problema, use um símbolo de pré-processamento especial que indica que você esteja criando DLL versus usando a DLL.Por exemplo, imagine DLLs de extensão de dois, dll e b. dll.Cada exportar algumas classes A.H e B.H, respectivamente.B. dll usa as classes de DLL.Os arquivos de cabeçalho poderiam ter esta aparência:
/* A.H */
#ifdef A_IMPL
#define CLASS_DECL_A __declspec(dllexport)
#else
#define CLASS_DECL_A __declspec(dllimport)
#endif
class CLASS_DECL_A CExampleA : public CObject
{ ... class definition ... };
/* B.H */
#ifdef B_IMPL
#define CLASS_DECL_B __declspec(dllexport)
#else
#define CLASS_DECL_B __declspec(dllimport)
#endif
class CLASS_DECL_B CExampleB : public CExampleA
{ ... class definition .. };
Quando a dll é criado, ele é criado com /D A_IMPL e quando b. dll é criado, ele é criado com /D B_IMPL.Usando símbolos separados para cada DLL exportado CExampleB e CExampleA é importado ao criar b. dll.CExampleA é exportada ao criar a dll e importado quando usado por b. dll (ou outro cliente).
Esse tipo de camadas não pode ser feito quando uso interno AFX_EXT_CLASS e _AFXEXT símbolos de pré-processamento.A técnica descrita acima resolve esse problema de maneira não ao contrário das que mecanismo MFC próprio usa ao criar sua extensão DLLs OLE, banco de dados e rede.
Não exportando a classe inteira
Novamente, você terá que tomar cuidados especiais quando você não estiver exportando uma classe inteira.Você precisa garantir que os itens de dados necessários criados por macros MFC são exportados corretamente.Isso pode ser feito por re-defining AFX_DATA a macro de sua classe específica.Isso deve ser feito a qualquer momento que você não estiver exportando uma classe inteira.
Por exemplo:
// A.H
#ifdef A_IMPL
#define CLASS_DECL_A _declspec(dllexport)
#else
#define CLASS_DECL_A _declspec(dllimport)
#endif
#undef AFX_DATA
#define AFX_DATA CLASS_DECL_A
class CExampleA : public CObject
{
DECLARE_DYNAMIC()
CLASS_DECL_A int SomeFunction();
//class definition
.
.
.
};
#undef AFX_DATA
#define AFX_DATA
DllMain
A seguir está o código exato que você deve colocar no seu arquivo de origem principal para a DLL de extensão.Ele deve vir após o padrão inclui.Observe que quando você usar AppWizard para criar arquivos de starter para uma DLL de extensão, ele fornece uma DllMain para você.
#include "afxdllx.h"
static AFX_EXTENSION_MODULE extensionDLL;
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(
extensionDLL, hInstance))
return 0;
// TODO: perform other initialization tasks here
}
else if (dwReason == DLL_PROCESS_DETACH)
{
// Extension DLL per-process termination
AfxTermExtensionModule(extensionDLL);
// TODO: perform other cleanup tasks here
}
return 1; // ok
}
A chamada para AfxInitExtensionModule captura as classes de tempo de execução de módulos (CRuntimeClass estruturas), bem como seus fábricas de objeto (COleObjectFactory objetos) para usar posteriormente, quando o CDynLinkLibrary objeto é criado.A chamada (opcional) AfxTermExtensionModule permite MFC para limpeza a extensão DLL quando cada processo desanexa (que acontece quando o processo é encerrado ou quando a DLL é descarregada como resultado de uma FreeLibrary chamar) de extensão DLL.Desde que a maioria dos extensão DLLs não são carregadas dinamicamente (geralmente, eles são vinculados por meio de suas bibliotecas de importação), a chamada para AfxTermExtensionModule não é necessário.
Se seu aplicativo carrega e libera DLLs de extensão dinamicamente, certifique-se de chamar AfxTermExtensionModule como mostrado acima.Também Certifique-se de usar AfxLoadLibrary e AfxFreeLibrary (em vez de funções Win32 LoadLibrary e FreeLibrary) se seu aplicativo usa vários threads ou se ele dinamicamente carrega uma extensão DLL.Usando AfxLoadLibrary e AfxFreeLibrary assegura que o código de inicialização e desligamento que executa quando a extensão DLL é carregada e descarregada não corromper o estado global do MFC.
O arquivo de cabeçalho AFXDLLX.H contém definições especiais para estruturas usadas em DLLs de extensão, como a definição de AFX_EXTENSION_MODULE e CDynLinkLibrary.
O global extensionDLL deve ser declarado como mostrado.Ao contrário da versão de 16 bits do MFC, você pode alocar memória e chamar funções MFC durante esse tempo, desde que o MFCxx.DLL é totalmente inicializado pelo tempo de DllMain é chamado.
Compartilhamento de recursos e Classes
DLLs de extensão do MFC simples precisam exportar somente algumas funções de baixa largura de banda para o aplicativo cliente e nada mais.Mais DLLs de uso intensivo de interface do usuário poderá exportar classes C++ e recursos para o aplicativo cliente.
Exportação de recursos é feito através de uma lista de recursos.Cada aplicativo é uma lista vinculada separada de CDynLinkLibrary objetos.Ao procurar um recurso, a maioria das implementações padrão MFC que carregar recursos analisar primeira o módulo atual do recurso (AfxGetResourceHandle) e se não encontrar walk lista de CDynLinkLibrary objetos tentando carregar o recurso solicitado.
Criação dinâmica de objetos C++ recebe um nome de classe do C++ é semelhante.O mecanismo de desserialização do objeto MFC precisa ter todos os CRuntimeClass objetos registrados, de forma que pode reconstruir criando dinamicamente objeto C++ do tipo necessário com base no que foi armazenado anteriormente.
Se você deseja que o aplicativo cliente para usar as classes em sua extensão DLL são DECLARE_SERIAL, você precisará exportar suas classes fiquem visíveis para o aplicativo cliente.Isso também é feito inserindo a CDynLinkLibrary lista.
No caso do exemplo MFC avançado conceitos DLLHUSK, a lista é semelhante:
head -> DLLHUSK.EXE - or - DLLHUSK.EXE
| |
TESTDLL2.DLL TESTDLL2.DLL
| |
TESTDLL1.DLL TESTDLL1.DLL
| |
| |
MFC90D.DLL MFC90.DLL
O MFCxx.DLL é geralmente a última na lista de classe e recursos.MFCxx.DLL inclui todos os recursos padrão do MFC, incluindo seqüências de caracteres de prompts para todas as identificações de comando padrão.Colocando-a na cauda da lista permite que as DLLs e o próprio aplicativo de cliente não tenha um sua própria cópia de recursos padrão do MFC, mas ao confiar em recursos compartilhados no MFCxx.DLL em vez disso.
Mesclando os recursos e os nomes de classe de todas as DLLs no espaço de nome do aplicativo cliente tem a desvantagem que têm cuidado quais identificações ou nomes que você escolher.Você pode obviamente desativar esse recurso não exportando ou seus recursos ou um CDynLinkLibrary o objeto para o aplicativo cliente.O DLLHUSK exemplo gerencia o espaço de nome do recurso compartilhado usando vários arquivos de cabeçalho.Consulte técnico nota 35 para obter mais dicas sobre como usar arquivos de recurso compartilhado.
Inicializando a DLL
Como mencionado acima, você geralmente deseja criar um CDynLinkLibrary objeto para exportar suas classes e recursos para o aplicativo cliente.Você precisará fornecer um ponto de entrada exportado para inicializar a DLL.No mínimo, isso é uma rotina void que não requer argumentos e não retorna nada, mas pode ser que desejar.
Cada aplicativo cliente que quer usar sua DLL deve chamar a rotina de inicialização, se você usar essa abordagem.Isso também pode alocar CDynLinkLibrary de objeto no seu DllMain depois de chamar o AfxInitExtensionModule.
A rotina de inicialização deve criar um CDynLinkLibrary objeto no heap do aplicativo atual, com fio para sua informação de DLL de extensão.Isso pode ser feito com o seguinte:
extern "C" extern void WINAPI InitXxxDLL()
{
new CDynLinkLibrary(extensionDLL);
}
O nome de rotina, InitXxxDLL neste exemplo, pode ser qualquer coisa que você deseja.Ele não precisa ser extern "C", mas fazendo assim torna mais fácil manter a lista de exportação.
Observação |
---|
Se você usar a extensão DLL por uma DLL regular, você deve exportar essa função de inicialização.Esta função deve ser chamada de DLL normal antes de usar quaisquer classes da DLL de extensão ou recursos. |
Exportar entradas
A maneira simple de exportar suas classes é usar __declspec(dllimport) e __declspec(dllexport) em cada classe e a função global que deseja exportar.Isso torna muito mais fácil, mas é menos eficiente do que a nomeação de cada ponto de entrada (descrito abaixo) desde que você tem menos controle sobre quais funções são exportadas e não é possível exportar funções por ordinal.TESTDLL1 e TESTDLL2 usam este método para exportar suas entradas.
São um método mais eficiente (e o método usado pelo MFCxx.DLL) exportar cada entrada manualmente, nomeando cada entrada do.Arquivo DEF.Como podemos exportar seletivas exportações de nossa DLL (ou seja, não tudo), podemos deve decidir quais interfaces específicas que deseja exportar.Isso é difícil, pois você deve especificar nomes desconfigurados para o vinculador na forma de entradas na.Arquivo DEF.Não exporte qualquer classes C++, a menos que você realmente precisa ter um link simbólico para ele.
Se você tiver tentado exportar C++ classes com um.DEF arquivo antes, talvez você queira desenvolver uma ferramenta para gerar automaticamente a essa lista.Isso pode ser feito usando um processo de link de dois estágios.Vincular sua DLL uma vez com nenhuma exportações e permitir que o vinculador gerar um.Arquivo de mapa.O.Arquivo de mapa pode ser usado para gerar uma lista de funções que devem ser exportados para com alguns reorganização, ele pode ser usado para gerar entradas de exportação para o.Arquivo DEF.Exportar lista para MFCxx.DLL e o OLE e DLLs de extensão do banco de dados, milhares em número, foi gerada com um processo (embora ele não é totalmente automático e requer alguns mão ajuste de vez em quando).
CWinApp vs.CDynLinkLibrary
Uma DLL de extensão do MFC não tem um CWinApp-derivado objeto próprio; em vez disso, deve trabalhar com o CWinApp-derivado de objeto do aplicativo cliente.Isso significa que o aplicativo cliente possui a bomba de mensagem principal, o loop ocioso e assim por diante.
Se sua DLL de extensão do MFC precisa manter dados extras para cada aplicativo, você pode derivar uma nova classe de CDynLinkLibrary e crie-o a InitXxxDLL a rotina de descrever acima.Quando executado, a DLL pode verificar a lista do aplicativo atual de CDynLinkLibrary objetos para encontrar uma que determinada extensão DLL.
Usando recursos na sua implementação de DLL
Como mencionado acima, a carga de recursos padrão vai orientá-lo da lista de CDynLinkLibrary objetos procurando primeiro EXE ou DLL que possui o recurso solicitado.Todas as APIs do MFC, bem como todo o código interno usa AfxFindResourceHandle para percorrer a lista de recursos para localizar qualquer recurso, não importa onde resida.
Se você deseja carregar somente os recursos de um local específico, use as APIs AfxGetResourceHandle e AfxSetResourceHandle salvar alça antiga e definir a nova alça.Certifique-se de restaurar o identificador de recurso antigo antes de retornar para o aplicativo cliente.O exemplo TESTDLL2 usa essa abordagem para carregar explicitamente um menu.
Percorrer a lista tem desvantagens que é ligeiramente mais lenta e requer gerenciamento de intervalos de ID do recurso.Ele tem a vantagem que um aplicativo cliente com links para várias DLLs de extensão pode usar qualquer recurso fornecido DLL sem ter que especificar o identificador de instância DLL.AfxFindResourceHandleuma API é usada para percorrer a lista de recursos para procurar uma determinada correspondência.Ele leva o nome e um tipo de recurso e retorna o identificador de recurso onde foi encontrado primeiro (ou nulo).
Escrever um aplicativo que usa a versão DLL
Requisitos do aplicativo
Um aplicativo que usa a versão compartilhada do MFC deve seguir algumas regras simples:
Ele deve ter um CWinApp de objeto e siga as regras padrão para uma bomba de mensagem.
Ele deve ser compilado com um conjunto de sinalizadores de compilador necessária (veja abaixo).
Ele deve vincular com bibliotecas de importação MFCxx.Definindo os sinalizadores de compilador necessárias, os cabeçalhos MFC determinam em tempo de link que biblioteca o aplicativo deve vincular com.
Para executar o arquivo executável, MFCxx.DLL deve estar no caminho ou no diretório de sistema do Windows.
Criando com o ambiente de desenvolvimento
Se você estiver usando o makefile interno com a maioria dos padrões padrão, você pode alterar facilmente o projeto para criar a versão da DLL.
A etapa a seguir pressupõe que você tenha um aplicativo MFC está funcionando corretamente vinculado com NAFXCWD.LIB (para depuração) e NAFXCW.LIB (para o varejo) e deseja convertê-lo para usar a versão compartilhada da biblioteca MFC.Você está executando o ambiente do Visual C++ e tem um arquivo de projeto interno.
- Sobre o projetos menu, clique em Propriedades.No Geral página em Padrões de projeto, defina o Microsoft Foundation Classes para Usar MFC em uma DLL compartilhada (MFCxx(d).dll).
Criando com NMAKE
Se você estiver usando o recurso externo makefile do Visual C++ ou estiver usando NMAKE diretamente, você terá que editar o makefile para dar suporte a compilador e vinculador opções
Sinalizadores de compilador necessárias:
- / /MD D_AFXDLL
/ D_AFXDLL
Os cabeçalhos MFC padrão precisam esse símbolo ser definido:
- /MD
O aplicativo deve usar a versão DLL da biblioteca de tempo de execução c
Todos os outros sinalizadores de compilador siga os padrões MFC (por exemplo, Debug para depuração).
Edite a lista de vinculador de bibliotecas.Alterar NAFXCWD.LIB para MFCxxD.LIB e alterar o NAFXCW.LIB para MFCxx.LIB.Substitua LIBC.LIB com MSVCRT.LIB.Como com qualquer outra biblioteca MFC é importante MFCxxD.LIB é colocado antes de quaisquer bibliotecas de tempo de execução C.
Opcionalmente adicionar /D_AFXDLL para o varejo e depuração opções do compilador de recurso (aquele que realmente compila recursos com /R).Isso torna seu executável final menores compartilhando recursos que estão presentes nas DLLs MFC.
Uma reconstrução completa é necessária após essas alterações são feitas.
Criação de amostras
A maioria dos programas de exemplo MFC pode ser construída a partir de Visual C++ ou um MAKEFILE NMAKE-compatível compartilhado a partir da linha de comando.
Para converter qualquer desses exemplos para usar MFCxx.DLL, você pode carregar o.MAK arquivo em Visual C++ e defina as opções de projeto conforme descrito acima.Se você estiver usando compilação NMAKE, você pode especificar "AFXDLL = 1" no NMAKE a linha de comando e que irá criar o exemplo usando as bibliotecas MFC compartilhadas.
O exemplo MFC avançado conceitos DLLHUSK criado com a versão da DLL do MFC.Esta amostra não apenas ilustra como criar um aplicativo vinculado com MFCxx.DLL, mas ele também ilustra a outros recursos da opção de empacotamento DLL do MFC, como descrito mais adiante nesta nota técnica de DLLs de extensão MFC.
Notas de embalagem
A versão de varejo de DLLs (MFCxx [U].DLL) são livremente redistribuível.A versão de depuração das DLLs não são redistribuível gratuitamente e devem ser usados somente durante o desenvolvimento do seu aplicativo.
Depurar DLLs são fornecidos com informações de depuração.Usando o depurador do Visual C++, você pode rastrear a execução de seu aplicativo, bem como a DLL.Versão DLLs (MFCxx [U].DLL) não contêm informações de depuração.
Se você personalizar ou recriar as DLLs, em seguida, você deve chamar eles algo diferente de arquivo "MFCxx" O MFC SRC MFCDLL.MAK descreve as opções de compilação e contém a lógica para renomear a DLL.Renomear os arquivos é necessário, pois essas DLLs potencialmente são compartilhadas por vários aplicativos MFC.Ter sua versão personalizada do MFC DLLs substituir aqueles instalados no sistema podem quebrar outro aplicativo MFC usando as DLLs de MFC compartilhada.
Não é recomendável recriar as DLLs do MFC.
Como o MFCxx.DLL É implementado
A seção a seguir descreve como a DLL do MFC (MFCxx.DLL e MFCxxD.DLL) é implementada.Compreender que os detalhes aqui também não são importantes se tudo o que você deseja fazer é usar a DLL do MFC com o aplicativo.Detalhes aqui não são essenciais para a compreensão de como escrever uma DLL de extensão do MFC, mas compreender essa implementação pode ajudá-lo a escrever sua própria DLL.
Visão geral da implementação
DLL da MFC é realmente um caso especial de uma DLL de extensão do MFC conforme descrito acima.Ele tem um grande número de exportações para um grande número de classes.Existem algumas coisas adicionais fazemos na DLL da MFC que tornam ainda mais especiais de uma DLL de extensão regular.
Win32 faz a maior parte do trabalho
A versão de 16 bits do MFC necessário um número de técnicas especiais, incluindo dados-app no segmento de pilha, segmentos especiais criados pelo código 80x86 assembly, contextos de exceção por processo e outras técnicas.Win32 suporta diretamente os dados por processo em uma DLL, que é o que você deseja que a maioria do tempo.A maior parte MFCxx.DLL é apenas NAFXCW.LIB empacotado em uma DLL.Se você examinar o código-fonte do MFC, você encontrará _AFXDLL # ifdef muito poucas, já que há muito poucos casos especiais que precisam ser feitas.Casos especiais que existem especificamente lidar com o Win32 no Windows 3.1 (também conhecido como Win32s).Win32s não não suporte por processo DLL dados diretamente assim a DLL do MFC devem usar o armazenamento de thread local (TLS) APIs do Win32 para obter dados de processo local.
Impacto na biblioteca de fontes, arquivos adicionais
O impacto do _AFXDLL versão em cabeçalhos e as fontes de biblioteca de classe do MFC normal é relativamente pequenos.Há um versão especial de arquivo (AFXV_DLL.H), bem como um arquivo de cabeçalho adicional (AFXDLL_.H) incluídos por AFXWIN principal.Cabeçalho H.AFXDLL_.Inclui o cabeçalho de h o CDynLinkLibrary classe e outros detalhes de implementação de ambos _AFXDLL aplicativos e DLLs de extensão do MFC.AFXDLLX.Cabeçalho h é fornecido para a criação de DLLs de extensão do MFC (veja os detalhes acima).
As fontes regulares para a biblioteca MFC no MFC SRC tem código condicional adicional sob o _AFXDLL # ifdef.Um arquivo de origem adicionais (DLLINIT.CPP) contém o código de inicialização DLL extra e outro glue para a versão compartilhada do MFC.
Para criar a versão compartilhada do MFC, arquivos adicionais são fornecidos.(Consulte abaixo para obter detalhes sobre como criar a DLL.)
Dois.Arquivos de definição são usados para exportar os pontos de entrada de DLL do MFC para depuração (MFCxxD.DEF) e solte (MFCxx.DEF) versões da DLL.
Um arquivo.Arquivo RC (MFCDLL.RC) contém todos os recursos padrão do MFC e um recurso VERSIONINFO para a DLL.
A.Arquivo CLW (MFCDLL.CLW) é fornecido permitir navegação o MFC classes usando ClassWizard.Observação: este recurso não é específico para a versão da DLL do MFC.
Gerenciamento de memória
Um aplicativo usando o MFCxx.DLL usa um alocador de memória comuns fornecido pela MSVCRTxx.DLL, compartilhada DLL C runtime.Bem como as DLLs de MFC próprios, quaisquer DLLs de extensão e o aplicativo usam esse alocador de memória compartilhada.Usando uma DLL compartilhada para alocação de memória, as DLLs de MFC pode alocar memória que posteriormente é liberada pelo aplicativo ou vice-versa.Como o aplicativo e a DLL devem usar o mesmo alocador, você não deve substituir C++ global operator new ou operator delete.Aplicarem as mesmas regras para o resto das rotinas de alocação de memória de tempo de execução C (como malloc, realloc, livree outros).
Ordinais e __declspec(dllexport) de classe e DLL de nomeação
Não usamos o class**__declspec(dllexport)** a funcionalidade do compilador C++.Em vez disso, uma lista de exportações está incluída com as fontes de biblioteca de classe (MFCxx.DEF e MFCxxD.DEF).Somente esses selecione conjunto de pontos de entrada (funções e dados) são exportados.Outros símbolos, como funções de implementação privada do MFC ou classes, não são exportados todas as exportações são feitas por ordinal sem um nome de seqüência de caracteres na tabela de nomes residentes ou não residentes.
Usando class**__declspec(dllexport)** pode ser uma alternativa viável para a criação de DLLs menores, mas no caso de uma DLL grande como o MFC, o mecanismo de exportação padrão tem capacidade e eficiência de limites.
Isso significa que todas as novidades que estamos pode empacotar uma grande quantidade de recursos da versão MFCxx.DLL é apenas cerca de 800 KB sem comprometer muito execução ou carregar velocidade.MFCxx.DLL teria sido 100K maiores essa técnica não tem sido usado.Isso também torna possível adicionar pontos de entrada adicionais no final da.Arquivo DEF para permitir o controle de versão simple sem comprometer a eficiência da velocidade e tamanho de exportação de ordinal.Revisões de versão principal da biblioteca de classe do MFC irá alterar o nome da biblioteca.Ou seja, MFC30.DLL é a DLL redistribuível que contém a versão 3.0 da biblioteca de classes do MFC.Uma atualização dessa DLL, digamos, em um hipotético 3.1 MFC, a DLL seria nomeada MFC31.DLL em vez disso.Novamente, se você modificar o código-fonte do MFC para produzir uma versão personalizada da DLL da MFC, use um nome diferente (e preferencialmente sem "MFC") no nome.