2012-10-15 72 views
5

我嘗試在我的c#控制檯應用程序中綁定http://msdn.microsoft.com/en-us/library/ms235636.aspx中顯示的簡單C++ dll,但在運行時在DLL中添加EntryPointNotFoundException。我的測試課程是EntryPointNotFoundException當在C#中綁定C++ dll時

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並查看Export Functions列表。您也可以使用DumpBin

默認情況下,從C++或C DLL導出的函數使用Name Decoration(也稱爲Name Mangling)。

正如上MSDN說:

用於C A修飾名++函數包含以下 信息:

  • 函數名稱。
  • 函數是成員函數的類,如果它是成員函數。這可能包括封裝函數的類的類,等等。
  • 函數所屬的名稱空間(如果它是名稱空間的一部分)。
  • 函數參數的類型。
  • 調用約定。
  • 函數的返回類型。

所以裝飾名稱爲您Add的功能,例如,看起來像[email protected]@[email protected]@[email protected]

但是,如Darin Dimitrov建議的那樣,可以強制C++編譯器通過在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