11

我尝试在我的 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));
        }
    }
}

什么不正确?

4

2 回答 2

19

您可以尝试在类之外声明函数并使用以下命令导出它们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));
        }
    }
}
于 2012-10-15T09:28:32.020 回答
7

在这种情况下,您可以下载Dependency Walker,将您的 DLL 加载到其中并查看 Export Functions 列表。您也可以为此使用DumpBin

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

正如MSDN上所说:

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

  • 函数名称。
  • 函数所属的类(如果它是成员函数)。这可能包括包含函数类的类,等等。
  • 函数所属的命名空间(如果它是命名空间的一部分)。
  • 函数参数的类型。
  • 调用约定。
  • 函数的返回类型。

Add例如,您的函数的修饰名称将如下所示Add@MyMathFuncs@MathFuncs@@SANNN@Z

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

尽管如果您要使用第三方 DLL(因此您不能修改它)或者您只是出于某种原因不想公开修饰名称,您可以明确指定函数的名称:

[DllImport("MathFuncsDll.dll", EntryPoint = "Add@MyMathFuncs@MathFuncs@@SANNN@Z")]
public static extern double Add(double a, double b);
于 2012-10-15T10:25:56.133 回答