2010-06-15 7 views
3

J'ai été gaven un fichier dll C++, un fichier lib et un fichier d'en-tête. Je dois les appeler depuis mon application C#.C# appelez un dll C++ get EntryPointNotFoundException

fichier d'en-tête

ressemble à ceci:

class Clog ; 

class EXPORT_MACRO NB_DPSM 
{ 
private: 
    string sFileNameToAnalyze ; 

    Clog *pLog ; 

    void write2log(string text) ; 

public: 
    NB_DPSM(void); 
    ~NB_DPSM(void); 

    void setFileNameToAnalyze(string FileNameToAnalyze) ;  
    int WriteGenbenchData(string& message) ; 
}; 

Dans mon code C#, je les code:

internal ReturnStatus correctDataDLL(string rawDataFileName) 
     { 
      if (rawDataFileName == null || rawDataFileName.Length <= 0) 
      { 
       return ReturnStatus.Return_CannotFindFile; 
      } 
      else 
      { 
       setFileNameToAnalyze(rawDataFileName);       
      } 

      string msg = ""; 
      int returnVal = WriteGenbenchData(ref msg); 


      return ReturnStatus.Return_Success; 
     } 

[DllImport("..\\..\\thirdParty\\cogs\\NB_DPSM.dll")] 
public static extern void setFileNameToAnalyze(string fileName); 


[DllImport("..\\..\\thirdParty\\cogs\\NB_DPSM.dll")] 
public static extern int WriteGenbenchData(ref string message); 

Je EntryPointNotFoundException obtenu à la déclaration setFileNameToAnalyze(rawDataFileName);.

Peu de questions:

  1. dois-je ajouter ce fichier lib dans quelque part de mon projet C#? Comment? Ai-je besoin d'ajouter le fichier d'en-tête dans mon projet C#?

  2. Comment? (aucune erreur de compilation pour l'instant)

  3. Je voudrais supprimer ces "..\\..\\thirdParty\\cogs\\" chemin de code. comment ça?

  4. comment faire pour monter de cela EntryPointNotFoundException?

grâce,

Répondre

2

Vous n'avez pas besoin d'inclure le fichier d'en-tête ou le fichier lib dans votre projet C#. Ces fichiers vous sont inutiles quand même.

La raison pour laquelle vous obtenez une exception EntryPointNotFound est que vous avez fourni des noms incorrects pour ces points d'entrée. Lorsque vous compilez un projet C++, le compilateur écrase les noms en ajoutant des informations supplémentaires sur les paramètres et les types de retour. (Vous pouvez utiliser l'utilitaire dumpbin.exe pour voir ces points d'entrée.)

Le véritable problème, cependant, est que votre DLL contient évidemment une classe C++. "setFileNameToAnalyze" et "WriteGenbenchData" sont des méthodes d'instance de cette classe, et non des fonctions statiques. Vous ne pouvez pas les appeler sans créer d'abord une instance de la classe NB_DPSM.

Il est peut-être possible de faire cela en utilisant seulement P/Invoke, mais à ce stade, je pense que c'est probablement plus de problèmes que ça en vaut la peine. Vous devez créer une bibliothèque de classes C++ gérée pour envelopper l'ancienne DLL à la place. En ce qui concerne la partie (3) de votre question, supprimez simplement les chemins et assurez-vous que NB_DPSM.dll réside dans le même répertoire bin que le résultat de vos fichiers de sortie.

2

Placez les fonctions en dehors de toutes les classes (comme fonctions globales) et dans un bloc extern "C" { ... }.

Vous n'avez pas besoin du fichier d'en-tête en C#. (C'est ce que fait le [DllImport])

+0

pourquoi avoir besoin du bloc "extern" C "{}" ? – 5YrsLaterDBA

+3

@ 5YrsLaterDBA: Pour éviter [name mangling] (http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_C.2B.2B). – SLaks

2

pourrait essayer de rendre votre propre C non géré ++ dll comme Shim, en utilisant la dll fournie ont 1 méthode

extern "C" int GenBenchData(const string &filename, string & message){ 
    NB_DPSM builder; 
    builder.setFileNameToAnalyze(filename); 
    return builder.WriteGenbenchData(message); 
} 

en C#, vous déclarez que avec

[DllImport("shim.dll", CharSet = CharSet.Auto)] 
static extern int GenBenchData([MarshalAs(UnmanagedType.LPStr)]string filename, StringBuilder message); 
1

Aussi méfiez-vous de la calling convention. Si votre DLL est vraiment C++, utilisez un outil pour visualiser les noms exportés (comme depends.exe référencé dans l'article lié). Chaque compilateur C++ a son propre schéma de décoration ce qui le rend un peu fastidieux à adapter. Vous pouvez également utiliser un assembly C++ géré par wrapper qui lie à la DLL C++. Si c'est juste une interface C prenez soin de la convention d'appel et de la taille des caractères (piège commun: un long en C# est 64bit en C/C++ il est 32bit)