INFO: Utilizando _declspec(dllimport) & _declspec(dllexport) no código

Traduções de Artigos Traduções de Artigos
Artigo: 132044 - Ver produtos para os quais este artigo se aplica.
Expandir tudo | Reduzir tudo

Nesta página

Sumário

Este artigo complementa as informações abrangidas no seguinte artigo na base de dados de conhecimento da Microsoft:
107501INFO: __export substituídos por __declspec no Visual C++ 32 bits
Este artigo explica as vantagens e mechanics da utilização _declspec(dllimport) e _declspec(dllexport) na aplicação.

Mais Informação

A edição de 32 bits do Visual C++ utiliza _declspec(dllimport) e _declspec(dllexport) para substituir a palavra-chave __export utilizada anteriormente em versões de 16 bits do Visual C++.

Não é necessário utilizar _declspec(dllimport) para o código para compilar correctamente, mas ao fazê-lo, permite o compilador ao gerar código melhor. O compilador é capaz de gerar código melhor uma vez que este tome conhecimento por tem a certeza se existe uma função de uma DLL ou não, para que o compilador pode produzir códigos ignorar um nível de direccionamento indirecto habitualmente estar presente na chamada de função que cruzado um limite DLL.

Com a secção EXPORTS de ficheiro da .def adequada, não é necessário _declspec(dllexport). _declspec(dllexport) foi adicionada para proporcionar uma forma fácil exportar funções de um .exe ou .dll sem utilizar um ficheiro .def.

Este artigo fornece uma discussão exaustiva, relativamente baixo nível sobre estes problemas.

O formato executável portátil Win32 foi concebido para minimizar o número de páginas que devem ser processadas para corrigir importações. Para efectuar este procedimento, coloca todos os endereços importação para qualquer programa num único local denominado tabela de endereços importar. Isto permite que o carregador modificar apenas uma ou duas páginas ao aceder a estes importações.

Utilizar _declspec(dllimport) para chamadas a funções

No seguinte exemplo de código, assumem func1 é uma função que reside em separado do ficheiro .exe que contém a função main() uma DLL.

Sem _declspec(dllimport), atribuído este código:
void main(void) {
    func1();
}
				
o compilador gera código que tem este aspecto:
call func1
				
e o linker converte a chamada para semelhante ao seguinte:
call 0x4000000         ; The address of 'func1'.
				
se existir 'func1' na DLL de outro, o linker não é possível resolver esta situação directamente porque nenhuma forma de saber o que o endereço do 'func1' encontra-se. Em ambientes de 16 bits, o linker Adiciona este endereço de código a uma lista de .exe que o carregador seria patch em tempo de execução com o endereço correcto. Em ambientes de 32 bits, o linker gera um thunk para o qual-lo conhecer o endereço. O thunk tem este aspecto:
   0x40000000:    jmp DWORD PTR __imp_func1
				
aqui __imp_func1 é o endereço ranhura do func1 na tabela endereço importação do ficheiro .exe. Todos os endereços, portanto, são conhecidos pelo linker. O carregador só tem de actualizar tabela de endereços importar o ficheiro .exe ao tempo de carregamento para tudo a funcionar correctamente.

Assim, utilizar _declspec(dllimport) é melhor porque é melhor se o linker não gera uma thunk se não tiver a. Thunks aumentar o código (em sistemas em RISC, pode ser várias instruções) e pode degradar o desempenho da cache. Se saber o compilador que a função é de uma DLL, pode gerar uma chamada indirecta onde.

Agora, este código:
__declspec(dllimport) void func1(void);

void main(void) {
    func1();
}
				
gera esta instrução:
call DWORD PTR __imp_func1
				
é não thunk e nenhuma instrução jmp, por isso, o código mais pequenos e mais rápido.

Por outro lado, para chamadas de função dentro de uma DLL, que não pretende ter de utilizar uma chamada indirecta. Já sabe o endereço de uma função. Tempo e espaço são necessários para carregar e armazenar o endereço da função antes de uma chamada indirecta, para que uma chamada directa é sempre mais rápido e mais pequeno. Só deseja utilizar __declspec(dllimport) ao chamar funções DLL do exterior a DLL propriamente dito. Não utilize __declspec(dllimport) funções dentro de uma DLL durante a criação dessa DLL.

Utilizar _declspec(dllexport)

A Microsoft apresentou __export na versão do compilador de 16 bits para permitir que o compilador gerar automaticamente os nomes de exportação e colocá-los num ficheiro .LIB. Este ficheiro .LIB, em seguida, poderia ser utilizado tal como um .LIB estática para ligar a uma DLL.

A Microsoft adicionou __declspec(dllexport) para continuar esta conveniência. O objectivo consiste em Adicionar a directiva de exportação para o objecto ficheiro pelo que não necessita de um ficheiro .def.

Esta questão de conveniência é mais evidente quando tentar exportar decorado os nomes das funções do C++. Não existe nenhuma especificação padrão para decoração de nomes, para pode alterar o nome de uma função exportada entre versões do compilador. Se utilizar _declspec(dllexport), recompilar o DLL e os ficheiros .exe dependentes é necessária apenas a conta para alterações de convenção de nomenclatura.

Muitos exportar directivas como ordinais, NONAME ou PRIVATE, pode ser efectuada apenas num ficheiro .def e não é possível especificar estes atributos sem um ficheiro .def. No entanto, utilizar _declspec(dllexport) juntamente com a utilizar um ficheiro .def não causa erros de compilação.

Como referência, procure o ficheiro de cabeçalho WINBASE.H Win32. Contém exemplos de utilização __declspec(dllexport) e __declspec(dllimport) preferencial.

