Pergunta

Eu tenho lido muitos um tutorial / artigo em DLLs não gerenciados em C ++. Para a vida de mim, no entanto, eu não consigo entender o conceito. Eu sou facilmente confundido pela discordância aparente sobre se ele precisa de um arquivo de cabeçalho, como exportá-lo, se eu preciso de um arquivo .lib eo que você tem.

Então, vamos supor que eu tenho apenas uma função assim:

public int calculateSquare(int num)
{
    return num*num;
}

Ignorando o código real, o que eu preciso para fazer esta função simples, por si só, em uma DLL que eu possa, em seguida, chamar? Eu só adicionar __dllexport ou seja o que for para a primeira linha ou que eu preciso de um cabeçalho? Estou perplexo com tudo isso.

Foi útil?

Solução

Eu não posso forçar este bastante compilador, o C ++ não vê arquivos de cabeçalho, após o pré-processamento é feito, há apenas um grande arquivo de origem (também chamado de unidade de compilação). Então estritamente você não precisa de um cabeçalho para exportar essa função a partir de uma dll. O que você precisa é alguma forma de compilação condicional para exportar a função na DLL que você está compilando e importá-lo no código do cliente.

Normalmente, isso é feito com uma combinação de macros e arquivos de cabeçalho. Você cria uma macro chamada MYIMPORTEXPORT e através do uso de instruções condicionais macro-lhe fazê-lo funcionar como __declspec (dllexport) na dll, e __declspec (dllimport) no código do cliente.

em MYIMPORTEXPORT.h arquivo

#ifdef SOME_CONDITION
#define MYIMPORTEXPORT __declspec( dllexport )
#else
#define MYIMPORTEXPORT __declspec( dllimport )
#endif

em myheader.h arquivo

#include <MyImportExport.h>

MYIMPORTEXPORT public int calculateSquare(int num)
{
    return num*num;
}

na dll arquivo .cpp

#define SOME_CONDITION

#include <MyHeader.h>

no arquivo .cpp código de cliente

#include <MyHeader.h>

É claro que você também precisa de sinal para o vinculador que você está construindo uma dll com o / DLL opção .

O processo de construção também vai fazer um arquivo .lib, esta é uma lib estático - chamado o stub neste caso - que as necessidades de código de cliente para vincular a como se fosse um link para uma lib estático real. Automagicamente, a dll será carregado quando o código do cliente é executado. Claro que a dll precisa ser encontrado pelo sistema operacional através do seu mecanismo de pesquisa, o que significa que você não pode colocar a dll apenas em qualquer lugar, mas em um local específico. Aqui é mais sobre isso.

Uma ferramenta muito útil para ver se você exportou a função correta do dll, e se o código do cliente está correctamente importação é dumpbin . Executá-lo com / exportações e / importações, respectivamente.

Outras dicas

resposta QBziZ' é certo o suficiente. Veja em C ++

Para completá-lo:. Em C ++, se você precisa usar um símbolo, você deve dizer ao compilador que ele existe, e muitas vezes, o seu protótipo

Em outras línguas, o compilador simplesmente explorar a biblioteca por conta própria, e encontrar o símbolo, et voilà .

Em C ++, você deve dizer ao compilador.

Veja cabeçalho de um C / C ++ como um livro de mesa de conteúdos

A melhor maneira é colocar em algum lugar comum o código necessário. A "interface", se quiser. Isso geralmente é feito em um arquivo de cabeçalho, chamado cabeçalho porque isso geralmente não é um arquivo de fonte independente. O cabeçalho é de apenas um arquivo cujo objectivo é o de ser incluído (ou seja, copiar / colar pelo pré-processador) em arquivos verdadeira fonte.

Em substância, parece que você tem que declarar duas vezes um símbolo (função, classe, qualquer que seja). Que é quase uma heresia quando comparado a outros idiomas.

Você deve vê-lo como um livro, com um quadro de síntese, ou um índice. Na tabela, você tem todos os capítulos. No texto, você tem os capítulos e seus conteúdos.

E, às vezes, você está apenas feliz você tem a lista de capítulos.

C ++, este é o cabeçalho.

E sobre o DLL?

Então, de volta para o problema DLL:. O objetivo de uma DLL é símbolos de exportação que seu código irá usar

Assim forma, em um C ++, você deve tanto de exportação do código na compilação (ou seja, no Windows, use o __declspec, por exemplo) e "publicar" uma tabela do que é exportado (ou seja, ter cabeçalhos "públicas" contendo o declarações exportados).

Lista de verificação para as funções de exportação:

  • É a convenção de chamada adequado para o chamador? (Isso determina como os parâmetros e resultados são passados, e que é responsável pela limpeza da pilha). Você deve indicar a sua convenção de chamada explicitamente.
  • Em que o nome do símbolo será exportado? C ++ geralmente precisa para decorar ( "calandra") os nomes dos símbolos, por exemplo para distinguir entre diferentes sobrecargas.
  • Diga o vinculador para fazer a função visível como DLL Export

Em MSVC:

  • __stdcall (que é convenção de chamada Pascal) é a convenção de chamada típico de símbolos exportados -. Apoiado pela maioria dos clientes, eu acho
  • externo "C" permite exportar o símbolo de estilo C sem nome desconfiguração
  • uso __declspec(dllexport) para marcar um símbolo a ser exportado, ou vincular um arquivo .def separada, onde os símbolos a serem exportados estão listados. Com um arquivo .def também é possível exportar apenas por ordinal (não pelo nome), e alterar o nome do símbolo que é exportado.

Você precisa exportar a função usando either__declspec( dllexport ) ou adicionar a função a um arquivo de definição de módulo (.DEF). Em seguida, compilar tho projeto como uma DLL.

No lado do cliente, você tem duas opções. Ou usar uma biblioteca de importação (.lib) que é gerado quando compilar o DLL. Basta ligar com seu projeto cliente com esta biblioteca lhe dará acesso às funções exportadas da DLL. E você precisa de um arquivo de cabeçalho, porque o compilador precisa saber a assinatura de sua função - que retorna int e leva um int. Para recapitular, você precisa vincular com uma biblioteca de importação (.lib) e um arquivo de cabeçalho que contém o cabeçalho de sua função.

Outra maneira é para carregar a DLL dinamicamente usando chamada WinAPI LoadLibrary e depois GetProcAddress para obter um ponteiro para a função. O ponteiro para a função deve ter o tipo correto, para que o compilador pode dar-lhe que os parâmetros corretos e a convenção de chamada correto é usado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top