Question

A créé des noms DLL et exportés C ++ de base en utilisant le fichier de définition de module (MYDLL.DEF). Après la compilation je vérifie les noms des fonctions exportées à l'aide dumpbin.exe Je me attends à:

SomeFunction

mais je vois ceci:

SomeFunction = SomeFunction@@@23mangledstuff#@@@@

Pourquoi?

La fonction exportée apparaît undecorated (en particulier par rapport à ne pas utiliser le module fichier Def), mais ce qui est avec les autres trucs?

Si je dumpbin.exe contre une DLL à partir de toute application commerciale, vous obtenez le nettoyage:

SomeFunction

et rien d'autre ...

J'ai aussi essayé de retirer la définition du module et l'exportation des noms en utilisant le style « C » d'exportation, à savoir:

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

(en utilisant simplement « extern "C" n'a pas créé une fonction exportée)

Cependant, cela crée toujours la même sortie, à savoir:

SomeFunction = SomeFunction@@@23mangledstuff#@@@@

J'ai aussi essayé l'option #define dllexport __declspec(dllexport) et créé un LIB sans problème. Cependant, je ne veux pas avoir à fournir un fichier LIB aux personnes utilisant la DLL dans leur application C #.

Il est une DLL C ++ vanilles (code non géré), compilé avec rien C ++, mais un en-tête simple et code. Sans module Def Je reçois des fonctions mutilées exportées (je peux créer une bibliothèque statique et utiliser le LIB pas de problème. J'essaie d'éviter cela). Si j'utilise extern "C" __declspec(dllexport) ou une définition du module je reçois ce qui semble être un nom de fonction undecorated ... le seul problème est qu'il est suivi d'un « = » et ce qui ressemble à une version décorée du une fonction. Je veux me débarrasser des choses après le « = » - ou tout au moins comprendre pourquoi il est là.

En l'état actuel, je suis certain que je peux appeler la fonction de C # en utilisant un P / Invoke ... Je veux juste éviter cette ordure à la fin de la « = ».

Je suis ouvert aux suggestions sur la façon de modifier le projet / paramètres du compilateur, mais je viens d'utiliser le modèle standard DLL Visual Studio - rien de spécial.

Était-ce utile?

La solution

Vous pouvez obtenir ce que vous voulez en désactivant la génération d'informations de débogage. Propriétés du projet +, Linker, débogage, générer des informations de débogage = Non.

Bien sûr, vous voulez seulement faire cela pour la version Release. Lorsque l'option est déjà définie de cette façon.

Autres conseils

Au lieu d'utiliser le fichier .def il suffit d'insérer pragma comment comme ceci

#pragma comment(linker, "/EXPORT:SomeFunction=_SomeFunction@@@23mangledstuff#@@@@")

Edit: Ou encore plus facile: A l'intérieur du corps de l'utilisation de la fonction

#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)

. . . si vous avez du mal à trouver le nom de la fonction décorée. Ce dernier pragma peut encore être réduit par une simple définition de la macro.

Vous devez déclarer les fonctions que extern "C" si vous ne voulez pas que leur nom soit mutilées.

De l'expérience, soyez prudent si vous utilisez __stdcall dans votre signature de la fonction. Avec __stdcall, le nom restera mutilée dans une certaine mesure (vous trouverez assez rapidement). Apparemment, il y a deux niveaux de mutiler, une des offres de extern "C" avec au niveau C ++, mais il ne traite pas avec un autre niveau de nom mangling causé par __stdcall. Le mangling supplémentaire est apparemment utile à une surcharge -. Mais je ne suis pas certain de ce

Désolé pour répondre à un vieux fil, mais ce qui a été marquée comme la réponse ne fonctionne pas pour moi.

Comme un certain nombre de personnes ont fait remarquer, la décoration extern « C » est important. Modification du « Projet / Propriétés / Linker / Débogage / Générer les informations de débogage » paramètre fait absolument aucune différence aux noms déchiquetés généré pour moi dans les deux Debug ou Release mode construction.

Configuration: VS2005 la compilation d'une classe Visual C ++ projet de bibliothèque. Je vérifiais la sortie compilé .dll avec l'outil Dependency Walker de Microsoft.

Voici une recette exemple qui a fonctionné pour moi ...

En project.h:

#define DllExport extern "C" __declspec( dllexport )

DllExport bool API_Init();
DllExport bool API_Shutdown();

En project.cpp:

#include "project.h"

bool API_Init()
{
  return true;
}

bool API_Shutdown()
{
  return true;
}

Ensuite, être appelé à partir de C # code managé, class.cs:

using System.Runtime.Interopservices;
namespace Foo
{
    public class Project
    {
        [DllImport("project.dll")]
        public static extern bool API_Init();

        [DllImport("project.dll")]
        public static extern bool API_Shutdown();
    }
}

Faire ce qui précède a empêché les noms tronqués dans les deux Debug et le mode Release, quel que soit le paramètre Générer les informations de débogage. Bonne chance.

Même sans mutiler, 32 bits et 64 bits construit différemment les exportations de nom, même avec extern « C ». Check it out avec depends.exe.

Cela peut signifier grande difficulté à tout client qui fait un LoadLibrary + GetProcAdress pour accéder à votre fonction.

Alors, au-dessus de tous les autres utilisent un module fichier de définition comme suit:

LIBRARY MYDLL
EXPORTS
myFunction=myFunction

Ouaip, il est un peu une douleur à maintenir, mais combien de fonctions exportées écrivez-vous par jour?

De plus, je change généralement les macros comme indiqué ci-dessous, car mes fonctions DLL d'exportation non classes C ++ et je veux qu'ils soient appelable par la plupart des environnements de programmation:

#ifdef WTS_EXPORTS
#define WTS_API(ReturnType) extern "C" __declspec(dllexport) ReturnType WINAPI
#else
#define WTS_API(ReturnType) extern "C" __declspec(dllimport) ReturnType WINAPI
#endif

WTS_API(int) fnWTS(void);

La dernière ligne utilisée pour confondre VisualAssistX il y a quelques années, je ne sais pas si elle digère bien maintenant: -)

