Compartilhar via


TN033: Versão DLL do MFC

Esta nota descreve como você pode usar o MFCxx.DLL e MFCxxD.DLL (onde x é o número da versão do MFC) compartilhados 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 sistema autônomo parte de uma DLL.

Esta nota técnica aborda três aspectos das DLLs.Os dois últimos são para usuários mais avançados:

  • Como você compilação uma DLL de extensão do MFC

  • Como você compilação um aplicativo MFC que usa a versão DLL do MFC

  • Como o MFC compartilhadas bibliotecas de vínculo dinâmico são implementados

Se você estiver interessado na criação de uma DLL usando o MFC que pode ser usado com aplicativos não-MFC (isso é chamado de uma DLL normal), consulte Observação técnica 11.

Visão geral do suporte MFCxx.DLL: Terminologia e arquivos

DLL comum: Você usa uma DLL regular para compilação uma DLL autônoma usando algumas das classes MFC.Interfaces entre o limite do aplicativo/DLL são interfaces de "C" e o aplicativo cliente não precisa ser um aplicativo MFC.

Esta é a versão do suporte a DLL tem suportada no MFC 1.0.Ele está descrito no Observação técnica 11 e o MFC Advanced conceitos amostra DLLScreenCap.

Observação:

sistema autônomo do Visual C++ versão 4.0, o termo USRDLL está obsoleta e foi substituído por uma DLL regular que se 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 todas as novas funcionalidades incluindo as classes OLE e banco de dados.

AFXDLL: Isso também é conhecido sistema autônomo a versão compartilhada das bibliotecas de MFC.Este é o novo suporte a DLL adicionado no MFC 2.0.A própria biblioteca MFC está em um número de DLLs (descrita abaixo) e um aplicativo cliente ou DLL dinamicamente vincula as DLLs que requer.As interfaces entre o limite do aplicativo/DLL são C + c++ / MFC interfaces de classe.O aplicativo cliente deve ser um aplicativo MFC.Isso dá suporte a toda a funcionalidade do MFC 3.0 (exceção: UNICODE não é suportada para as classes de banco de dados).

Observação:

sistema autônomo do Visual C++ versão 4.0, esse tipo de DLL é conhecido sistema autônomo um "DLL de extensão."

Esta nota usará MFCxx.DLL para fazer referência à toda a DLL da MFC definido, que inclui:

  • depurar: 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 compartilhado DLLs.Essas bibliotecas contêm código que deve ser estaticamente vinculado ao aplicativo ou DLL.

Links um aplicativo para as bibliotecas de importação correspondente:

  • depurar: MFCxxD.LIB

  • versão: MFCxx.LIB

  • depurar Unicode: MFCxxUD.LIB

  • Versão Unicode: MFCxxU.LIB

Um "MFC extensão DLL" é uma DLL construída MFCxx.DLL (e/ou Outros MFC compartilhado DLLs).É aqui a arquitetura de componente MFC ativado.Se você derivar uma classe útil de uma classe, a MFC ou compilação outro Kit de ferramentas semelhantes a MFC, é possível colocá-la em uma DLL.Que DLL usa MFCxx.DLL, sistema autônomo o aplicativo cliente final.Isso permite que classes reutilizáveis folha, reutilizáveis de classes base e classes reutilizáveis documentos/modo de exibição.

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 maior parte da biblioteca MFC é menos de 10 K).

  • A versão compartilhada do MFC oferece suporte a DLLs normais e DLLs de extensão do MFC.

  • Criando um aplicativo que usa as bibliotecas MFC compartilhadas é mais rápido do que a criação de um aplicativo MFC vinculado estaticamente porque não é necessário vincular MFC propriamente dito.Isso é especialmente verdadeiro em DEPURAR compilações onde o vinculador deve compactar as informações de depuração — por meio da vinculação 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ê use a versão compartilhada do MFC não:

  • Um aplicativo que usa a biblioteca compartilhada de envio requer que você enviar o MFCxx.DLL (e outros) biblioteca com o 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 fornecer MSVCRTxx.DLL, que contém a biblioteca C tempo de execução que é usada tanto por seu programa e as DLLs de MFC propriamente ditas.

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 de classes MFC.Uma DLL de extensão do MFC usa as DLLs de MFC compartilhado 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 compilador adicional e opções do vinculador.

  • Uma DLL de extensão do MFC não possui um CWinApp-classe derivada.

  • Uma DLL de extensão do MFC deve fornecer um especial DllMain. AppWizard fornece um DllMain função que você pode modificar.

  • Uma DLL de extensão do MFC geralmente fornecerá uma rotina de inicialização para criar um CDynLinkLibrary se a DLL de extensão desejar exportar CRuntimeClasses ou recursos para o aplicativo. Uma classe derivada de CDynLinkLibrary pode ser usado se os dados de cada aplicativo devem ser mantidos pela extensão DLL.

