Pergunta

Eu gostaria de um exemplo simples de exportar uma função de um Windows DLL C ++.

Eu gostaria de ver o cabeçalho, o arquivo cpp eo arquivo def (se for absolutamente necessário).

Eu gostaria que o nome exportado para ser undecorated . Eu gostaria de usar a convenção mais de chamada padrão (__stdcall?). Eu gostaria o uso __ declspec (dllexport) e não ter que usar um arquivo DEF.

Por exemplo:

  //header
  extern "C"
  {
   __declspec(dllexport) int __stdcall foo(long bar);
  }

  //cpp
  int __stdcall foo(long bar)
  {
    return 0;
  }

Eu estou tentando evitar os sublinhados e / ou números de vinculador adicionado (contagens de bytes?) Para o nome.

Eu estou bem com não apoiar dllimport e dllexport usando o mesmo cabeçalho. Eu não quero qualquer informação sobre a exportação de métodos de classe C ++, apenas c-estilo funções globais.

Atualização

Não incluindo a convenção de chamada (e usando extern "C") dá-me os nomes de exportação, como eu gosto, mas o que isso significa? É tudo o padrão convenção de chamada Eu estou conseguindo o que PInvoke (NET), declare (VB6) e GetProcAddress esperaria? (Eu acho que para GetProcAddress dependeria o ponteiro de função o chamador criado).

Eu quero que este DLL para ser usado sem um arquivo de cabeçalho, então eu realmente não precisa a um monte de # define fantasia para fazer a utilizável cabeçalho por um chamador.

Estou OK com uma resposta é que eu tenho que usar um arquivo DEF.

Foi útil?

Solução

Se você quiser exportações C lisas, use um projeto C não C ++. DLLs C ++ contar com nome-desconfiguração para todos os ismos do C ++ (namespaces etc ...). Você pode compilar o código como C, indo para as configurações do projeto em C / C ++ -> Avançado, não é uma opção "Compile Como", que cooresponds para o compilador muda / TP e / TC

.

Como exportar / importar DLL liberais no VC ++

O que você realmente quer fazer é definir uma macro condicional em um cabeçalho que será incluída em todos os arquivos de origem no seu projeto DLL:

#ifdef LIBRARY_EXPORTS
#    define LIBRARY_API __declspec(dllexport)
#else
#    define LIBRARY_API __declspec(dllimport)
#endif

Então, em uma função que você quer ser exportados você usa LIBRARY_API:

LIBRARY_API int GetCoolInteger();

Em seu projeto de construção da biblioteca criar uma definição LIBRARY_EXPORTS isso fará com que as suas funções a serem exportadas para a sua construção DLL.

Desde LIBRARY_EXPORTS não será definido em um projeto consumindo a DLL, quando o projeto inclui o arquivo de cabeçalho da sua biblioteca de todas as funções serão importados vez.

Se a sua biblioteca é para ser multi-plataforma pode definir LIBRARY_API como nada quando não estiver no Windows:

#ifdef _WIN32
#    ifdef LIBRARY_EXPORTS
#        define LIBRARY_API __declspec(dllexport)
#    else
#        define LIBRARY_API __declspec(dllimport)
#    endif
#elif
#    define LIBRARY_API
#endif

Ao usar dllexport / dllimport você não precisa de arquivos DEF uso, se você usar arquivos DEF você não precisa usar dllexport / dllimport. Os dois métodos de realizar a mesma tarefa maneiras diferentes, acredito que dllexport / dllimport é o método recomendado para fora dos dois.

exportar as funções de um unmangled ++ DLL C durante LoadLibrary / PInvoke

Se você precisa disso para usar LoadLibrary e GetProcAddress, ou talvez fazendo PInvoke do .net você pode usar extern "C" em linha com o seu dllexport. E já que estamos usando GetProcAddress em vez de dllimport não precisamos fazer a dança ifdef de cima, apenas uma dllexport simples:

O Código:

#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)

EXTERN_DLL_EXPORT int getEngineVersion() {
  return 1;
}

EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) {
  K.getGraphicsServer().addGraphicsDriver(
    auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
  );
}

E aqui está o que as exportações parecido com DUMPBIN / exportações:

  Dump of file opengl_plugin.dll

  File Type: DLL

  Section contains the following exports for opengl_plugin.dll

    00000000 characteristics
    49866068 time date stamp Sun Feb 01 19:54:32 2009
        0.00 version
           1 ordinal base
           2 number of functions
           2 number of names

    ordinal hint RVA      name

          1    0 0001110E getEngineVersion = @ILT+265(_getEngineVersion)
          2    1 00011028 registerPlugin = @ILT+35(_registerPlugin)

Assim, este código funciona bem:

m_hDLL = ::LoadLibrary(T"opengl_plugin.dll");

m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(
  ::GetProcAddress(m_hDLL, "getEngineVersion")
);
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(
  ::GetProcAddress(m_hDLL, "registerPlugin")
);

Outras dicas

Para C ++:

Eu só enfrentou o mesmo problema e eu acho que vale a pena mencionar um problema surge quando se usar tanto __stdcall (ou WINAPI) e extern "C":

Como você sabe extern "C" remove a decoração de modo que em vez de:

__declspec(dllexport) int Test(void)                        --> dumpbin : ?Test@@YaHXZ

-lo a obter um nome de símbolo undecorated:

extern "C" __declspec(dllexport) int Test(void)             --> dumpbin : Test

No entanto, o _stdcall (= WINAPI macro, que altera a convenção de chamada) também decora nomes para que se usarmos tanto obtemos:

   extern "C" __declspec(dllexport) int WINAPI Test(void)   --> dumpbin : _Test@0

eo benefício da extern "C" está perdido, porque o símbolo está decorado (com _ @bytes)

Note que esta única ocorre para arquitetura x86, porque a convenção __stdcall é ignorado em x64 ( MSDN : em x64 arquiteturas, por convenção, os argumentos são passados ??nos registradores quando possível, e os argumentos subsequentes são passados ??na pilha .).

Isto é particularmente complicado se você tiver como alvo ambas as plataformas x86 e x64.


Duas soluções

  1. Use um arquivo de definição. Mas Isso força você a manter o estado do arquivo def.

  2. a maneira mais simples: definir o macro (ver MSDN ):

comentário #define EXPORTAÇÃO (linker, "/ EXPORT:" __FUNCTION__ "=" __FUNCDNAME __)

e, em seguida, incluir o seguinte pragma no corpo da função:

#pragma EXPORT

Exemplo completa:

 int WINAPI Test(void)
{
    #pragma EXPORT
    return 1;
}

Isto irá exportar a função undecorated para ambos os alvos x86 e x64, preservando a convenção __stdcall para x86. O __declspec(dllexport) não é necessária neste caso.

Eu tinha exatamente o mesmo problema, a minha solução foi usar arquivo de definição de módulo (.DEF) em vez de __declspec(dllexport) para definir exportações ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). Eu não tenho idéia por que isso funciona, mas ele faz

Eu acho _naked pode obter o que deseja, mas também impede o compilador de gerar o código de gerenciamento de pilha para a função. extern "C" faz com que nome de estilo C decoração. Retire isso e que deve se livrar de seus _ de. O vinculador não adicionar os sublinhados, o compilador faz. stdcall faz com que o tamanho da pilha argumento para ser anexado.

Para saber mais, 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?

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