Importações mútuas

Exportar ou importar outro arquivo executável apresenta complicações quando as importações são mútua (ou circular). Por exemplo, duas DLLs importar símbolos uns dos outros, similar à mutuamente recursivas: funções.

O problema com a importação mutuamente os arquivos executáveis (geralmente DLLs) é que nenhuma delas pode ser criada sem construir outro primeiro. Cada processo de construção requer, como entrada, uma biblioteca de importação produzida pelo processo de compilação.

A solução é usar o utilitário LIB com a opção /DEF, que produz uma biblioteca de importação sem compilar o arquivo executável. Usando esse utilitário, você pode criar todas as bibliotecas de importação que você precisa, não importa quantos DLLs envolvidas ou complicadas como as dependências são.

A solução geral para a manipulação de importações mútuas é:

  1. Levar cada DLL por sua vez. (Qualquer ordem é viável, embora alguns pedidos são mais ideais). Se todas as bibliotecas de importação necessário existem e estejam atualizadas, execute o LINK para criar o arquivo executável (DLL). Isso produz uma biblioteca de importação. Caso contrário, execute LIB para produzir uma biblioteca de importação.

    A execução de LIB com a opção /DEF produz um arquivo adicional com um.Extensão EXP. A.Arquivo EXP deve ser usado posteriormente para criar o arquivo executável.

  2. Após usar o LINK ou LIB para construir todas as bibliotecas de importação, volte e executar o LINK para criar todos os arquivos executáveis que não foram criados na etapa anterior. Observe que o arquivo de .exp correspondente deve ser especificado na linha de LINK.

    Se você tivesse executado o utilitário LIB anteriormente para produzir uma biblioteca de importação para DLL1, LIB vai ter também o arquivo DLL1.exp. Você deve usar DLL1.exp como entrada para o LINK ao criar DLL1.dlll.

A ilustração a seguir mostra uma solução para duas DLLs de importação mutuamente, DLL1 e DLL2. Etapa 1 é executar LIB, com o conjunto da opção /DEF, em DLL1. Etapa 1 produz DLL1.lib, uma biblioteca de importação e DLL1.exp. Na etapa 2, a biblioteca de importação é usada para construir DLL2, que por sua vez, produz uma biblioteca de importação para os símbolos do DLL2. Etapa 3 constrói DLL1, usando o DLL1.exp e DLL2.lib como entrada. Observe que um arquivo de .exp para DLL2 não é necessário porque o LIB não foi usado para criar a biblioteca de importação do DLL2.

Vinculando duas DLLs com importações mútuas

Importações mútuas vinculadas a 2 DLLs

Limitações do _AFXEXT

Você pode usar o _AFXEXT símbolo do pré-processador para suas DLLs de extensão desde que você não tem várias camadas de DLLs de extensão. Se você tiver a extensão de DLLs que ligue ou derivar de classes em sua própria extensão DLLs, que então derivar de classes MFC, você deve usar o seu próprio símbolo do pré-processador para evitar ambigüidade.

O problema é que em Win32, você deve declarar explicitamente 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ê define _AFXEXT, os cabeçalhos MFC Certifique-se de que AFX_EXT_CLASS está definido corretamente.

Quando você tiver várias camadas, um símbolo, como AFX_EXT_CLASS não é suficiente, porque uma DLL de extensão pode ser novas classes de exportação, assim como a importação de outras classes de outra extensão DLL. Para resolver esse problema, use um símbolo do pré-processador especial que indica que você está construindo a DLL versus usando a DLL. Por exemplo, imagine as DLLs de extensão de dois, a. dll e b. dll. Cada um deles exportar algumas classes de A.h e B.h, respectivamente. B. dll usa as classes de dll. Os arquivos de cabeçalho seriam algo parecido com isto:

/* 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 CExampleB é exportado e CExampleA é importado quando estiver criando b. dll. CExampleAé exportada ao criar a dll e importados quando usado por b. dll (ou outro cliente).

Esse tipo de disposição em camadas não pode ser feito durante o 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 do que mecanismo de MFC próprio usa ao criar suas tecnologias ativo, o banco de dados e DLLs de extensão de rede.

Não exportar a classe inteira

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 feito, redefinindo AFX_DATA a macro. sua classe específica em uma Isso deve ser feito a qualquer momento que você não estiver exportando toda a turma.

For example:

/* 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

O que você deseja fazer?

O que você deseja saber mais a respeito?

Consulte também

Conceitos

Importando e exportando