【问题标题】:EntryPointNotFoundException when binding C++ dll in C#在 C# 中绑定 C++ dll 时出现 EntryPointNotFoundException
【发布时间】:2012-10-05 05:29:50
【问题描述】:

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

什么不正确?

【问题讨论】:

标签: c# dllimport entrypointnotfoundexcept


【解决方案1】:

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

【讨论】:

  • 谢谢!但是,如果我有大型类,我将不得不包装我想使用的所有方法,不是吗?
  • 您可以在命名空间中组织它们。我认为您不能使用 P/Invoke 调用 C++ 类方法,因为创建 P/Invoke 是为了调用任何非托管代码(包括不存在类概念的纯 C)。因此,您仍然可以在非托管代码中使用类,但只公开需要从托管代码中调用的函数。
【解决方案2】:

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

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

MSDN所说:

C++ 函数的修饰名称包含以下内容 资料:

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

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

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

虽然如果你打算使用第三方 DLL(所以你不能修改它)或者你只是出于某种原因不想暴露修饰的名字,你可以明确地指定函数的名字:

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

【讨论】:

  • 我使用了dumpbin,但不知道如何处理它。感谢 EntryPoint 的好建议
猜你喜欢
  • 2021-04-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 2021-09-23
  • 1970-01-01
相关资源
最近更新 更多