Je sais combien de fois je l'ai essayé de forcer les noms de fonction en utilisant le code et #pragma de. Et je finis toujours avec exactement la même chose, en utilisant Fichier définition de module (* .def) à la fin. Et voici la raison:

//---------------------------------------------------------------------------------------------------
// Test cases built using VC2010 - Win32 - Debug / Release << doesn't matter
//---------------------------------------------------------------------------------------------------
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = Yes (/DEBUG)
//  || (or, also doesn't matter)
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = No + delete PDB file!

extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> _SetCallback@4

__declspec(dllexport) void SetCallback(LPCALLBACK function);
> ?SetCallback@@YAXP6AXHPADPAX@Z@Z

__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> ?SetCallback@@YGXP6GXHPADPAX@Z@Z    

//---------------------------------------------------------------------------------------------------
// this also big is nonsense cause as soon you change your calling convention or add / remove
// extern "C" code won't link anymore.

// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback=SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=_SetCallback@4")
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YAXP6AXHPADPAX@Z@Z")
__declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YGXP6GXHPADPAX@Z@Z")
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);

//---------------------------------------------------------------------------------------------------
// So far only repetable case is using Module-Definition File (*.def) in all possible cases:
EXPORTS
  SetCallback

extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback

__declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback

// And by far this is most acceptable as it will reproduce exactly same exported function name 
// using most common compilers. Header is dictating calling convention so not much trouble for
// other sw/ppl trying to build Interop or similar.

Je me demande pourquoi personne ne l'a fait, il m'a fallu seulement 10 minutes pour tester tous les cas.