Utilizar _declspec(dllexport) e _declspec(dllimport) no dados

No caso de dados, utilizar _declspec(dllimport) é um item de conveniência que remove uma camada de direccionamento indirecto. Quando importa dados de uma DLL, ainda tem de percorrer a tabela de endereços de importação. Nos dias Win32 antes _declspec(dllimport), isso significava tiver de se lembrar de efectuar um nível adicional de direccionamento indirecto quando aceder a dados exportados a partir da DLL:
// project.h
#ifdef _DLL     // If accessing the data from inside the DLL
   ULONG ulDataInDll;

else            // If accessing the data from outside the DLL
   ULONG *ulDataInDll;
#endif
				
É, em seguida, vai exportar os dados no ficheiro .def:
// project.def
LIBRARY project
EXPORTS
    ulDataInDll   CONSTANT
				
e aceder fora a DLL:
if (*ulDataInDll == 0L) {
   // Do stuff here
}
				
quando marcar os dados como __declspec(dllimport), o compilador gera automaticamente o código de direccionamento indirecto para si. Já não tiver preocupar com os passos acima descritos. Como mencionado anteriormente, não utilize _declspec(dllimport) declaração nos dados ao criar a DLL. Funções dentro da DLL não irão utilizar a tabela de endereços importar para aceder o objecto de dados. Por conseguinte, não terá o nível de direccionamento indirecto presente adicional.

Para exportar os dados automaticamente a partir da DLL, utilize esta declaração:
__declspec(dllexport) ULONG ulDataInDLL;
				

Utilizar um ficheiro .def

Se optar por utilizar __declspec(dllimport) juntamente com um ficheiro .def, deve alterar o ficheiro .def para utilizar dados em vez da CONSTANTE para reduzir a probabilidade de que a codificação incorrecta causará um problema:
// project.def
LIBRARY project
EXPORTS
    ulDataInDll   DATA
				
o gráfico seguinte mostra qual a razão:
Keyword     Emits in the import lib     Exports
CONSTANT    __imp_ulDataInDll           ulDataInDll
            __ulDataInDll

DATA        __imp_ulDataInDll           ulDataInDll
				
utilizar _declspec (dllimport) e CONSTANTE lista a versão __imp_ e o nome undecorated na biblioteca de importação .LIB DLL que é criado para permitir a ligação explícita. Utilizar _declspec(dllimport) e dados lista apenas a versão __imp_ do nome.

Se utilizar CONSTANTE, uma das seguintes construções de código pode ser utilizada para aceder a ulDataInDll:
__declspec(dllimport) ULONG ulDataInDll; /*prototype*/ 
   if (ulDataInDll == 0L)   /*sample code fragment*/ 
				
- ou -
ULONG *ulDataInDll;      /*prototype*/ 
if (*ulDataInDll == 0L)  /*sample code fragment*/ 
				
No entanto, se utilizar dados no ficheiro .def, apenas o código compilado com a seguinte definição pode aceder à ulDataInDll variável:
__declspec(dllimport) ULONG ulDataInDll;
if (ulDataInDll == 0L)   /*sample code fragment*/ 
				
utilizar CONSTANT é mais arriscado porque se se esquecer a utilizar o nível de direccionamento indirecto adicional, pode aceder potencialmente ponteiro a tabela de endereços de importação de para a variável--não a variável propriamente dito. Este tipo de problema frequentemente pode manifestar como uma violação de acesso porque a tabela de endereços importar actualmente é efectuada só de leitura pelo compilador de Microsoft e linkers.

Linker actual Visual C++ emite um aviso se vê-lo CONSTANTE no ficheiro .def para contas para este incidente. O motivo real apenas para utilizar a CONSTANTE é se não conseguir recompilar alguns ficheiros de objecto onde o ficheiro de cabeçalho não lista dllimport no protótipo.

Referências

O Visual C++ Books Online fornecem uma quantidade substancial de documentação na dllexport e dllimport atributos de classe de armazenamento. Isto inclui "Os atributos dllexport e dllimport" e os tópicos "utilizar dllimport e dllexport em C++" no capítulo "Microsoft específicas Modificadores" de referência de linguagem do C++ e os tópicos "Exportar símbolos" no capítulo "Criar DLLs de Win32" da referência técnicas de programação. Para uma lista exaustiva Tópicos relacionados, procure o Books Online para "dllimport" ou "dllexport".

Para mais informações, consulte os seguintes artigos na base de dados de conhecimento da Microsoft:
90530Como exportar dados a partir de uma DLL ou uma aplicação
107501INFO: __export substituídos por __declspec no Visual C++ 32 bits

Propriedades

Artigo: 132044 - Última revisão: 2 de dezembro de 2003 - Revisão: 2.0
A informação contida neste artigo aplica-se a:
  • Microsoft Visual C++ 1.0 Professional Edition
  • Microsoft Visual C++ 2.0 Professional Edition
  • Microsoft Visual C++ 2.1
  • Microsoft Visual C++ 4.0 Standard Edition
  • Microsoft Visual C++ 5.0 Enterprise Edition
  • Microsoft Visual C++ 5.0 Professional Edition
Palavras-chave: 
kbmt kbcode kbcompiler kbinfo KB132044 KbMtpt
Tradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine translation ou MT), não tendo sido portanto revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 132044
Exclusão de Responsabilidade para Conteúdo sem Suporte na KB
Este artigo foi escrito sobre produtos para os quais a Microsoft já não fornece suporte. Por conseguinte, este artigo é oferecido "tal como está" e deixará de ser actualizado.

Submeter comentários

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com