Funzioni sovraccaricate nel file def DLL C++
Domanda
Sto scrivendo una DLL C/C++ e desidero esportare alcune funzioni che ho eseguito prima di utilizzare un file .def come questo
LIBRARY "MyLib"
EXPORTS
Foo
Bar
con il codice definito così, ad esempio:
int Foo(int a);
void Bar(int foo);
Tuttavia, cosa succede se voglio dichiarare un metodo sovraccaricato di Foo() come:
int Foo(int a, int b);
Poiché il file def ha solo il nome della funzione e non il prototipo completo, non riesco a vedere come gestirebbe le funzioni sovraccaricate.Utilizzi semplicemente l'unica voce e quindi specifichi quale versione sovraccaricata desideri quando passi il puntatore a funzione adeguatamente prototipato a LoadLibrary() ?
Modificare:Per essere chiari, questo è su Windows che utilizza Visual Studio 2005
Modificare:Contrassegnato il metodo non def (__declspec) come risposta... So che questo in realtà non risolve il problema utilizzando i file def come volevo, ma sembra che probabilmente non esista alcuna soluzione (ufficiale) utilizzando i file def.Lasceremo la questione aperta, tuttavia, nel caso qualcuno sappia qualcosa non abbiamo funzioni sovraccaricate e file def.
Soluzione
Nel codice stesso, contrassegna le funzioni che desideri esportare utilizzando __declspec(dllexport).Per esempio:
#define DllExport __declspec(dllexport)
int DllExport Foo( int a ) {
// implementation
}
int DllExport Foo( int a, int b ) {
// implementation
}
In questo caso non è necessario elencare le funzioni nel file .def.
In alternativa, potresti essere in grado di utilizzare un valore di parametro predefinito, come:
int Foo( int a, int b = -1 )
Ciò presuppone che esista un valore per b che puoi utilizzare per indicare che non è utilizzato.Se -1 è un valore legale per b, o se non c'è o non dovrebbe esserci un valore predefinito, questo non funzionerà.
Modifica (Adam Haile):Corretto per utilizzare __declspec poiché __dllspec non era corretto, quindi ho potuto contrassegnarlo come risposta ufficiale... era abbastanza vicino.
Modifica (Graeme):Ops, grazie per aver corretto il mio errore di battitura!
Altri suggerimenti
L'overload delle funzioni è una funzionalità C++ che si basa sulla manipolazione dei nomi (i nomi criptici delle funzioni nei messaggi di errore del linker).
Scrivendo i nomi alterati nel file def, posso collegare ed eseguire il mio progetto di test:
LIBRARY "TestDLL"
EXPORTS
?Foo@@YAXH@Z
?Foo@@YAXHH@Z
sembra funzionare per
void Foo( int x );
void Foo( int x, int y );
Quindi copia i nomi delle funzioni C++ dal messaggio di errore e scrivili nel tuo file def.Tuttavia la vera domanda è:Perché vuoi utilizzare un file def e non utilizzare __declspec(dllexport) ?
I nomi alterati non sono portabili, ho testato con VC++ 2008.
Ho avuto un problema simile quindi volevo pubblicare anche questo.
Di solito si usa
extern "C" __declspec(dllexport) void Foo();
esportare il nome di una funzione va bene.Lo farà Generalmente Esporta il nome Unmangled senza la necessità di un file .def.Vi sono, tuttavia, alcune eccezioni come __stdcall funzioni e nomi di funzioni sovraccarichi.
Se si dichiara una funzione per utilizzare la convenzione __stdCall (come è fatto per molte funzioni API), allora
extern "C" __declspec(dllexport) void __stdcall Foo();
Esporterà un nome mangellato come _foo@4.In questo caso potrebbe essere necessario mappare esplicitamente il nome esportato in un nome interno interno.
UN.Come esportare un nome non alterato.In un file .def aggiungi
----
EXPORTS
; Explicit exports can go here
Foo
-----
Questo proverà a trovare una "corrispondenza migliore" per una funzione interna Foo e ad esportarla.Nel caso sopra in cui esiste un solo foo questo creerà la mappatura
Pippo = _Pippo@4
come si può vedere tramite dumpbin /EXPORTS
Se hai sovraccaricato un nome di funzione, potrebbe essere necessario dire esplicitamente quale funzione desideri nel file .Def specificando un nome Mangled usando la sintassi EntryName [= InternalName].per esempio.
----
EXPORTS
; Explicit exports can go here
Foo=_Foo@4
-----
B.Un'alternativa ai file .def è che puoi esportare i nomi "sul posto" utilizzando un #pragma.
#pragma comment(linker, "/export:Foo=_Foo@4")
C.Una terza alternativa è dichiarare solo una versione di Foo come extern "C" da esportare senza modifiche.Vedere Qui per dettagli.
Non esiste un modo ufficiale per fare quello che vuoi, perché l'interfaccia dll è un C api.
Il compilatore stesso utilizza nomi alterati come soluzione alternativa, quindi dovresti utilizzare la alterazione dei nomi quando non vuoi cambiare troppo nel tuo codice.
Non esiste un modo indipendente dalla lingua o dalla versione per esportare una funzione sovraccaricata poiché la convenzione di modifica può cambiare con ogni versione del compilatore.
Questo è uno dei motivi per cui la maggior parte delle funzioni WinXX hanno nomi divertenti come *Ex o *2.
La definizione di Systax per EXPORTS è:
entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA]
nomeentrata è il nome della funzione o della variabile che desideri esportare.Questo è necessario.Se il nome che esporti è diverso dal nome nella DLL, specifica il nome dell'esportazione nella DLL con internalname.
Ad esempio, se la tua DLL esporta una funzione, func1() e desideri che venga utilizzata come func2(), dovrai specificare:
EXPORTS
func2=func1
Basta vedere i nomi alterati (usando Dependency Walker) e specificare il nome della propria funzione.
Fonte: http://msdn.microsoft.com/en-us/library/hyx1zcd3(v=vs.71).aspx
Modificare:Funziona con DLL dinamiche, dove dobbiamo utilizzare GetProcAddress() per recuperare esplicitamente una funzione in Dll.