Essas considerações são descritas com mais detalhes abaixo.Você também deve consultar o MFC Advanced conceitos amostra DLLHUSK, pois ele ilustra:

  • Criando um aplicativo usando bibliotecas compartilhadas.(DLLHUSK.EXE é um aplicativo MFC que vincula dinamicamente bibliotecas MFC, bem sistema autônomo Outros DLLs).

  • Criando uma DLL de extensão do MFC.(Observe sistema autônomo sinalizadores especiais, sistema autônomo _AFXEXT que são usados na criação de uma DLL de extensão)

  • Dois exemplos das DLLs de extensão do MFC.Um mostra a estrutura básica de uma DLL de extensão 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.Você deve seguem a convenção da DLL da MFC e fornecer tanto uma depurar e varejo (/Release) versão da sua DLL de extensão.Isso permite que programas de cliente para criar versões de tanto depurar e varejo de seus aplicativos e vinculá-las com a depurar apropriada ou a versão comercial do todas as DLLs.

Observação:

Como o C++ desconfiguração de nomes e exportar problemas, a lista de exportação de uma DLL de extensão pode ser diferente entre as versões de depurar e varejo da mesma DLL e DLLs para diferentes plataformas.A MFC comercial xx.DLL tem aproximadamente 2000 exportados pontos de entrada; a depurar MFCxxD.DLL tem aproximadamente 3000 pontos de entrada exportado.

Anotação rápida no gerenciamento de memória

A seção intitulada "memória Management", no participante desta 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 apenas uma DLL de extensão são descritas aqui.

MFCxx.DLL e todas sistema autônomo DLLs de extensão carregadas no espaço de endereço de um aplicativo cliente usará o mesmo alocador de memória, carregamento de recurso e outros estados "global" MFC sistema autônomo se estivessem no mesmo aplicativo.Isso é significativo porque as bibliotecas de DLL não-MFC e regulares DLLs vinculadas estaticamente a MFC fazer o oposto exato e tem alocar cada DLL fora do seu próprio pool de memória.

Se uma DLL de extensão aloca memória, que a memória pode livremente misto com qualquer Outros objeto alocados por aplicativo.Além disso, se um aplicativo que usa as bibliotecas MFC compartilhadas falhar, a proteção do sistema operacional será manter a integridade de qualquer Outros aplicativo do MFC a DLL de compartilhamento.

Da mesma forma outros estados MFC "global", sistema autônomo o corrente executável carregar recursos, também são compartilhados entre o aplicativo cliente e todas sistema autônomo DLLs de extensão do MFC, bem sistema autônomo MFCxx.DLL propriamente dito.

Criação de 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 compilador apropriado.Foi também gerar um DllMain função que você pode modificar.

