在C#中绑定C ++ DLL时的EntryPointNotFoundException

我尝试在我的c#控制台应用程序中绑定http://msdn.microsoft.com/en-us/library/ms235636.aspx中显示的简单c ++ dll,但是在运行时我在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)); } } } 

什么是不正确的?

您可以尝试在类外声明函数,并使用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  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)); } } } 

在这种情况下,您可以下载Dependency Walker ,将DLL加载到其中并查看“导出函数”列表。 您也可以使用DumpBin 。

默认情况下,从C ++或C DLL导出的函数使用名称修饰 (也称为名称管理 )。

正如在MSDN上所说:

C ++函数的修饰名称包含以下信息:

  • function名称。
  • 函数所属的类,如果是成员函数。 这可能包括包含函数类的类,依此类推。
  • 函数所属的命名空间(如果它是命名空间的一部分)。
  • 函数参数的类型。
  • 呼召惯例。
  • 函数的返回类型。

例如, Add函数的装饰名称将类似于Add@MyMathFuncs@MathFuncs@@SANNN@Z

但正如Darin Dimitrov所建议的那样,通过将函数和任何函数原型包含在extern "C" {…}块中,可以强制C ++编译器公开C ++函数的未修饰名称。

虽然如果您要使用第三方DLL(因此无法修改它),或者您只是因为某些原因不想公开装饰名称,您可以明确指定函数的名称:

 [DllImport("MathFuncsDll.dll", EntryPoint = "Add@MyMathFuncs@MathFuncs@@SANNN@Z")] public static extern double Add(double a, double b);