2008-08-25 13 views
8

Ich bin ein C/C++ DLL zu schreiben und wollen bestimmte Funktionen exportieren, die ich eine DEF-Datei, bevor Sie wie diese definiertÜberladene Funktionen in C++ DLL-Datei def

LIBRARY "MyLib" 
EXPORTS 
    Foo 
    Bar 

mit dem Code getan haben dies zum Beispiel:

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

was aber, wenn ich will eine überladene Methode von Foo() wie erklären:

int Foo(int a, int b); 

Als d Die ef-Datei hat nur den Funktionsnamen und nicht den vollständigen Prototyp. Ich kann nicht sehen, wie sie mit den überladenen Funktionen umgehen würde. Verwenden Sie nur den einen Eintrag und geben Sie an, welche überladene Version bei der Übergabe des ordnungsgemäß prototypierten Funktionszeigers an LoadLibrary() übergeben werden soll?

Edit: klar zu sein, ist dies auf Windows Visual Studio 2005

bearbeitet mit: die Nicht-def (__declspec) Methode als Antwort markiert ... Ich weiß, das löst nicht das Problem tatsächlich mit def-Dateien, wie ich wollte, aber es scheint, dass es wahrscheinlich keine (offizielle) Lösung mit Def-Dateien gibt. Wird die Frage jedoch offen lassen, falls jemand etwas weiß, haben wir keine überladenen Funktionen und Def-Dateien.

Antwort

9

Markieren Sie im Code selbst die zu exportierenden Funktionen mit __declspec (dllexport). Zum Beispiel:

#define DllExport __declspec(dllexport) 

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

Wenn Sie dies tun, müssen Sie nicht die Funktionen in der DEF-Datei aufzulisten.

Alternativ können Sie in der Lage sein, einen Standard-Parameterwert zu verwenden, wie:

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

Dies setzt voraus, dass es einen Wert für b vorhanden ist, die Sie verwenden können, um anzuzeigen, dass er nicht benutzt wird. Wenn -1 ein zulässiger Wert für b ist, oder wenn es kein Standard ist oder sein sollte, wird dies nicht funktionieren.

Bearbeiten (Adam Haile): Korrigiert, __declspec als __dllspec zu verwenden, war nicht korrekt, also könnte ich das als die offizielle Antwort markieren ... es war nahe genug.

Bearbeiten (Graeme): Ups - danke für die Korrektur meines Tippfehlers!

+0

Was ist, wenn wir GetProcAddress() mit einer dynamischen DLL verwenden? – null

+2

Dann müssen Sie die entstellten Namen verwenden oder eine der Funktionen umbenennen und sie beide "extern" C "machen, vorausgesetzt, dass keiner von ihnen C++ - Objekte übernimmt oder zurückgibt. –

11

Funktion Überladung ist eine C++ - Funktion, die auf Name Mangling beruht (die kryptischen Funktionsnamen in den Linker-Fehlermeldungen).

Durch die entstellten Namen in die def-Datei zu schreiben, kann ich mein Testprojekt erhalten zu verknüpfen und laufen:

LIBRARY "TestDLL" 
EXPORTS 
    [email protected]@[email protected] 
    [email protected]@[email protected] 

für

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

die C++ Funktionsnamen So scheint zu funktionieren kopieren von die Fehlermeldung und schreibe sie in deine def-Datei. Die eigentliche Frage ist jedoch: Warum möchten Sie eine Def-Datei verwenden und nicht mit __declspec (dllexport) gehen?

Die verstümmelten Namen sind nicht portabel, ich habe mit VC++ 2008 getestet.

+0

Interessanter Ansatz. Mit nicht-portable meinen Sie über verschiedene Versionen von Visual Studio? Was würde bedeuten, dass sie ihren Namen Mangling Schemas zwischen den Versionen vielleicht ändern? – jxramos

+0

@jxramos Ich bin mir nicht sicher, ob sie tatsächlich das Namensmangelschema ändern können. Aber ich bezweifle, dass dies beim Umschalten auf einen anderen Compiler genauso funktionieren wird, wenn dieser Compiler nicht versucht, das VC-Verhalten zu emulieren. – Timbo