Se você estiver convertendo um projeto existente em uma DLL de extensão do MFC, inicie com as regras padrão para a criação de um aplicativo usando a versão compartilhada do MFC e faça o seguinte:

  • Add / D_AFXEXT aos sinalizadores de compilador.Na caixa de diálogo Propriedades da projeto, selecionar o nó C/C ++.Em seguida, selecionar a categoria de pré-processador.Add _AFXEXT campo definir macros, separando cada um dos itens com ponto-e-vírgula.

  • Remova o /Gy comutador de compilador. Na caixa de diálogo Propriedades da projeto, selecionar o nó C/C ++.selecionar a categoria de geração de código.Certifique-se de que 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 removerá funções não referenciadas.Se o projeto original é usado para compilação uma DLL regular estaticamente vinculada ao MFC, altere o /MT [d opção compilador /MD [d.

  • Criar uma biblioteca de exportar 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 sistema autônomo o tipo de destino.

Alterando os arquivos de cabeçalho

O meta de uma extensão DLL é geralmente exportar algumas funcionalidades comuns para um ou mais aplicativos que podem usar essa funcionalidade.Isso se resume à exportação de classes e funções global que estão disponível para os aplicativos cliente.

Para isso deve assegurar que cada uma das funções de membro está marcada sistema autônomo importar ou exportar conforme apropriado.Isso requer declarações especiais: __declspec(dllexport) and __declspec(DllImport).Quando sistema autônomo classes são usadas pelos aplicativos cliente, você deseja que ser declarado sistema autônomo __declspec(DllImport).Quando a extensão DLL propriamente dito está sendo criada, deve ser declarados sistema autônomo __declspec(dllexport).Além disso, as funções devem ser realmente exportadas, para que os programas clientes vinculá-las no time de carregamento.

Para exportar sua classe inteiro, use AFX_EXT_CLASS na definição de classe.Essa macro é definida pela estrutura sistema autônomo __declspec(dllexport) when _AFXDLL and _AFXEXT é definido, mas é definido sistema autônomo __declspec(DllImport) when _AFXEXT não foi definido. _AFXEXT conforme descrito acima, só é definido quando estiver criando sua DLL de extensão. Por exemplo:

class AFX_EXT_CLASS CExampleExport : public CObject
{ ... class definition ... };

Não exportar a classe inteira

Às vezes convém exportar apenas os membros necessários individuais da sua classe.Por exemplo, se você estiver exportando um CDialog-derivada da classe, você talvez só precise exportar o construtor e o DoModal Chame. Você pode exportar esses membros usando .def arquivo da DLL, mas você também pode usar AFX_EXT_CLASS da mesma forma nos membros individuais, que 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ê está exportando não mais todos os membros da classe.O problema é da forma que funcionam de macros do MFC.Várias das macros do auxiliar do MFC realmente declarar ou definem os membros de dados.Portanto, esses membros de dados também precisará ser exportados de sua DLL.

Por exemplo, a DECLARE_DYNAMIC macro é definida sistema autônomo a seguir ao criar 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 "staticAFX_DATA"é declarar um objeto estático dentro da sua classe. Para exportar essa classe corretamente e acessar informações em tempo de execução de um cliente .exe, você precisa exportar este objeto estático.Porque o objeto estático é declarado com o modificador de AFX_DATA, você precisará definir AFX_DATA a ser __declspec(dllexport) quando estiver criando sua DLL e defini-lo sistema autônomo __declspec(DllImport) durante a criação de seu executável de cliente.

sistema autônomo discutido acima AFX_EXT_CLsistema autônomoS já está definida dessa maneira.Você precisa apenas redefina AFX_DATA o mesmo sistema autônomo AFX_EXT_CLsistema autônomoS ao redor de sua definição clsistema autônomos.

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 em suas macros, então essa técnica irá funcionar para todos os cenários de tais. Por exemplo, funcionará para DECLARE_MESSAGE_MAP.

Observação:

Se você estiver exportando o classe inteira em vez de membros selecionados da classe, membros de dados estático são exportados automaticamente.

Você pode usar a mesma técnica para exportar o automaticamenteCArchive operador de extração para classes que usam o DECLARE_SERIAL e IMPLEMENT_SERIAL macros. Exporte o operador de arquivar por colchetes as declarações de classe (localizadas no arquivar .h) com o código a seguir:

#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-processador símbolo para suas DLLs de extensão, contanto que você não tenha várias camadas de DLLs de extensão.Se você tiver DLLs de extensão que telefonar ou derivar de classes em sua própria extensão DLLs, que, em seguida, derivam das classes MFC, você deve usar seu próprio símbolo de pré-processador para evitar ambigüidade.

O problema é que, em Win32, você deve declarar explicitamente todos sistema autônomo dados sistema autônomo __declspec(dllexport) se estiver a ser exportado de uma DLL e __declspec(DllImport) se estiver a ser importado de uma DLL.Quando você define _AFXEXT, os cabeçalhos MFC, certifique-se AFX_EXT_CLASS está definido corretamente.

Quando você tiver várias camadas, um símbolo, sistema autônomo AFX_EXT_CLASS não é suficiente, desde que uma DLL de extensão pode ser exportando novas classes, assim sistema autônomo a importação de outras classes de Outros extensão DLL.Para lidar com esse problema, utilize um símbolo de pré-processador especial que indica que você esteja criando a DLL em vez de usar a DLL.Por exemplo, imagine DLLs de extensão de dois, A.dll e B.dll.Cada um deles exportar algumas classes A.H e B.H, respectivamente.B.dll usa as classes de A.dll.Os arquivos de cabeçalho devem 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 é construído, ele é criado com /D A_IMPL e quando B.dll é criada, ela é criada com /D B_IMPL.Usando símbolos separados para cada DLL, CExampleB é exportada e CExampleA é importado quando estiver criando B.dll.CExampleA for exportado quando estiver criando A.dll e importado quando usado por B.dll (ou Outros cliente).

Esse tipo de disposição em camadas não pode ser concluído ao usar o interno AFX_EXT_CLASS and _AFXEXT símbolos de pré-processador. A técnica descrita acima resolve esse problema de maneira não diferentemente que o mecanismo de MFC se usa durante a criação de suas DLLs de extensão OLE, banco de dados e rede.

Não exportar a classe inteira

Novamente, você terá Tome um cuidado especial quando você não estiver exportando uma classe inteira.Você precisa garantir que os itens de dados necessários criados pelas macros MFC são exportados corretamente.Isso pode ser concluído por re-defining AFX_DATA a macro de sua classe específica.Isso deve ser concluído a qualquer momento que você está exportando não toda a turma.

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 fonte principal para a DLL de extensão.Ele deve vir depois que o padrão inclui.Observe que, quando usar AppWizard para criar arquivos de inicialização para uma DLL de extensão, ele fornece um 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 telefonar para AfxInitExtensionModule captura o (classes em tempo de execução de módulosCRuntimeClass estruturas), bem sistema autônomo seu objeto () fábricasCOleObjectFactory objetos) para uso posterior quando o CDynLinkLibrary objeto é criado.A telefonar para (opcional)AfxTermExtensionModule permite MFC para limpeza a DLL de extensão quando desliga de cada processo (que acontece quando o processo for encerrado, ou quando a DLL está descarregada sistema autônomo resultado de um FreeLibrary telefonar) da DLL de extensão.Desde a extensão a maioria das DLLs não são carregadas dinamicamente (geralmente, eles são vinculados por meio de suas bibliotecas de importação), a telefonar para AfxTermExtensionModule geralmente não é necessário.

Se seu aplicativo é carregado e libera DLLs de extensão dinamicamente, certifique-se de chamar AfxTermExtensionModule sistema autônomo mostrado acima. Também certifique-se de usar AfxLoadLibrary e AfxFreeLibrary (em vez de funções do Win32 LoadLibrary and FreeLibrary) Se seu aplicativo utiliza vários threads ou se ele dinamicamente carrega uma DLL de extensão.Usando AfxLoadLibrary e AfxFreeLibrary assegura que o código de inicialização e desligado que é executado quando a DLL de extensão é carregado e descarregado não corromper o estado global do MFC.

O arquivo de cabeçalho AFXDLLX.H contém definições especiais para estruturas usadas na extensão de DLLs, tais sistema autônomo a definição de AFX_EXTENSION_MODULE e CDynLinkLibrary.

O global extensionDLL deve ser declarado sistema autônomo mostrado.Ao contrário da versão de 16 bit do MFC, é possível alocar memória e telefonar MFC funções durante esse período, como o MFCxx.DLL é totalmente inicializado no momento em que seu DllMain é telefonar ed.

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.DLLs intensivo de interface do usuário mais talvez queiram exportar recursos e classes C++ para o aplicativo cliente.

Exportar recurso s é concluído por meio de um recurso lista.Em cada aplicativo é uma lista vinculada separada de CDynLinkLibrary objetos.Ao procurar um recurso, a maioria das implementações padrão de MFC que carregar recursos procurará primeiro lugar, no módulo de recursos corrente (AfxGetResourceHandle) e, se não encontrado exame da 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 a CRuntimeClass objetos registrados para que o pode reconstruir ao criar objeto C++ do tipo necessário com base no que foi armazenado anteriormente dinamicamente.

Se você quiser que o aplicativo cliente para usar classes na sua DLL de extensão são DECLARE_SERIAL, você precisará exportar suas classes fiquem visíveis para o aplicativo cliente. Isso é concluído também movimentar o CDynLinkLibrary lista.

No caso do exemplo de conceitos avançados do MFC 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 último na lista de classes e recursos.MFCxx.DLL inclui todos os recursos MFC padrão, incluindo seqüências de caracteres de prompts para todos os IDs de comando padrão.Colocando-a na cauda da lista permite que os DLLs e do próprio aplicativo cliente não tenha um sua própria cópia dos recursos padrão do MFC, mas para contam os recursos compartilhados no MFCxx.DLL em vez disso.

Mesclando os recursos e nomes de classe de todas as DLLs no espaço para nome do aplicativo cliente tem a desvantagem de que você precisa tomar cuidado que IDs ou nomes que você escolher.É claro que você pode desabilitar esse recurso através da exportação não de seus recursos ou um CDynLinkLibrary objeto para o aplicativo cliente.The DLLHUSK amostra gerencia o espaço para nome de recurso compartilhado usando vários arquivos de cabeçalho.See Observação técnica 35 para obter mais dicas sobre como usar arquivos de recurso compartilhado.

Ao inicializar a DLL

sistema autônomo mencionado acima, você geralmente deseja criar um CDynLinkLibrary objeto para exportar seus recursos e classes 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 deseja usar sua DLL deve chamar a rotina de inicialização, se você usar essa abordagem.Você também pode alocar esse CDynLinkLibrary objeto seuDllMain somente após a chamada AfxInitExtensionModule.

A rotina de inicialização deve criar um CDynLinkLibrary objeto no heap do aplicativo corrente, com fio para sua extensão DLL informações.Isso pode ser concluído com o seguinte:

extern "C" extern void WINAPI InitXxxDLL()
{
   new CDynLinkLibrary(extensionDLL);
}

O nome de rotina, InitXxxDLL neste exemplo, pode ser que quiser.Ele não precisa ser extern "C", mas fazendo positivo torna mais fácil manter lista de exportar.

Observação:

Se você usar a extensão DLL de uma DL regular L, 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.

Exportar entradas

De maneira simples para exportar suas classes é usar __declspec(DllImport) and __declspec(dllexport) em cada classe e a função global que deseja exportar.Isso torna muito mais fácil, mas é menos eficiente do que cada ponto de entrada (descrito abaixo) de nomeação, pois você tem menos controle sobre quais funções são exportadas e não é possível exportar as funções pelo ordinal.TESTDLL1 e TESTDLL2 use esse método para exportar suas entradas.

Um método mais eficiente (e o método usado pelo MFCxx.DLL) é exportar manualmente cada entrada de cada entrada no arquivo .def nomeando.Desde que estiver exportando seletivas exportações de nossa DLL (ou seja, nem tudo), deve decidir quais interfaces específicos que deseja exportar.Isso é difícil, pois você deve especificar os nomes desconfigurados para o vinculador em forma de entradas no arquivo .def.Não exporte a quaisquer classes C++, a menos que seja necessário ter um link simbólico para ele.

Se você tiver tentado a exportação de classes C++ com um arquivo .def antes, talvez queira desenvolver uma ferramenta para gerar automaticamente esta lista.Isso pode ser concluído usando um processo de vínculo de dois estágios.Vincular sua DLL uma vez com nenhuma exportações e permitir que o vinculador gerar um arquivo .MAP.O arquivo .MAP pode ser usado para gerar uma lista de funções que devem ser exportados para com alguns reorganizar, possa ser usada para gerar as entradas de exportar para o arquivo .def.A lista de exportar para MFCxx.DLL OLE e DLLs de extensão banco de dados, vários milhares em número, foi gerada com um processo (embora ele não é totalmente automático e exige alguns mão ajuste cada uma vez em quando).

CWinApp vs.CDynLinkLibrary

Uma DLL de extensão do MFC não possui um CWinApp-derivado objeto própria; 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 precisar de sua DLL de extensão do MFC manter os dados extras para cada aplicativo, é possível derivar uma nova classe de CDynLinkLibrary e criá-lo em InitXxxDLL rotina descrever acima.Quando em execução, a DLL pode consultar a lista do aplicativo corrente de CDynLinkLibrary objetos para localizar o item para esse determinado extensão DLL.

Usando recursos na sua implementação de DLL

sistema autônomo mencionado acima, a carga de recursos padrão vai orientá-lo da lista de CDynLinkLibrary objetos procurando a primeira EXE ou DLL que tem o recurso solicitado.Todas sistema autônomo APIs do MFC bem sistema autônomo o código interno usa AfxFindResourceHandle para percorrer a lista de recursos para localizar qualquer recurso, não importa onde podem estar.

Se desejar carregar somente recursos de um local específico, use as APIs AfxGetResourceHandle e AfxSetResourceHandle Para salvar a alça antiga e conjunto a nova alça. Certifique-se de restauração o identificador de recurso antigo antes de retornar ao aplicativo cliente.O exemplo TESTDLL2 usa essa abordagem para carregar explicitamente um menu.

Percorrer a lista tem desvantagens que é um pouco mais lenta e requer gerenciamento de intervalos de ID do recurso.Ele tem a vantagem que um aplicativo cliente com links para diversas DLLs de extensão pode usar qualquer recurso fornecido pelo DLL sem ter que especificar o identificador de instância DLL.AfxFindResourceHandle uma API é usada para percorrer a lista de recursos para procurar uma correspondência determinada. Ele usa o nome e o tipo de um recurso e retorna o identificador de recurso em que foi encontrado primeiro (ou nulo).

Escrever um aplicativo que usa a versão DLL

Requisitos de aplicativo

Um aplicativo que usa a versão compartilhada do MFC deve seguir algumas regras simples:

  • Ele deve ter um CWinApp objeto e siga o padrão de regras para uma bomba de mensagem.

  • Ele deve ser compilado com um conjunto de sinalizadores de compilador necessário (veja abaixo).

  • Ele deve vincular com bibliotecas de importação MFCxx.Definindo os sinalizadores de compilador necessário, os cabeçalhos MFC determinar em time de vinculação que o aplicativo deve vincular com biblioteca.

  • Para executar o executável, MFCxx.DLL deve ser 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 com com facilidade o projeto para criar a versão de DLL.

A seguinte etapa pressupõe que você tiver um aplicativo MFC está funcionando corretamente vinculado com NAFXCWD.LIB (para depurar) e NAFXCW.LIB (para o varejo) e você desejar convertê-lo para usar a versão da biblioteca MFC compartilhada.Você está executando o ambiente do Visual C++ e ter um arquivo de projeto interno.

  1. Sobre o Projetos menu, clicar Propriedades.No Geral página em Padrões de projeto, defina o Microsoft Foundation Classes como 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ê precisará edição o makefile para oferecer suporte a compilador e as opções do vinculador

Sinalizadores de compilador necessário:

  • / D_AFXDLL /MD
    / D_AFXDLL

Os cabeçalhos MFC padrão necessário esse símbolo ser definidos:

  • /MD
    O aplicativo deve usar a versão DLL da biblioteca de time de execução C.

Todos os outros sinalizadores de compilador siga os padrões MFC (por exemplo, _DEBUG para depurar).

Edite a lista de vinculador de bibliotecas.Alterar NAFXCWD.LIB para MFCxxD.LIB e altere NAFXCW.LIB para MFCxx.LIB.Substitua LIBC.LIB MSVCRT.LIB.sistema autônomo com qualquer Outros biblioteca MFC é importante que MFCxxD.LIB é colocada antes de quaisquer bibliotecas de tempo de execução C.

Opcionalmente, adicione / D_AFXDLL para o varejo e depurar opções do compilador recurso (aquele que realmente compila recursos com /R).Isso torna seu executável final menores compartilhando recursos que estão presentes em MFC DLLs.

É necessária uma recompilar completa depois que essas alterações forem feitas.

Criação de Exemplos

Pode ser montada a maioria dos programas de exemplo MFC do Visual C++ ou de um MAKEFILE compatível com NMAKE compartilhado a partir da linha de comando.

Para converter qualquer um desses exemplos para usar MFCxx.DLL, você pode carregar o arquivo .MAK em Visual C++ e defina sistema autônomo opções de projeto conforme descrito acima.Se estiver usando a compilação NMAKE, você pode especificar "AFXDLL = 1" no NMAKE linha de comando e que irá criar o exemplo usando as bibliotecas MFC compartilhadas.

O exemplo de conceitos avançados do MFC DLLHUSK é criada com a versão DLL do MFC.Este exemplo ilustra não apenas sistema autônomo compilação vinculadas de um aplicativo com MFCxx.DLL, mas ele também ilustra a outros recursos da opção de empacotamento DLL da MFC sistema autônomo DLLs de extensão do MFC descrito mais adiante nesta nota técnica.

Notas de embalagem

A versão comercial de DLLs (MFCxx[U].DLL) são redistribuível gratuitamente.A versão de depurar de DLLs não são redistribuível gratuitamente e devem ser usados somente durante o desenvolvimento do seu aplicativo.

A depurar de DLLs são fornecidos com informações de depurar.Usando o depurador do Visual C++, você pode rastrear a execução de seu aplicativo, bem sistema autônomo a DLL.As DLLs de versão (MFCxx[U].DLL) não contêm informações de depuração.

Se você personalizar ou recompilar as DLLs e, em seguida, você deverá chamá-los 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ária, pois essas DLLs potencialmente são compartilhadas por muitos aplicativos MFC.Com sua versão personalizada do substituir MFC DLLs aqueles instalados no sistema podem quebrar outro aplicativo MFC usando as DLLs compartilhados do MFC.

Não é recomendável recriar as DLLs do MFC.

Como o MFCxx.DLL É implementado

A seção a seguir descreve como a DLL da 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 da MFC com o aplicativo.Aqui os detalhes não são essenciais para compreender como escrever uma DLL de extensão do MFC, mas entender essa implementação pode ajudar escrever sua própria DLL.

Visão geral da implementação

A DLL da MFC é realmente um caso especial de uma DLL de extensão do MFC conforme descrito acima.Ele tem um número muito grande de exportações para um grande número de classes.Há algumas coisas adicionais que fazemos na MFC DLL torná-lo ainda mais especiais de uma DLL de extensão regular.

Win32 é o máximo do trabalho

A versão de 16 bit do MFC necessárias várias técnicas especiais, incluindo dados-app no segmento de pilha, segmentos especiais criados algum código de assembly 80 x 86, contextos de exceção por processo e outras técnicas.Win32 suporta diretamente dados por processo em uma DLL, que é o que você deseja na maioria das vezes.Na maioria das vezes MFCxx.DLL é apenas NAFXCW.LIB empacotados em uma DLL.Se você examinar o código-fonte do MFC, você encontrará muito poucos # ifdef _AFXDLL, visto que existem muito poucos casos especiais que precisam ser feitas.sistema autônomo casos especiais que são há especificamente para lidar com o Win32 no Windows 3.1 (também conhecido sistema autônomo Win32s).Win32s não não suporte por processo DLL dados diretamente até a DLL da MFC deve usar o armazenamento thread local (TLS) APIs do Win32 para obter dados de processo local.

Impacto na biblioteca de códigos-fonte, arquivos adicionais

O impacto do _AFXDLL versão em fontes normais de biblioteca de classes MFC e cabeçalhos é relativamente pequenos.Existe um arquivo de versão especial (AFXV_DLL.H), bem sistema autônomo um arquivo de cabeçalho adicional (AFXDLL_.H) incluído pelo cabeçalho AFXWIN.H principal.O cabeçalho AFXDLL_.H inclui o CDynLinkLibrary classe e outros detalhes de implementação de ambos os _AFXDLL aplicativos e DLLs de extensão do MFC.O cabeçalho AFXDLLX.H é fornecido para a criação de DLLs de extensão do MFC (veja os detalhes acima).

As fontes regulares à biblioteca MFC na MFC SRC têm algum código condicional adicional sob o _AFXDLL # ifdef.Um arquivo de fonte adicionais (DLLINIT.CPP) contém o código de inicialização DLL extra e Outros união para a versão compartilhada do MFC.

Para compilação a versão compartilhada do MFC, arquivos adicionais são fornecidos.(Consulte abaixo para obter detalhes sobre como compilação a DLL.)

  • Um makefile especial (MFCDLL.MAK) é usado para construir as DLLs.Este makefile inclui o MAKEFILE padrão para obter todos os biblioteca MFC normal regras de construção.

  • Dois arquivos .def são usados para exportar os pontos de entrada DLL da MFC para depurar (MFCxxD.DEF) e versões (MFCxx.DEF) da DLL de versão.

  • Um arquivo .RC (MFCDLL.RC) contém todos os recursos padrão do MFC e um recurso VERSIONINFO para a DLL.

  • Um arquivo .CLW (MFCDLL.CLW) é fornecido permitir navegação o MFC, classes usando ClassWizard.Observação: Esse recurso não é específico para a versão DLL do MFC.

Criando a DLL do MFC

Recriando a DLL da MFC é intencionalmente difícil, portanto, você acha que duas vezes (ou três vezes) antes de fazê-lo.Se você compreender os possíveis problemas de empacotamento e redistribuição restrições descritos abaixo e você ainda Na verdade precisa recriar a DLL da MFC, é possível.

O arquivo MFCDLL.MAK será compilação a DLL de depurar com as informações do CodeView:

NMAKE /f mfcdll.mak DEBUG=1 LIBNAME=MYMFC

O arquivo MFCDLL.MAK criará a DLL de versão sem informações do CodeView:

NMAKE /f mfcdll.mak DEBUG=0 LIBNAME=MYMFC

Isso criará uma versão particular da DLL no diretório MFC SRC com os nomes padrão MFCxx.DLL e MFCxxD.DLL MFC.Você precisará copiá-los para um local apropriado no seu caminho para usar as novas DLLs.O makefile MFCDLL.MAK também serão recompilar as bibliotecas de importação (MFCxx.LIB e MFCxxD.LIB) e coloque-os no diretório LIB do MFC padrão.Isso irá substituir as bibliotecas predefinidas MFCxx.LIB e MFCxxD.LIB, portanto, tenha cuidado.

Se você redistribuir uma versão modificada da biblioteca MFC DLL, certifique-se de alterar o nome da DLL no makefile MFCDLL.MAK e os dois arquivos .def.Consulte o makefile MFCDLL.MAK para obter mais informações.

Você pode modificar a biblioteca e redistribuir um varejo (/versão) da sua biblioteca modificada somente se você renomeá-lo para algo diferente de MFCxx.DLL.Não pode redistribuir a versão de depurar de um a depurar interna predefinida ou personalizada DLL.

Essas restrições de redistribuição são principalmente evitar uma proliferação de fora do padrão e potencialmente contendo as DLLs de vírus.O ideal é que não deve necessário recriar as DLLs e se você redistribuir o aplicativo com o MFCxx.DLL predefinidos fornecidos com o produto Visual C++, você evitará muitos problemas para si mesmo e os usuários.

Gerenciamento de memória

Um aplicativo usando MFCxx.DLL usa um alocador de memória comum fornecido pelo MSVCRTxx.DLL, a DLL C tempo de execução compartilhada.O aplicativo, quaisquer DLLs de extensão e assim sistema autônomo sistema autônomo DLLs de MFC se usar esse alocador de memória compartilhada.Ao usar 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.Como o aplicativo e a DLL devem usar o mesmo alocador, você não deve substituir o C++ global operator new ou operator delete. sistema autônomo mesmas regras se aplicam ao resto das rotinas de alocação de memória de time de execução C (por exemplo, malloc, realloc, disponível e outros).

Ordinais e classe __declspec(dllexport) e nomeação de DLL

We do not use the class __declspec(dllexport) functionality of the C++ compiler.Em vez disso, uma lista de exportações é incluída com as fontes de biblioteca de classes (MFCxx.DEF e MFCxxD.DEF).Somente estes conjunto selecionado de pontos de entrada (funções e dados) são exportadas.Outros símbolos, sistema autônomo funções de implementação privada do MFC ou classes, não são exportados todas sistema autônomo exportações são realizadas por ordinal sem um nome de seqüência de caracteres na tabela de nomes residentes ou não residente.

Using class __declspec(dllexport) may be a viable alternative for building smaller DLLs, but in the case of a large DLL like MFC, the default exporting mechanism has efficiency and capacity limits.

O que isso significa que todos os é que nós pode empacotar uma grande quantidade de recursos da versão MFCxx.DLL é apenas cerca de 800 KB sem comprometer muito execução ou carregando velocidade.MFCxx.DLL teria sido maior 100 K essa técnica não foi usado.Isso também torna possível adicionar pontos de entrada adicionais no participante do arquivo .def para permitir o controle de versão simples sem comprometer a eficiência de velocidade e o dimensionar de exportação por ordinal.Principais revisões versão o MFC classe biblioteca alterará o nome da biblioteca.Isto é, 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 do DLL do MFC, use um nome diferente (e preferivelmente um sem "MFC") no nome.

Consulte também

Outros recursos

Notas técnicas por número

Notas técnicas por categoria