2012-10-15 8 views
5

http://msdn.microsoft.com/en-us/library/ms235636.aspxに表示される単純なC++ DLLをC#コンソールアプリケーションにバインドしようとしましたが、実行時にDLL内でEntryPointNotFoundExceptionが発生します。私のテストクラスはC#でDLLをバインドするときにEntryPointNotFoundExceptionが発生する

namespace BindingCppDllExample 
{ 
    public class BindingDllClass 
    { 
     [DllImport("MathFuncsDll.dll")] 
     public static extern double Add(double a, double b); 
    } 

    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      double a = 2.3; 
      double b = 3.8; 
      double c = BindingDllClass.Add(a, b); 

      Console.WriteLine(string.Format("{0} + {1} = {2}", a, b, c)); 
     } 
    } 
} 

です。どういうところが間違っていますか?

+0

が重複する可能性:http://stackoverflow.com/questions/5877349/pinvoke-and-entrypointnotfoundexception – Star

+0

私はあなたのCallingConventionが一致していないことを推測するつもりです。私はまた、MathFuncsDll.dllが 'Add'という名前のメソッドをエクスポート可能として宣言していないと仮定します。 –

答えて

13

あなたはクラスの外の関数を宣言してもextern "C"でそれらを輸出してみてください:

ヘッダー:

// MathFuncsDll.h 
namespace MathFuncs 
{ 
    // Returns a + b 
    extern "C" __declspec(dllexport) double Add(double a, double b); 

    // Returns a - b 
    extern "C" __declspec(dllexport) double Subtract(double a, double b); 

    // Returns a * b 
    extern "C" __declspec(dllexport) double Multiply(double a, double b); 

    // Returns a/b 
    // Throws DivideByZeroException if b is 0 
    extern "C" __declspec(dllexport) double Divide(double a, double b); 
} 

実装:コードを呼び出す

// MyMathFuncs.cpp 
#include "MathFuncsDll.h" 
#include <stdexcept> 

using namespace std; 

namespace MathFuncs 
{ 
    double Add(double a, double b) 
    { 
     return a + b; 
    } 

    double Subtract(double a, double b) 
    { 
     return a - b; 
    } 

    double Multiply(double a, double b) 
    { 
     return a * b; 
    } 

    double Divide(double a, double b) 
    { 
     if (b == 0) 
     { 
      throw new invalid_argument("b cannot be zero!"); 
     } 

     return a/b; 
    } 
} 

namespace BindingCppDllExample 
{ 
    public class BindingDllClass 
    { 
     [DllImport("MathFuncsDll.dll")] 
     public static extern double Add(double a, double b); 
    } 

    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      double a = 2.3; 
      double b = 3.8; 
      double c = BindingDllClass.Add(a, b); 

      Console.WriteLine(string.Format("{0} + {1} = {2}", a, b, c)); 
     } 
    } 
} 
+0

ありがとう!しかし、私は大きなクラスを持っているなら、私が使いたいすべてのメソッドをラップする必要がありますね。 – alex555

+0

名前空間で整理できます。私はあなたがP/Invokeを使用してC++クラスのメソッドを呼び出すことはできないと考えています。P/Invokeはアンマネージコード(クラスの概念が存在しないプレーンCを含む)を呼び出すために作成されたからです。したがって、アンマネージコードでクラスを使用することはできますが、マネージコードから呼び出す必要のある関数のみを公開することができます。 –

5

このような場合は、Dependency Walkerをダウンロードし、DLLを読み込み、[エクスポート関数]リストを参照してください。これにはDumpBinを使用することもできます。

デフォルトでは、C++またはC DLLからエクスポートされた関数はName DecorationName Manglingとも呼ばれます)を使用しています。

としてはMSDNに言った:

  • 関数名:

    Cのために装飾された名前++関数は、次の 情報が含まれています。

  • 関数がメンバ関数である場合、その関数がメンバであるクラス。これには、関数のクラスを囲むクラスなどが含まれます。
  • 関数が属する名前空間(名前空間の一部である場合)。
  • 関数のパラメータの型。
  • 呼び出し規約。
  • 関数の戻り値の型。

だからあなたAdd関数の装飾の名前は、例えば、[email protected]@[email protected]@[email protected]次のようになります。

しかし、Darin Dimitrovが示唆したように、extern "C" {…}ブロック内に関数と関数プロトタイプを囲むことで、C++関数の未修飾の名前を公開するように強制することは可能です。

サードパーティのDLLを使用して(修正できないので)、何らかの理由で装飾された名前を公開したくない場合は、その関数の名前を明示的に指定することができます:

[DllImport("MathFuncsDll.dll", EntryPoint = "[email protected]@[email protected]@[email protected]")] 
public static extern double Add(double a, double b); 
+0

私はdumpbinを使っていましたが、どうしたらいいのか分かりませんでした。 EntryPointのアドバイスをありがとう – alex555

関連する問題