SomeFunction @@@ 23mangledstuff # @@@@ est mutilée pour donner les types et la classe de la fonction C ++. Les exportations simples sont des fonctions qui sont appelables de C ie sont écrits en C ou bien sont déclarés extern « C » dans le code C ++. Si est vous voulez une interface simple, vous devez faire les fonctions que vous exportez être utilisé seulement les types C et les rendre fonctions non membres de l'espace de noms global.

En fait, lorsque vous utilisez les fonctions en C ++, une partie de leurs noms incluent désormais leur signature et suchlike, afin de faciliter les fonctionnalités du langage comme la surcharge.

Si vous écrivez une DLL à l'aide __declspec (dllexport), alors il devrait également produire une lib. Lien vers cette lib, et vous serez automatiquement liés et les fonctions enregistrées par le CRT au moment de démarrage (si vous vous souveniez de changer toutes vos importations aux exportations). Vous n'avez pas besoin de connaître le nom mutiler si vous utilisez ce système.

Dans le cas où il n'a pas été clairement des centaines de lignes de gaufre sur le sujet des exportations mutilées. Voici ma valeur 2c:)

Après avoir créé un projet appelé Win32Project2 utilisant VS 2012 et en choisissant l'exportation de tous les symboles de l'assistant. Vous devriez avoir 2 fichiers appelés Win32Project2.cpp et Win32project2.h

Ces deux feront référence à un exemple de variable exportables et un exemple fonction exportée.

Dans Win32Project2.h vous aurez les éléments suivants:

#ifdef WIN32PROJECT2_EXPORTS
#define WIN32PROJECT2_API __declspec(dllexport)
#else
#define WIN32PROJECT2_API __declspec(dllimport)
#endif

extern WIN32PROJECT2_API int nWin32Project2;
WIN32PROJECT2_API int fnWin32Project2(void);

Pour changer unmangle les deux dernières lignes de déclarations extern "C" à:

extern "C" WIN32PROJECT2_API int nWin32Project2;
extern "C" WIN32PROJECT2_API int fnWin32Project2(void);

Dans Win32Project2.cpp vous aurez également les définitions par défaut suivantes:

// This is an example of an exported variable
WIN32PROJECT2_API int nWin32Project2=0;

// This is an example of an exported function.
WIN32PROJECT2_API int fnWin32Project2(void)
{
    return 42;
}

Pour changer unmangle À CEUX-CI:

// This is an example of an exported variable
extern "C" WIN32PROJECT2_API int nWin32Project2=0;

// This is an example of an exported function.
extern "C" WIN32PROJECT2_API int fnWin32Project2(void)
{
    return 42;
}

Essentiellement, vous devez utiliser le préfixe extern « C » devant des déclarations afin de forcer l'éditeur de liens C pour produire non substantypés comme les noms.

Si vous préférez utiliser des noms tronqués pour que peu de faux-fuyants supplémentaires (dans le cas où l'information est utile mutiler à quelqu'un d'une certaine façon) utiliser « dumpbin / exportations Win32Project2.dll » à partir d'une ligne de commande VC pour rechercher les noms de référence réels. Il aura la forme « ? FnWind32Project2 @ [octets param] @ [autres informations]. Il y a aussi d'autres outils de visualisation de DLL autour si vous utilisez un shell de commande VC ne flotte pas votre bateau.

Exactement pourquoi MS ne fait pas défaut à cette convention est un mystère. Les informations réelles mutiler signifie quelque chose (comme la taille du paramètre en octets et plus) qui pourrait être utile pour la validation et le débogage, mais est par ailleurs Guff.

Pour importer la fonction DLL ci-dessus dans le projet C # (dans ce cas, une application de base Windows C # avec une forme sur elle contenant le bouton « button1 ») est ici un exemple de code:

using System.Runtime.InteropServices;



    namespace AudioRecApp
    {

      public partial class Form1 : Form
      {
        [ DllImport("c:\\Projects\test\Debug\Win32Projects2.dll")] 
        public static extern int fnWin32Project2();

        public Form1()
        {
          InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
          int value;

          value = fnWin32Project2();
        }
      }
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top