+0

Dies ist sicherlich nur eine VC++ Sache, da ich glaube nicht, dass andere Compiler Def-Dateien verwenden. Auch wenn ich mich erinnere, was jemand mir einmal gesagt hat, dass Microsoft diese dll Schnittstelle Idee hat, wo Benutzer vorgewählte Elemente öffentlich ausgestellt werden, über die Def-Datei oder __declspec, während in Unix mit ihren * .so Akten alles mit einer öffentlichen API herausgestellt wird. Sie unterscheiden nicht zwischen der logischen öffentlichen API und der öffentlichen API der Bibliothek. – jxramos

2

Es gibt keine agnostische Sprache oder Version, die eine überladene Funktion exportiert, da sich die Mangling-Konvention mit jeder Version des Compilers ändern kann.

Dies ist ein Grund, warum die meisten WinXX-Funktionen lustige Namen wie * Ex oder * 2 haben.

+0

interessanter Hintergrund mit dem WinXX-Kommentar! – jxramos

3

Es gibt keine offizielle Art zu tun, was Sie wollen, denn die DLL-Schnittstelle ist ein CAPI.

Der Compiler selbst verwendet mangelnde Namen als Workaround, daher sollten Sie den Namen Mangling verwenden, wenn Sie nicht zu viel Code ändern möchten.

8

Ich hatte ein ähnliches Problem, also wollte ich auch hier posten.

  1. Normalerweise

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

    einen Funktionsnamen zu exportieren ist in Ordnung. Es wird in der Regel exportieren Sie den Namen unmigrled ohne die Notwendigkeit für eine .def-Datei. Es gibt jedoch einige Ausnahmen wie __stdcall Funktionen und überladene Funktionsnamen.

  2. Wenn Sie eine Funktion deklarieren die __stdcall Konvention zu verwenden (wie für viele API-Funktionen durchgeführt wird), dann

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

    wird wie _foo @ 4 einen verstümmelten Namen exportieren. In diesem Fall müssen Sie den exportierten Namen möglicherweise explizit einem internen ungültigen Namen zuordnen.

A. So exportieren Sie einen nicht verwalteten Namen. In einer DEF-Datei

---- 
EXPORTS 
    ; Explicit exports can go here 

    Foo 
----- 

hinzufügen Dies wird versuchen, eine „beste Übereinstimmung“ für eine interne Funktion Foo zu finden und exportieren. Im obigen Fall, wo es nur ein foo dies die Zuordnung

Foo = _foo @ 4

erstellen, wie über dumpbin/exports

Wenn Sie einen Funktionsnamen, den Sie dann überlastet sehen werden Unter Umständen müssen Sie in der DEF-Datei explizit angeben, welche Funktion Sie verwenden möchten, indem Sie einen ungültigen Namen mit der Syntax [] [] angeben. z.B.

---- 
EXPORTS 
    ; Explicit exports can go here 

    [email protected] 
----- 

B. Eine alternative Dateien zu .DEF ist, dass Sie Namen "in place" mit einem Pragma exportieren.

#pragma comment(linker, "/export:[email protected]") 

C. Eine dritte Alternative ist nur eine Version von Foo als extern "C" zu erklären unmangled exportiert werden. Details siehe here.

2

Systax für AUSFUHR Definition lautet:

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

Eintragsname die Funktion oder Variablennamen, die Sie exportieren möchten. Dies ist erforderlich. Wenn der Name, den Sie exportieren, sich von dem Namen in der DLL unterscheidet, geben Sie den Namen des Exports in der DLL mit Internenname an.

Zum Beispiel, wenn Ihre DLL eine Funktion, func1() exportiert und Sie wollen es als func2 verwendet werden(), geben Sie Folgendes an:

EXPORTS 
func2=func1 

einfach die verstümmelten Namen sehen (mit Dependency Walker) und geben Sie Ihren eigenen Funktionsnamen an.

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

Edit: Dies funktioniert für dynamischen DLLs, wo wir brauchen GetProcAddress() verwenden, um explizit eine Funktion in Dll zu holen.