Question

Je voudrais un exemple simple d'exporter une fonction à partir d'une fenêtre C ++ DLL.

Je voudrais voir l'en-tête, le fichier cpp, et le fichier def (si cela est absolument nécessaire).

Je voudrais que le nom exporté pour être undecorated . Je voudrais utiliser la convention d'appel le plus standard (__stdcall?). Je voudrais l'utilisation __ declspec (dllexport) et ne pas avoir à utiliser un 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 l'éditeur des liens underscores et / ou de chiffres (comptage d'octets?) Au nom.

Je suis OK avec ne supportant pas dllimport et dllexport en utilisant la même tête. Je ne veux pas d'informations sur l'exportation des méthodes de la classe C de, juste des fonctions globales c-style.

UPDATE

Non compris la convention d'appel (et en utilisant extern « C ») me donne les noms d'exportation comme je l'aime, mais qu'est-ce que cela signifie? Est-ce que par défaut la convention d'appel que je reçois ce PInvoke (.NET), déclarer (VB6) et GetProcAddress s'attendre? (Je suppose que pour GetProcAddress cela dépend de la fonction pointeur de l'appelant créé).

Je veux que cette DLL à utiliser sans fichier d'en-tête, donc je ne vois vraiment pas besoin de beaucoup de fantaisie #defines pour rendre l'en-tête utilisable par un appelant.

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

Était-ce utile?

La solution

Si vous voulez les exportations C ordinaire, utilisez un projet C ++ non C. C ++ DLLs comptent sur le nom-mutiler pour tous les ismes C ++ de (namespaces etc ...). Vous pouvez compiler votre code en C en allant dans les paramètres de votre projet sous C / C ++ -> Avancé, il y a une option "Compile Comme" qui cooresponds aux commutateurs du compilateur / TP et / TC

.

Exportation / importation DLL Libs dans VC ++

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

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

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

LIBRARY_API int GetCoolInteger();

Dans votre projet de construction de la bibliothèque de créer une LIBRARY_EXPORTS définir cela entraînera vos fonctions à exporter pour votre build DLL.

Depuis LIBRARY_EXPORTS ne sera pas définie dans un projet consommant la DLL, lorsque ce projet inclut le fichier d'en-tête de votre bibliothèque toutes les fonctions seront importées à la place.

Si votre bibliothèque est d'être multi-plateforme, vous pouvez définir LIBRARY_API comme rien lorsqu'ils ne sont 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

Lors de l'utilisation dllexport / dllimport vous n'avez pas besoin d'utiliser des fichiers DEF, si vous utilisez des fichiers DEF vous n'avez pas besoin d'utiliser dllexport / dllimport. Les deux méthodes accomplir la même tâche de différentes façons, je crois que dllexport / dllimport est la méthode recommandée sur les deux.

Exportation fonctions non substantypés à partir d'une DLL C ++ pour LoadLibrary / PInvoke

Si vous avez besoin d'utiliser ce LoadLibrary et GetProcAddress, ou faire PInvoke de .NET, vous pouvez peut-être utiliser en ligne de extern "C" avec votre dllexport. Et puisque nous utilisons GetProcAddress au lieu de dllimport nous ne devons faire la danse ifdef d'en haut, 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<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
  );
}

Et voici ce que les exportations ressemblent 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)

ce code fonctionne très bien:

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")
);

Autres conseils

Pour C ++:

Je viens face à la même question et je pense qu'il est utile de mentionner un problème survient quand on utilise les deux __stdcall (ou WINAPI) et extern "C":

Comme vous le savez extern "C" supprime la décoration de sorte qu'au lieu de:

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

vous obtenez un nom de symbole undecorated:

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

Cependant, la _stdcall (= WINAPI macro, qui modifie la convention d'appel) décore aussi les noms de sorte que si nous utilisons à la fois, nous obtenons:

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

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

  

Notez que ce que se produit pour l'architecture x86, car   la convention __stdcall est ignorée sur x64 ( msdn : sur x64 architectures, par convention, les arguments sont passés dans des registres lorsque cela est possible, et les arguments suivants sont passés sur la pile .).

Ceci est particulièrement délicat si vous ciblez les deux 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. la façon la plus simple: définir la macro (voir msdn ):

  

#define commentaire EXPORT (linker, "/ EXPORT:" __FUNCTION__ "="   __FUNCDNAME __)

et ensuite inclure le pragma suivant dans le corps de la fonction:

#pragma EXPORT

Exemple complet:

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

exportera la fonction undecorated pour les deux cibles x86 et x64, tout en préservant la convention __stdcall pour x86. Le __declspec(dllexport) n'est pas nécessaire dans ce cas.

J'ai eu exactement le même problème, ma solution était d'utiliser un 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 fait

Je pense que _naked pourrait obtenir ce que vous voulez, mais il empêche également le compilateur de générer le code de gestion de la pile pour la fonction. extern "C" provoque la décoration de nom de style C. Retirez et que cela devrait se débarrasser de vos _ de. L'éditeur de liens n'ajoute pas les underscores, le compilateur fait. stdcall provoque la taille de la pile des arguments à ajouter.

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

La grande question est de savoir pourquoi voulez-vous faire? Quel est le problème avec les noms déchiquetés?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top