Pergunta

Estou escrevendo uma DLL C/C++ e quero exportar certas funções que fiz antes de usar um arquivo .def como este

LIBRARY "MyLib"
EXPORTS
  Foo
  Bar

com o código definido como este, por exemplo:

int Foo(int a);
void Bar(int foo);

No entanto, e se eu quiser declarar um método sobrecarregado de Foo() como:

int Foo(int a, int b);

Como o arquivo def possui apenas o nome da função e não o protótipo completo, não consigo ver como ele lidaria com as funções sobrecarregadas.Você apenas usa uma entrada e especifica qual versão sobrecarregada deseja ao passar o ponteiro de função prototipado corretamente para LoadLibrary() ?

Editar:Para ser claro, isso ocorre no Windows usando Visual Studio 2005

Editar:Marcado o método não-def (__declspec) como resposta... Eu sei que isso não resolve o problema usando arquivos def como eu queria, mas parece que provavelmente não há solução (oficial) usando arquivos def.Deixaremos a questão em aberto, porém, caso alguém saiba de algo não temos funções e arquivos def sobrecarregados.

Foi útil?

Solução

No próprio código, marque as funções que deseja exportar usando __declspec(dllexport).Por exemplo:

#define DllExport __declspec(dllexport)

int DllExport  Foo( int a ) {
  // implementation
}
int DllExport Foo( int a, int b ) {
  // implementation
}

Se fizer isso, não será necessário listar as funções no arquivo .def.

Como alternativa, você pode usar um valor de parâmetro padrão, como:

int Foo( int a, int b = -1 )

Isso pressupõe que existe um valor para b que você pode usar para indicar que ele não é utilizado.Se -1 for um valor legal para b, ou se não houver ou não deveria haver um padrão, isso não funcionará.

Editar (Adam Haile):Corrigido para usar __declspec porque __dllspec não estava correto, então eu poderia marcar isso como a resposta oficial... estava perto o suficiente.

Editar (Graeme):Ops, obrigado por corrigir meu erro de digitação!

Outras dicas

A sobrecarga de função é um recurso do C++ que depende da manipulação de nomes (os nomes de funções enigmáticos nas mensagens de erro do vinculador).

Ao escrever os nomes mutilados no arquivo def, posso fazer com que meu projeto de teste seja vinculado e executado:

LIBRARY "TestDLL"
EXPORTS
    ?Foo@@YAXH@Z
    ?Foo@@YAXHH@Z

parece funcionar para

void Foo( int x );
void Foo( int x, int y );

Portanto, copie os nomes das funções C++ da mensagem de erro e grave-os em seu arquivo def.No entanto, a verdadeira questão é:Por que você deseja usar um arquivo def e não usar __declspec(dllexport) ?

Os nomes mutilados não são portáveis, testei com VC++ 2008.

Eu tive um problema semelhante, então queria postar sobre isso também.

  1. Geralmente usando

    extern "C" __declspec(dllexport) void Foo();
    

    exportar um nome de função está bem.Ele vai geralmente exportar o nome desmanchado sem a necessidade de um Arquivo .def.Há, no entanto, alguns exceções como funções __stdcall e nomes de funções sobrecarregados.

  2. Se você declarar uma função para usar o __stdcall convenção (como é feito para muitas funções da API) em seguida,

    extern "C" __declspec(dllexport) void __stdcall Foo();
    

    irá exportar um nome manchado como _Foo@4.Nesse caso, talvez seja necessário mapear explicitamente o nome exportado a um nome interno manchado.

A.Como exportar um nome não mutilado.Em um arquivo .def adicione

----
EXPORTS
    ; Explicit exports can go here

    Foo
-----

Isto tentará encontrar a "melhor correspondência" para uma função interna Foo e exportá-la.No caso acima onde há apenas um foo isso criará o mapeamento

Foo = _Foo@4

como pode ser visto via dumpbin /EXPORTS

Se você sobrecarregou um nome de função, talvez seja necessário dizer explicitamente qual função deseja no arquivo .def especificando um nome manipulado usando a sintaxe entryname[=internalname].por exemplo.

----
EXPORTS
    ; Explicit exports can go here

    Foo=_Foo@4
-----

B.Uma alternativa aos arquivos .def é que você pode exportar nomes "no local" usando um #pragma.

#pragma comment(linker, "/export:Foo=_Foo@4")

C.Uma terceira alternativa é declarar apenas uma versão de Foo como "C" externo para ser exportada sem confusão.Ver aqui para detalhes.

Não existe uma maneira oficial de fazer o que você deseja, porque a interface dll é uma API C.

O próprio compilador usa nomes mutilados como solução alternativa, portanto, você deve usar a mutilação de nomes quando não quiser alterar muito seu código.

Não existe uma maneira independente de idioma ou versão de exportar uma função sobrecarregada, pois a convenção de manipulação pode mudar a cada versão do compilador.

Esta é uma das razões pelas quais a maioria das funções WinXX têm nomes engraçados como *Ex ou *2.

A definição do Systax para EXPORTS é:

entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]

nome da entrada é o nome da função ou variável que você deseja exportar.Isto é necessário.Se o nome que você exporta for diferente do nome na DLL, especifique o nome da exportação na DLL com nome interno.

Por exemplo, se sua DLL exporta uma função func1() e você deseja que ela seja usada como func2(), você especificaria:

EXPORTS
func2=func1

Basta ver os nomes mutilados (usando o Dependency Walker) e especificar o nome de suas próprias funções.

Fonte: http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx

Editar:Isso funciona para DLLs dinâmicas, onde precisamos usar GetProcAddress() para buscar explicitamente funções em DLL.

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