web-dev-qa-db-fra.com

Impossible de trouver un point d'entrée lors de l'appel de la DLL C++ en C #

J'essaie d'apprendre P/Invoke, alors j'ai créé une simple DLL en C++

KingFucs.h:

namespace KingFuncs
{
    class KingFuncs
    {
    public:
        static __declspec(dllexport) int GiveMeNumber(int i);
    };
}

KingFuns.cpp:

#include "KingFuncs.h"
#include <stdexcept>

using namespace std;

namespace KingFuncs
{
    int KingFuncs::GiveMeNumber(int i)
    {
        return i;
    }
}

Donc, il compile, puis j'ai copié cette dll dans le dossier de débogage de mon WPF, avec le code:

[DllImport("KingFuncDll.dll", EntryPoint = "GiveMeNumber", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern int GiveMeNumber(
              int i
              );

Et en appelant le bouton, cliquez sur:

private void Button_Click(object sender, RoutedEventArgs e)
{
    int num = GiveMeNumber(123);
}

Mais cela me donne une exception:

Impossible de trouver un point d'entrée nommé 'GiveMeNumber' dans DLL 'KingFuncDll.dll'.

Vraiment .... qu'est-ce que j'ai mal fait ... Il est évidemment capable de trouver la DLL, sinon serait une autre exception. Mais mon nom de méthode est exactement le même… Je ne peux pas penser à une autre raison.

15
King Chan

Vous devez utiliser extern "C" lorsque vous exportez votre fonction afin de supprimer le changement de nom C++. Et vous ne devriez pas non plus essayer d’appeler/invoquer des membres d’une classe. Utilisez des fonctions libres à la place:

extern "C" {
    __declspec(dllexport) int GiveMeNumber(int i)
    {
        return i;
    }
}

Du côté géré, votre attribut DllImport est tout faux. N'utilisez pas SetLastError, réservé aux API Win32. Ne dérangez pas le réglage CharSet s'il n'y a pas de paramètres de texte. Pas besoin de ExactSpelling. Et la convention d'appel est probablement Cdecl.

[DllImport("KingFuncDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int GiveMeNumber(int i);
33
David Heffernan

Le nom du point d'entrée d'un fichier dll est donné dans le fichier .exp qui se trouve dans le dossier de débogage où d'autres fichiers source sont présents. Si dumpbin ne fonctionne pas, vous pouvez essayer ceci.

0

Le problème est que vous déclarez la "fonction" C++ dans une classe C++ et dites à P/Invoke d'utiliser StdCall.

Essayez de déclarer une fonction C++ en dehors d'une classe et de l'exporter comme vous l'avez fait. Ensuite, votre code devrait fonctionner.

Si vous devez réellement avoir une fonction C++ dans une classe, consultez CallingConvention.ThisCall. Mais ensuite, vous êtes responsable de la création de votre instance de classe non gérée et de la transmettre comme premier paramètre de votre appel P/Invoke.

0
Pedro