Exportation de fonctions à partir d’une DLL avec dllexport

Je voudrais un exemple simple d’exportation d’une fonction à partir d’une DLL Windows C ++.

J’aimerais voir l’en-tête, le fichier cpp et le fichier def (si absolument nécessaire).

Je voudrais que le nom exporté ne soit pas décoré . Je voudrais utiliser la convention d’appel la plus standard (__stdcall?). Je voudrais utiliser __declspec (dllexport) et ne pas avoir à utiliser de fichier DEF.

Par exemple:

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

J’essaie d’éviter que le lieur ajoute des traits de soulignement et / ou des chiffres (nombre d’octets?) Au nom.

Je suis d’accord pour ne pas supporter dllimport et dllexport en utilisant le même en-tête. Je ne veux pas d’informations sur l’exportation de méthodes de classe C ++, mais uniquement sur les fonctions globales de style c.

METTRE À JOUR

Ne pas inclure la convention d’appel (et en utilisant extern “C”) me donne les noms d’exportation comme je veux, mais qu’est-ce que cela signifie? Quelle que soit la convention d’appel par défaut, je reçois ce que pinvoke (.NET), declare (vb6) et GetProcAddress attendent? (Je suppose que pour GetProcAddress, cela dépend du pointeur de fonction créé par l’appelant).

Je veux que cette DLL soit utilisée sans fichier d’en-tête, donc je n’ai pas vraiment besoin de beaucoup de #defines pour rendre l’entête utilisable par un appelant.

Je suis OK avec une réponse étant que je dois utiliser un fichier DEF.

Si vous souhaitez des exportations en langage C, utilisez un projet C et non C ++. Les DLL C ++ reposent sur la gestion des noms pour tous les isms C ++ (espaces de noms, etc.). Vous pouvez comstackr votre code en C en allant dans les parameters de votre projet sous C / C ++ -> Avancé, il y a une option “Comstackr en tant que” qui correspond aux commutateurs / TP et / TC du compilateur.

Exportation / importation de bibliothèques DLL dans VC ++

Ce que vous voulez vraiment faire est de définir une macro conditionnelle dans un en-tête qui sera incluse dans tous les fichiers source de votre projet DLL:

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

Ensuite, sur une fonction que vous souhaitez exporter, vous utilisez LIBRARY_API :

 LIBRARY_API int GetCoolInteger(); 

Dans votre projet de génération de bibliothèque, créez une définition LIBRARY_EXPORTS cela entraînera l’exportation de vos fonctions pour votre compilation DLL.

Puisque LIBRARY_EXPORTS ne sera pas défini dans un projet utilisant la DLL, lorsque ce projet inclut le fichier d’en-tête de votre bibliothèque, toutes les fonctions seront imscopes à la place.

Si votre bibliothèque doit être multi-plateforme, vous pouvez définir LIBRARY_API comme rien si vous n’êtes pas sous Windows:

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

Lorsque vous utilisez dllexport / dllimport, vous n’avez pas besoin d’utiliser les fichiers DEF, si vous utilisez des fichiers DEF, vous n’avez pas besoin d’utiliser dllexport / dllimport. Les deux méthodes accomplissent la même tâche de différentes manières, je pense que dllexport / dllimport est la méthode recommandée parmi les deux.

Exportation de fonctions non liées depuis une DLL C ++ pour LoadLibrary / PInvoke

Si vous en avez besoin pour utiliser LoadLibrary et GetProcAddress, ou peut-être faire PInvoke à partir de .NET, vous pouvez utiliser extern "C" ligne avec votre dllexport. Et comme nous utilisons GetProcAddress au lieu de dllimport, nous n’avons pas besoin de faire la danse ifdef par dessus, juste un simple dllexport:

Le code:

 #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(new OpenGLGraphicsDriver()) ); } 

Et voici à quoi ressemblent les exportations avec Dumpbin / exports:

  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) 

Donc, ce code fonctionne bien:

 m_hDLL = ::LoadLibrary(T"opengl_plugin.dll"); m_pfnGetEngineVersion = reinterpret_cast( ::GetProcAddress(m_hDLL, "getEngineVersion") ); m_pfnRegisterPlugin = reinterpret_cast( ::GetProcAddress(m_hDLL, "registerPlugin") ); 

Pour C ++:

Je viens de faire face au même problème et je pense qu’il est utile de mentionner qu’un problème survient lorsque l’on utilise à la fois __stdcall (ou WINAPI ) et extern "C" :

Comme vous le savez, extern "C" supprime la décoration pour qu’au lieu de:

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

vous obtenez un nom de symbole non décoré:

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

Cependant, le _stdcall (= macro WINAPI, qui modifie la convention d’appel) décore également les noms de sorte que si nous utilisons les deux, nous obtenons:

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

et le bénéfice de extern "C" est perdu car le symbole est décoré (avec _ @bytes)

Notez que cela ne se produit que pour l’architecture x86 car la convention __stdcall est ignorée sur x64 ( msdn : sur les architectures x64, par convention, les arguments sont transmis dans les registres lorsque cela est possible et les arguments suivants sont transmis à la stack ).

Cela est particulièrement délicat si vous ciblez les plates-formes x86 et x64.


Deux solutions

  1. Utilisez un fichier de définition. Mais cela vous oblige à maintenir l’état du fichier def.

  2. le plus simple: définir la macro (voir msdn ):

#define commentaire EXPORT (éditeur de liens “/ EXPORT:” __FUNCTION__ “=” __FUNCDNAME__)

puis inclure le pragma suivant dans le corps de la fonction:

 #pragma EXPORT 

Exemple complet:

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

Cela exportera la fonction non décorée pour les cibles x86 et x64 tout en conservant la convention __stdcall pour x86. Le __declspec(dllexport) n’est pas requirejs dans ce cas.

J’ai eu exactement le même problème, ma solution consistait à utiliser le fichier de définition de module (.def) au lieu de __declspec(dllexport) pour définir les exportations ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). Je ne sais pas pourquoi cela fonctionne, mais il le fait

Je pense que _naked peut obtenir ce que vous voulez, mais il empêche également le compilateur de générer le code de gestion de la stack pour la fonction. extern “C” provoque une décoration de nom de style C. Supprimez cela et cela devrait vous débarrasser de vos _’s. L’éditeur de liens n’ajoute pas les traits de soulignement, contrairement au compilateur. stdcall entraîne l’ajout de la taille de la stack d’arguments.

Pour plus d’informations, voir: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

La plus grande question est pourquoi tu veux faire ça? Quel est le problème avec les noms mutilés?