Gostaria de um exemplo simples de exportação de uma função de uma DLL do Windows C ++.
Eu gostaria de ver o cabeçalho, o .cpp
arquivo e o .def
arquivo (se for absolutamente necessário).
Gostaria que o nome exportado não fosse decorado . Eu gostaria de usar a convenção de chamada mais padrão ( __stdcall
?). Gostaria de usar __declspec(dllexport)
e não preciso usar um .def
arquivo.
Por exemplo:
//header
extern "C"
{
__declspec(dllexport) int __stdcall foo(long bar);
}
//cpp
int __stdcall foo(long bar)
{
return 0;
}
Estou tentando evitar que o vinculador tenha adicionado sublinhados e / ou números (contagens de bytes?) Ao nome.
Aceito não suportar dllimport
e dllexport
usar o mesmo cabeçalho. Não quero nenhuma informação sobre como exportar métodos de classe C ++, apenas funções globais de estilo c.
ATUALIZAR
Não incluir a convenção de chamada (e usar extern "C"
) me dá os nomes de exportação como eu gosto, mas o que isso significa? Qualquer convenção de chamada padrão que estou obtendo é o que pinvoke (.NET), declare (vb6) e GetProcAddress
esperava? (Acho GetProcAddress
que dependeria do ponteiro de função criado pelo chamador).
Eu quero que essa DLL seja usada sem um arquivo de cabeçalho, então eu realmente não preciso de muita fantasia #defines
para tornar o cabeçalho utilizável por um chamador.
Aceito responder que preciso usar um *.def
arquivo.
fonte
extern C
irá remover a decoração que descreve os tipos de parâmetros da função, mas não a decoração que descreve a convenção de chamada da função; b) para remover toda a decoração, você precisa especificar o nome (não decorado) em um arquivo DEF.Respostas:
Se você deseja exportações simples de C, use um projeto C, não C ++. DLLs C ++ contam com a modificação de nomes para todos os isms C ++ (namespaces etc ...). Você pode compilar seu código como C acessando as configurações do projeto em C / C ++ -> Avançado, há uma opção "Compilar como" que corresponde às opções do compilador / TP e / TC.
Se você ainda deseja usar C ++ para escrever o interno de sua biblioteca, mas exportar algumas funções não fragmentadas para uso fora de C ++, consulte a segunda seção abaixo.
Exportando / importando bibliotecas DLL em VC ++
O que você realmente deseja fazer é definir uma macro condicional em um cabeçalho que será incluído em todos os arquivos de origem em seu projeto DLL:
Então, em uma função que você deseja exportar, use
LIBRARY_API
:Em seu projeto de construção de biblioteca, crie um define que
LIBRARY_EXPORTS
fará com que suas funções sejam exportadas para sua construção de DLL.Desde a
LIBRARY_EXPORTS
não será definido em um projeto que consuma a DLL, quando esse projeto incluir o arquivo de cabeçalho de sua biblioteca, todas as funções serão importadas.Se sua biblioteca deve ser multiplataforma, você pode definir LIBRARY_API como nada quando não estiver no Windows:
Ao usar dllexport / dllimport, você não precisa usar arquivos DEF; se usar arquivos DEF, não precisa usar dllexport / dllimport. Os dois métodos realizam a mesma tarefa de maneiras diferentes, acredito que dllexport / dllimport é o método recomendado dos dois.
Exportar funções não fragmentadas de uma DLL C ++ para LoadLibrary / PInvoke
Se você precisar disso para usar LoadLibrary e GetProcAddress, ou talvez importar de outra linguagem (ou seja, PInvoke de .NET ou FFI em Python / R etc), você pode usar
extern "C"
inline com seu dllexport para dizer ao compilador C ++ para não destruir os nomes. E como estamos usando GetProcAddress em vez de dllimport, não precisamos fazer a dança ifdef de cima, apenas um dllexport simples:O código:
E aqui está a aparência das exportações com Dumpbin / exports:
Portanto, este código funciona bem:
fonte
Para C ++:
Acabei de enfrentar o mesmo problema e acho que vale a pena mencionar que surge um problema quando se usa ambos
__stdcall
(ouWINAPI
) eextern "C"
:Como você sabe,
extern "C"
remove a decoração para que, em vez de:você obtém um nome de símbolo não decorado:
No entanto, a
_stdcall
(= macro WINAPI, que muda a convenção de chamada) também decora os nomes de forma que, se usarmos ambos, obteremos:e o benefício de
extern "C"
é perdido porque o símbolo é decorado (com _ @bytes)Isso é particularmente complicado se você tiver como alvo as plataformas x86 e x64.
Duas soluções
Use um arquivo de definição. Mas isso força você a manter o estado do arquivo def.
a maneira mais simples: definir a macro (ver msdn ):
e inclua o seguinte pragma no corpo da função:
Exemplo completo:
Isso exportará a função não decorada para destinos x86 e x64, preservando a
__stdcall
convenção para x86. O__declspec(dllexport)
não é necessário neste caso.fonte
__FUNCTION__
macro só funciona em funções.Eu tive exatamente o mesmo problema, minha solução foi usar o arquivo de definição de módulo (.def) em vez de
__declspec(dllexport)
definir exportações ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). Não tenho ideia de por que isso funciona, mas funcionafonte
.def
módulo de exportação de arquivo faz o trabalho, mas à custa de ser capaz de fornecerextern
definições no arquivo de cabeçalho para, por exemplo dados no globais caso, você tem que fornecer aextern
definição manualmente no internos usos de esses dados. (Sim, há momentos em que você precisa disso.) É melhor geralmente e especialmente para código de plataforma cruzada simplesmente usar__declspec()
com uma macro para que você possa manipular os dados normalmente.__stdcall
, então__declspec(dllexport)
será não remover as decorações..def
No entanto, adicionar a função a um testamento.Acho que _naked pode conseguir o que você deseja, mas também impede que o compilador gere o código de gerenciamento de pilha para a função. extern "C" causa a decoração do nome do estilo C. Remova isso e isso deve se livrar do seu _. O vinculador não adiciona sublinhados, o compilador faz. stdcall faz com que o tamanho da pilha de argumentos seja anexado.
Para obter mais informações, consulte: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx
A grande questão é por que você quer fazer isso? O que há de errado com os nomes mutilados?
fonte