Esta anotação 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 normais, consulte Usando o MFC como parte de uma DLL.
Esta anotação técnica abrange três aspectos das DLLs. Os dois últimos são para os usuários mais avançados:
Se você está interessado em construir uma DLL usando MFC que pode ser usado com aplicativos não-MFC (isso é chamado de uma DLL regular), consulte o técnico Nota 11.
Visão geral do suporte MFCxx. dll: arquivos e terminologia
DLL Regular: usar uma DLL regular parComCompilação uma DLL autônoma usando algumas das classes MFC. Interfaces em que o limite do App/DLL são interfaces de "C", e o aplicativo cliente não tem de ser um aplicativo do MFC.
Esta é a versão da DLL suporte suportada no MFC 1.0. Ele está descrito na técnica Nota 11 e MFC Avançado conceitos exemplo DLLTRACE.
&Notanbsp; Como do Visual C++ versão 4.0, o termo USRDLL é obsoleto e foi substituído por uma DLL regular que vincula estaticamente a MFC. Você também pode criar uma DLL regular que vincula dinamicamente a MFC.
MFC 3.0 (ou superior) oferece suporte a DLLs regulares com todas as funcionalidades novas 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 (descrito abaixo) e um aplicativo cliente ou DLL dinamicamente conecta as DLLs que ele necessita. Interfaces em que o limite de aplicação/DLL são C + c++ / interfaces de classe do MFC. O aplicativo cliente deve ser um aplicativo do MFC. Isso oferece suporte a todas as funcionalidades do MFC 3.0 (excption: UNICODE não é suportado para as classes de banco de dados).
&Notanbsp; Como do Visual C++ versão 4.0, esse tipo de DLL é referido como uma "extensão DLL."
Isso Anotação usará MFCxx. dll para se referir a todo o conjunto de DLL do MFC, que inclui:
&Notanbsp; O MFCSxx [U] [D].LIB bibliotecas são usadas em conjunto com o MFC compartilhada DLLs. Essas bibliotecas contêm código que deve estar vinculado estaticamente para o aplicativo ou DLL.
Um aplicativo links para as bibliotecas de importação correspondente:
"Uma DLL de extensão do MFC" é uma DLL construída sobre MFCxx. dll (e/ou a outro MFC compartilhada DLLs). Aqui a arquitetura de componentes do MFC nos chutes. Se você deriva uma classe útil de uma classe do MFC, ou construir outro MFC-como toolkit, você pode colocá-lo em uma DLL. Que DLL usará MFCxx. dll, como faz o aplicativo do cliente final. Isso permite que classes reutilizáveis folha, reutilizáveis classes base e classes de documento/Exibir reutilizável.
&Notanbsp; Não é necessário vincular com os MFCOxx [U] D, D MFCDxx [U] ou MFCNxx [U] D Depurar bibliotecas a menos que seu aplicativo usa o MFC/OLE, banco de dados ou classes de rede respectivamente.
Prós e contras
Por que você deve usar a versão compartilhada do MFC?
Por que você não deve usar a versão compartilhada do MFC:
Uma DLL de extensão MFC é uma DLL que contém classes e funções escritas para embelezar a funcionalidade das classes MFC. O suporte de depuração OLE e banco de dados de DLLs (MFCOxxD.DLL e MFCDxxD) são exemplos de extensão do MFC DLLs em que eles usam MFCxxD. dll. Uma DLL de extensão MFC usa as DLLs do MFC compartilhada da mesma forma que um aplicativo usa-lo, com algumas considerações adicionais:
Estas considerações são descritas mais detalhadamente abaixo. Você deve se referir a MFC Avançado conceitos exemplo DLLHUSK desde que ele ilustra
O aplicativo cliente e as DLLs de extensão devem usar a mesma versão do MFCxx. dll. Você deverá seguir a Convenção de DLL do MFC e fornecer ambos depuração e varejo (/ versão) versão de sua extensão DLL. Isso permite que programas cliente para construir versões de depuração e varejo de seus aplicativos e vinculá-los com o adequado Depurar ou versão de varejo do todas as DLLs.
&Notanbsp; Devido a C++ nome desconfiguração e exportação edição, lista Exportar de uma DLL de extensão pode ser diferente entre as versões de depuração e varejo de DLL o mesmo e as DLLs para diferentes plataformas. O varejo MFCxx. dll tem cerca de 2000 exportados pontos de entrada; o debug MFCxxD. dll tem cerca de 3000 exportados pontos de entrada.
Nota rápida sobre gerenciamento de memória
A seção intitulada "Memory Management", perto do final da presente nota técnica, descreve a implementação do 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 de cliente usará o mesmo alocador de memória, carga de recursos e outros Estados "globais" de MFC como se estivessem no mesmo aplicativo. Isso é significativo porque as bibliotecas não - DLL do MFC e regulares DLLs vinculadas estaticamente a MFC fazem exatamente o oposto e tem cada atribuição de DLL fora do seu próprio pool de memória.
Se uma extensão DLL aloca memória, que a memória pode misturar livremente com qualquer outro objeto alocado pelo aplicativo. Além disso, se um aplicativo que usa as bibliotecas MFC compartilhadas falha, a proteção do sistema operacional irá manter a integridade de qualquer outro aplicativo de MFC 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 MFC bem como MFCxx. DLL próprio.
Criando uma DLL de extensão
Você pode usar AppWizard para criar um projeto de DLL de extensão MFC, e ele irá gerar automaticamente o apropriado do compilador e vinculador configurações. Foi também gerar uma função de DllMain que você pode modificar.
Se você estiver convertendo um projeto existente para uma DLL de extensão MFC, começar com as regras padrão para a construção de um aplicativo usando a versão compartilhada do MFC, em seguida, faça o seguinte:
Alterando seus arquivos de cabeçalho
O objetivo da extensão DLL geralmente é exportar algumas funcionalidades comuns para um ou mais aplicativos que podem usar essa funcionalidade. Isso se resume a exportar classes e funções global que estão disponíveis para os aplicativos de cliente.
Para fazer isso você deve garantir que cada uma das funções de membro está marcada como importar ou exportar como apropriado. Isto requer declarações de especiais: dllexport e __declspec(dllimport). Quando suas classes são usadas pelos aplicativos cliente, você quer que eles para ser declarado como __declspec(dllimport). Quando a extensão DLL propriamente dito está sendo construída, eles devem ser declarados como dllexport. Além disso, as funções devem ser efectivamente exportadas, para que os programas de cliente vincular a eles em tempo de carregamento.
Para exportar sua classe inteira, use AFX_EXT_CLASS na definição de classe. Essa macro é definida pela estrutura como dllexport quando AFXDLL e AFXEXT é definido, mas definido como __declspec(dllimport) quando AFXEXT não está definido. AFXEXT conforme descrito acima, só é definido quando estiver criando sua extensão DLL. Por exemplo:
classe AFX_EXT_CLASS CExampleExport: público CObject
{... classe definição...}
Não exportando a classe inteira
Às vezes você pode querer exportar apenas necessários Membros individuais da sua classe. Por exemplo, se você estiver exportando um CDialog-derivado classe, talvez você só precise exportar o Construtor e chamar DoModal . Você pode exportar esses membros usando a DLL.Arquivo DEF, mas você também pode usar AFX_EXT_CLASS praticamente da mesma maneira na individuais membros que você precisa exportar.
Por exemplo:
classe CExampleDialog: público CDialog
{
público:
AFX_EXT_CLASS CExampleDialog();
AFX_EXT_CLASS int DoModal();
/ / rest da definição de classe
.
.
.
}
Quando você fizer isso, você pode ter um problema adicional devido ao fato de que você já não estiver exportando todos os membros da classe. O problema é na forma como esse trabalho de macros do MFC. Várias das macros de auxiliar do MFC efectivamente declaram ou Definirm os membros de dados. Portanto, esses membros de dados também precisará ser exportados da sua DLL.
Por exemplo, a macro DECLARE_DYNAMIC é definida da seguinte maneira quando estiver criando uma DLL de extensão:
# define DECLARE_DY&NAMIC(class_name) \
protegido: \
nbsp; estático CRuntimeClass * PASCAL _GetBaseClass(); \
público: \
classe estática de CRuntimeClass AFX_DATA # # class_name; \
virtual CRuntimeClass * GetRuntimeClass() const; \
A linha que começa "estático AFX_DATA" é declarar um objeto estático dentro de sua classe. Exportar corretamente essa classe 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 de AFX_DATA, você só precisa definir AFX_DATA para ser dllexport ao criar sua DLL e defini-lo como __declspec(dllimport) quando estiver criando seu cliente executável.
Como discutido acima, AFX_EXT_CLASS já está definido dessa maneira. Assim, você só precisará redefinir AFX_DATA a ser o mesmo como AFX_EXT_CLASS em torno de sua definição de classe.
Por exemplo:
nbsp; # undef AFX_DATA
# define AFX_DATA AFX_EXT_CLASS
Classe CExampleView: público CView
{
DECLARE_DY&NAMIC()
/ /... definição de classe...
};
# undef AFX_DATA
# define AFX_DATA
MFC sempre usa o símbolo AFX_DATA em itens de dados que define dentro de suas macros, por isso essa técnica funcionará para todos esses cenários. Por exemplo, ele vai trabalhar para DECLARE_MESSAGE_MAP.
&Notanbsp; Se você estiver exportando a classe inteira em vez de membros selecionados da classe, os membros de dados estáticos são exportados automaticamente.
Você pode usar a mesma técnica para exportar automaticamente o operador de extração CArchive para classes que usam as DECLARE_SERIAL e IMPLEMENT_SERIAL macros. O operador de arquivo de exportação por triangulação as declarações de classe (localizado na.Arquivo H) com o seguinte código:
# undef AFX_API
# define AFX_API AFX_EXT_CLASS
lt; suas declarações de classe aqui >
# undef AFX_API
# define AFX_API
Limitações do AFXEXT
Você pode usar o símbolo de pré-processador do _AFXEXT para 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 das classes em sua própria extensão DLLs, que, em seguida, derivam das classes MFC, você deve usar seu símbolo de pré-processamento para evitar ambigüidade.
O problema é que no Win32, você deve explicitamente declarar todos os dados como dllexport se for para ser exportada de uma DLL e __declspec(dllimport) se for ser importado de uma DLL. Quando você define AFXEXT, os cabeçalhos MFC certifique-se de que AFX_EXT_CLASS está definido corretamente.
Quando você tem várias camadas, um símbolo, como AFX_EXT_CLASS não é suficiente, uma vez que uma DLL de extensão pode ser Exportando classes novas, bem como importação de outras classes de outra extensão DLL. Para resolver este problema, use um símbolo de pre-Processor especial que indica que você está construindo a DLL propriamente dito versus usando a DLL. Por exemplo, imagine DLLs de extensão dois arquivo a. dll e b. dll. Cada um deles exportar algumas classes em A.H e B.H, respectivamente. B. dll usa as classes de arquivo a. dll. Os arquivos de cabeçalho poderia ser algo como isto:
/ / A.H
# ifdef A_IMPL
# define CLASS_DECL_A dllexport
# else
# define CLASS_DECL_A __declspec(dllimport)
# endif
CLASS_DECL_A CExampleA de classe: CObject pública
{...... definição de classe};
/ / B.H
# ifdef B_IMPL
# define CLASS_DECL_B dllexport
# else
# define CLASS_DECL_B __declspec(dllimport)
# endif
Classe CLASS_DECL_B CExampleB: CExampleA pública
{... definição de classe...}
Quando arquivo 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, CExampleB é exportada e CExampleA é importado quando edifício b. dll. CExampleA é exportado durante a criação de arquivo a. dll e importado quando usado por b. dll (ou algum outro cliente).
Este tipo de disposição em camadas não pode ser feito usando os símbolos de pre-Processor AFX_EXT_CLASS e AFXEXT built-in. A técnica descrita acima resolve esse problema de uma forma não ao contrário, que o mecanismo de MFC próprio usa quando estiver criando suas DLLs de extensão OLE, banco de dados e rede.
Não exportando a classe inteira
Novamente você terá que tomar um cuidado especial quando você não estiver exportando uma classe inteira. Você deve garantir que os itens de dados necessários criados pelas macros MFC são exportados corretamente. Isso pode ser feito por re-definindo o AFX_DATA a macro de sua classe específica. Isso deve ser feito a qualquer momento que você não estiver exportando a classe inteira.
Por exemplo:
/ / A.H
# ifdef A_IMPL
nbsp; # define CLASS_DECL_A _declspec(dllexport)
# else
# define CLASS_DECL_A _declspec(dllimport)
# endif
# undef AFX_DATA
# define AFX_DATA CLASS_DECL_A
CExampleA de classe: CObject pública
{
DECLARE_DY&NAMIC()
CLASS_DECL_A int SomeFunction();
//Class definição.
.
.
};
# 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 sua extensão DLL. Ele deve vir depois que o padrão inclui. Observe que quando você usar AppWizard para criar arquivos de inicialização para uma extensão DLL, ele fornece um DllMain para você.
# include "afxdllx.h"
extensionDLL AFX_EXTE&NSION_MODULE estático;
extern "C" int APIENTRY DllMain (HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
nbsp; se (dwReason = = DLL_PROCESS_ATTACH)
{
/ / Inicialização única de DLL de extensão se (!AfxInitExtensionModule (
extensionDLL, hInstance))
return 0;
/ / TODO: executar outras tarefas de inicialização aqui
}
else if (dwReason = = DLL_PROCESS_DETACH)
{
/ / Extensão DLL por processo de rescisão
AfxTermExtensionModule(extensionDLL);
/ / TODO: executar outras tarefas de limpeza aqui
}
retornar 1; / / ok
}
A chamada AfxInitExtensionModule captura as classes módulos de tempo de execução (estruturas deCRuntimeClass ), bem como suas fábricas de objeto (objetos deCOleObjectFactory ) para uso posterior quando o objeto de CDynLinkLibrary é criado. A chamada AfxTermExtensionModule (opcional) permite MFC para limpeza a extensão DLL quando cada processo desanexa (o que acontece quando o processo é encerrado ou quando a DLL é descarregada como resultado de um chamar FreeLibrary ) da extensão DLL. Desde a maioria extensão DLLs não são dinamicamente carregados (geralmente, eles são vinculados através de suas bibliotecas de Importarar), a chamada AfxTermExtensionModule geralmente não é necessária.
Se seu aplicativo carrega e libera DLLs de exte&nsão dinamicamente, certifique-se de chamar AfxTermExtensionModule como mostrado above.nbsp; Além disso, certifique-se de usar AfxLoadLibrary e AfxFreeLibrary (em vez do Win32 funções LoadLibrary e FreeLibrary) se seu aplicativo usa Múltiplo segmentos. Usando AfxLoadLibrary e AfxFreeLibrary garante que o código de inicialização e desligamento que executa quando a extensão DLL é carregada e descarregada não corrompe o estado global do MFC.
O arquivo de cabeçalho AFXDLLX.H contém definições especiais para estruturas usadas em extensão DLLs, tais 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 este tempo, uma vez que o MFCxx. dll estiver totalmente inicializado pelo tempo que seus DllMain é chamado.
Compartilhamento de recursos e Classes
DLLs de extensão MFC simples só precisam exportar algumas funções de baixa largura de banda para o aplicativo cliente e nada mais. Mais DLLs intensivo de interface do usuário talvez queiram exportar classes C++ e recursos para o aplicativo cliente.
Exportação de recursos é feito através de uma lista de recursos. Em cada aplicativo é uma lista vinculada separada de CDynLinkLibrary objetos. Quando à procura de um recurso, a maioria das implementações padrão MFC que carregar recursos olham primeiros no módulo recurso atual (AfxGetResourceHandle) e se a lista de objetos CDynLinkLibrary tentar carregar o recurso solicitado não foi encontrada a pé.
Criação dinâmica de objetos de C++ recebe um nome de classe do C++ é semelhante. O mecanismo de desserialização do objeto MFC precisa ter todos os objetos de CRuntimeClass registrados para que possa reconstruir, criando dinamicamente C++ objeto do tipo exigido com base no que foi armazenado anteriormente.
Se desejar que o aplicativo cliente para usar classes em sua extensão DLL que são DECLARE_SERIAL, você precisará exportar suas classes para ser visível para o aplicativo cliente. Isso também é feito percorrendo a lista de CDynLinkLibrary.
No caso do MFC Avançado conceitos exemplo DLLHUSK, a lista é algo como
cabeça - > DLLHUSK.EXE - ou - DLLHUSK.EXE
| |
TESTDLL2.DLL TESTDLL2.DLL
| |
TESTDLL1.DLL TESTDLL1.DLL
| |
MFCO42D.DLL |
| |
MFCD42D.DLL |
| |
MFC42D.DLL MFC42.DLL
O MFCxx. dll é normalmente passada sobre o recurso e a lista de classe. 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. Colocá-lo na cauda da lista permite que os DLLs e o próprio aplicativo de cliente não ter a sua própria cópia dos recursos do MFC padrão, mas ao contar com os recursos compartilhados no MFCxx. dll em vez disso.
Mesclar os recursos e os nomes de classe de todas as DLLs no espaço de nome do aplicativo cliente tem a desvantagem de que você tem que ter cuidado quais identificações ou nomes que você escolhe. Naturalmente você pode desativar esse recurso, não exportando seus recursos ou um objeto de CDynLinkLibrary para o aplicativo cliente. O exemplo DLLHUSK gerencia o espaço de nome de recurso compartilhado usando Múltiplo arquivos de cabeçalho. Consulte 35 observação técnica para obter mais dicas sobre como usar arquivos de recurso compartilhado.
Inicializando a DLL
Como mencionado acima, você geralmente deseja criar um objeto de CDynLinkLibrary 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 nula que não leva argumentos e não retorna nada, mas pode ser qualquer coisa que você gosta.
Cada aplicativo do cliente que quer usar sua DLL deve chamar esta rotina de inicialização, se você usar essa abordagem. Você também pode atribuir esse objeto de CDynLinkLibrary em seus DllMain apenas depois de chamar AfxInitExtensionModule.
A rotina de inicialização deve criar um objeto de CDynLinkLibrary no heap do aplicativo atual, com fio até a sua informação de DLL de extensão. Isso pode ser feito com a seguinte:
extern "C" de extern void InitXxxDLL() WI&NAPI
{
nbsp; novo CDynLinkLibrary(extensionDLL);
}
O nome de rotina, InitXxxDLL neste exemplo, pode ser qualquer coisa que você quer. Não precisa ser extern “C” , mas fazendo assim faz a lista de exportação mais fácil de manter.
&Notanbsp; Se você usar sua extensão DLL de uma DLL regular, você deve exportar essa função de inicialização. Esta função deve ser chamada de DLL normal antes de usar qualquer extensão DLL classes ou recursos.
Exportação de inscrições
A maneira simple de exportar suas classes é usar __declspec(dllimport) e dllexport em cada classe e a função global que deseja exportar. Isso torna muito mais fácil, mas é menos eficiente que nomeando cada ponto de entrada (descrito abaixo), uma vez que você tem menos controle sobre quais funções exportadas e não é possível exportar funções por ordinal. Este é o método que TESTDLL1 e TESTDLL2 usam para exportar suas entradas.
Um método mais eficiente (e o método usado pelo MFCxx. dll) são exportar cada entrada manualmente, nomeando cada entrada no.Arquivo DEF. Uma vez que estamos a exportar exportação seletiva de nossa DLL (isto é, não tudo), precisamos decidir quais interfaces determinados queremos exportar. Isso é difícil, pois você deve especificar os nomes desconfigurados para o vinculador em forma de entradas na.Arquivo DEF. Não exporte quaisquer classes de C++, a menos que você realmente precisa ter um link simbólico para ele.
Se você já tentou exportar C++ classes com um.DEF arquivo antes, você pode querer desenvolver uma ferramenta para gerar automaticamente a essa lista. Isso pode ser feito usando um processo de ligação de dois estágios. Vincular sua DLL uma vez com nenhuma das exportações, e permitir que o vinculador a gerar um.Arquivo de mapa. O.Arquivo de mapa pode ser usado para gerar uma lista de funções que devem ser exportadas, assim com alguns munging, ele pode ser usado para gerar suas entradas de exportação para o seu.Arquivo DEF. A lista de exportação para MFCxx. dll e o OLE e DLLs de extensão de banco de dados, vários milhares em número, foi gerada com esse processo (embora não é completamente automático e requer alguma mão ajuste de vez em quando).
CWinApp vs. CDynLinkLibrary
Uma DLL de extensão MFC não possui um CWinApp-derivado objeto próprio; em vez dele deve funcionar com o CWinApp-derivado objeto do aplicativo cliente. Isso significa que o aplicativo cliente possui a bomba de mensagem principal, o loop ocioso e assim por diante.
Se a DLL de extensão do MFC deve manter dados adicionais para cada aplicativo, você pode derivar uma Novo classe de CDynLinkLibrary e criá-lo no InitXxxDLL rotina descrevem acima. Quando em execução, a DLL pode verificar lista do aplicativo atual de CDynLinkLibrary objetos para encontrar o caminho para essa determinada extensão DLL.
Utilização dos recursos na sua implementação de DLL
Como mencionado acima, a carga de recursos padrão andará a lista de objetos CDynLinkLibrary procurando o primeiro EXE ou DLL que tem o recurso solicitado. Todas as APIs do MFC, como também todo o código interno usa AfxFindResourceHandle para a lista de recursos para localizar qualquer recurso, não importa onde podem estar a pé.
Se você deseja apenas carregar recursos de um lugar específico, use as APIs AfxGetResourceHandle e AfxSetResourceHandle para salvar o antigo identificador e definir o novo identificador. Certifique-se de restaurar o antigo identificador de recurso antes de retornar para o aplicativo cliente. O exemplo TESTDLL2 usa essa abordagem para explicitamente carregar um menu.
Andando a lista tem as desvantagens que é ligeiramente mais lenta e requer Gerenciando intervalos de ID do recurso. Tem a vantagem de que um aplicativo cliente links para várias DLLs de extensão pode usar qualquer recurso desde DLL sem ter que especificar o identificador de instância DLL. AfxFindResourceHandle é um API usado para andar a lista de recursos para olhar para um determinado jogo. Ele leva o nome e o tipo de um recurso e retorna o identificador de recurso onde foi encontrada pela primeira vez (ou NULL).
Requisitos do aplicativo
Um aplicativo que usa a versão compartilhada do MFC deve seguir algumas regras simples:
Edifício 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 parComCompilação a versão DLL.
A etapa a seguir presume que você tenha um aplicativo de MFC funcionam correctamente ligado com NAFXCWD.LIB (para depuração) e NAFXCW.LIB (para venda a retalho) e você 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.
Edifício com NMAKE
Se você estiver usando o recurso externo makefile do Visual C++, ou estiver usando NMAKE diretamente, você terá que editar seu makefile para dar suporte a compilador e vinculador opções
Sinalizadores do compilador necessária:
/ /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. Mudança NAFXCWD.LIB para MFCxxD.LIB e alterar o NAFXCW.LIB para MFCxx.LIB. Adicione MFCOxx[U]D.LIB, MFCDxx[U]D.LIB e MFCNxx[U]D.LIB conforme o caso (necessário para uso do MFC/OLE, banco de dados ou classes de rede). Substitua LIBC.LIB com MSVCRT.LIB. Como com qualquer outra biblioteca de MFC, é importante que MFCxxD.LIB é colocado antes de quaisquer bibliotecas de tempo de execução c.
Opcionalmente, adicionar /D_AFXDLL para ambos seu varejo e depurar opções de compilador de recurso (aquele que realmente compila os recursos com /R). Isso torna seu executável final menor, compartilhando os recursos que estão presentes nas DLLs do MFC.
Uma reconstrução completa é exigida após essas alterações são feitas.
Os exemplos de construção
A maioria dos programas de exemplo MFC pode ser construída a partir de Visual C++ ou um MAKEFILE NMAKE-compatível compartilhado na linha de comando.
Para converter qualquer uma dessas amostras para utilizar MFCxx. dll, você pode carregar o.MAK arquivo no Visual C++ e defina as opções de projeto, como descrito acima. Se você estiver usando a compilação NMAKE, você pode especificar "AFXDLL = 1" a NMAKE, a linha de comando e que vai construir o exemplo usando as bibliotecas MFC compartilhadas.
MFC Avançado conceitos exemplo DLLHUSK é construído com a versão DLL da MFC. Este exemplo não só ilustra como ComCompilação um aplicativo ligado com MFCxx. dll, mas ele também ilustra outras características da opção de embalagem de DLL do MFC, como DLLs de extensão MFC descrito posteriormente nesta nota técnica.
Notas de embalagem
A versão de varejo das DLLs (MFCxx [U].DLL) são livremente redistribuível. A versão de Depurar de DLLs não são livremente redistribuível e deve ser usada somente durante o desenvolvimento do seu aplicativo.
A Depurar de 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. As versão DLLs (MFCxx [U].DLL) não contêm informações de depuração.
Se você personalizar ou reconstruir as DLLs, então você deve chamar-lhes algo diferente arquivo "MFCxx" The MFC SRC MFCDLL.MAK descreve opções de compilação e contém a lógica para renomear a DLL. Esta regra também se aplica ao MFC/OLE, banco de dados e rede DLLs que são construídas por MFCOLE.MAK, MFCDB.MAK e MFCNET.MAK, respectivamente. Renomear os arquivos é necessário, uma vez que essas DLLs estão potencialmente compartilhadas por vários aplicativos do MFC. Tendo sua versão das DLLs MFC personalizado substituir aqueles instalados no sistema pode quebrar a outro aplicativo do MFC usando o MFC DLLs compartilhadas.
Reconstruir as DLLs do MFC não é recomendado.
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ê quer fazer é usar a DLL do MFC com o aplicativo. Os 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óprias DLL.
Visão geral da implementação
DLL do MFC é realmente um caso especial de uma DLL de extensão MFC conforme descrito acima. Ele tem um grande número de exportações para um grande número de classes. Existem algumas coisas adicionais que fazemos na DLL do MFC que torná-lo ainda mais especial do que uma DLL de extensão regular.
Win32 faz a maior parte do trabalho
A versão de 16 bits do MFC precisava de um número de técnicas especiais, incluindo os dados por app no segmento de pilha, segmentos especiais criados por algum código de assembly de 80 x 86, contextos de exceção por processo e outras técnicas. Win32 suporta diretamente por processo dados em uma DLL, que é o que você quer na maioria das vezes. Na maior parte MFCxx. dll é apenas NAFXCW.LIB empacotado em uma DLL. Se você examinar o código-origem MFC, você encontrará muito poucos # ifdef AFXDLL, desde há muito poucos casos especiais que precisam ser feitas. Os casos especiais que estão lá são especificamente lidar com Win32 em Windows 3.1 (também conhecido como Win32s). Win32s faz não suporte por processo DLL dados directamente assim o DLL do MFC devem usar o armazenamento de thread local (TLS) APIs do Win32 para obter dados de local de processo.
Impacto nas fontes da biblioteca, arquivos adicionais
O impacto da versão AFXDLL sobre as fontes de biblioteca de classe MFC normais e cabeçalhos é relativamente menor. Há um versão especial arquivo (AFXV_DLL.H) como um arquivo de cabeçalho adicional (AFXDLL_.H) incluído por AFXWIN principal.Cabeçalho H. O AFXDLL_.H cabeçalho inclui a classe de CDynLinkLibrary e outros detalhes de implementação de aplicativos AFXDLL e DLLs de extensão MFC. O AFXDLLX.Cabeçalho h é fornecido para criar DLLs de extensão MFC (ver detalhes acima).
As fontes regulares para a biblioteca MFC no MFC SRC tem algum código condicional adicional sob o # ifdef AFXDLL . Um arquivo de código-fonte adicionais (DLLINIT.CPP) contém o código de inicialização DLL extra e outra cola para a versão compartilhada do MFC.
Para construir a versão compartilhada do MFC, arquivos adicionais são fornecidos. (Veja abaixo para obter detalhes sobre como construir a DLL).
Criando a DLL do MFC
Reconstruindo o DLL do MFC é intencionalmente difícil, então você pensa duas vezes (ou três vezes) antes de fazê-lo. Se você compreender os potenciais problemas de empacotamento e redistribuição restrições descritas abaixo e você ainda realmente precisa reconstruir a DLL do MFC, você pode.
MFCDLL.Arquivo MAK será Compilação o DLL de Depurar com informações CodeView:
NMAKE /f MFCDLL DEBUG = 1 LIBNAME = MYMFC
MFCDLL.Arquivo MAK será Compilação o DLL de versão sem informações CodeView:
NMAKE /f MFCDLL DEBUG = 0 LIBNAME = MYMFC
(da mesma forma, você usa MFCOLE.MAK, MFCDB.MAK e MFCNET.MAK para construir o MFCOxxD.DLL, MFCDxxD e MFCNxxD.DLL - as DLLs que contêm o MFC/OLE, banco de dados e classes de rede)
Este será Compilação uma versão particular do MFC DLL no seu diretório SRC MFC com os nomes padrão de MFCxx. dll e MFCxxD. dll. Você precisará copiá-los para um local apropriado em seu caminho para usar as novas DLLs. MFCDLL.MAK makefile também irá recriar as bibliotecas de Importarar (MFCxx.LIB e MFCxxD.LIB) e colocá-los no diretório LIB do MFC padrão. Isso irá substituir as bibliotecas predefinidas de MFCxx.LIB e MFCxxD.LIB, então por favor, tenha cuidado.
Se você quiser redistribuir uma versão modificada da biblioteca MFC DLL, certifique-se de alterar o nome da DLL no MFCDLL.MAK makefile e os dois.Arquivos DEF. Veja makefile MFCDLL.MAK para obter mais informações.
Você pode modificar a biblioteca e redistribuir um retalho (/ versão) de sua biblioteca modificada somente se você renomeá-lo para algo diferente de MFCxx. dll. Você não pode redistribuir a versão de Depurar de uma depuração construída predefinida ou Personalizar DLL.
Estas restrições de redistribuição são principalmente evitar a proliferação de fora do padrão e potencialmente vírus contendo DLLs. idealmente você deve não precise Recompilar as DLLs e se você redistribuir seu aplicativo com o MFCxx. dll predefinidas fornecidas com o produto do Visual C++, você evitará muitos problemas para si e para seus usuários.
Gerenciamento de memória
Um aplicativo utilizar MFCxx. dll usa um comum alocador de memória fornecido pelo MSVCRTxx.DLL, o DLL compartilhada de tempo de execução C. O aplicativo, as DLLs de extensão, bem como as DLLs do MFC, use este alocador de memória compartilhada. Usando uma DLL compartilhada para alocação de memória, as DLLs do MFC pode alocar memória que posteriormente é liberada pelo aplicativo ou vice-versa. Porque o aplicativo e a DLL devem usar o mesmo alocador, você não deve substituir o global C++ novo operador ou operador excluir. As mesmas regras aplicam-se ao resto das rotinas de alocação de memória C-tempo de execução (como malloc, realloc, livre, etc.).
Números ordinais e dllexport classe e DLL de nomeação
Nós não usamos o class dllexport funcionalidade do compilador C++. Em vez disso, uma lista das exportações está incluída com as fontes de biblioteca de classe (MFCxx.DEF e MFCxxD.DEF). Somente estes Selecionar conjunto de pontos de entrada (dados e funções) são exportados. Outros símbolos, como funções de implementação particular do MFC ou classes, não são exportados todas as exportações são feitas por ordinal sem um nome de Cadeia de caracteres na tabela de nomes residentes ou não residentes .
Usando class 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 padrão exportação mecanismo tem eficiência e capacidade limites .
O que isto significa que tudo é que nós pode empacotar uma grande quantidade de recursos da versão MFCxx. dll que é apenas cerca de 800 KBytes sem comprometer muito execução ou velocidade de carregamento. MFCxx. dll teria sido maior de 100K esta técnica não tivesse sido usado.Isso também torna possível acrescentar pontos de entrada adicionais no final da.Arquivo DEF para permitir o controle de versão simple sem comprometer a eficiência velocidade e tamanho de exportação por ordinal. Revisões de versão principal na biblioteca de classes do MFC mudará 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 MFC 3.1, o DLL seria nomeado MFC31.DLL em vez disso. Novamente, se você modificar o código-origem MFC para produzir uma versão personalizada do DLL do MFC, por favor, utilize um nome diferente (e, de preferência um sem "MFC") no nome da.
Técnico anotações por número |nbsp; &Notas técnicas por categoria