EntryPointNotFoundException when binding C++ dll i

2019-01-25 12:25发布

问题:

I try to bind a simple c++ dll shown in http://msdn.microsoft.com/en-us/library/ms235636.aspx in my c# console app, but I get a EntryPointNotFoundException for Add within dll at runtime. My test class is

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));
        }
    }
}

What is not correct?

回答1:

You could try declaring the functions outside of a class and also exporting them with extern "C":

Header:

// 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);
}

Implementation:

// 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;
    }
}

Calling code:

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));
        }
    }
}


回答2:

In cases such as this, you can download Dependency Walker, load your DLL into it and look at the Export Functions list. You can also use DumpBin for this.

By default, function exported from a C++ or C DLL are using Name Decoration (also called Name Mangling).

As said on MSDN:

A decorated name for a C++ function contains the following information:

  • The function name.
  • The class that the function is a member of, if it is a member function. This may include the class that encloses the function's class, and so on.
  • The namespace the function belongs to (if it is part of a namespace).
  • The types of the function's parameters.
  • The calling convention.
  • The return type of the function.

So decorated name for your Add function, for example, will look like Add@MyMathFuncs@MathFuncs@@SANNN@Z.

But it is possible to force the C++ compiler to expose undecorated names for C++ functions by enclosing the function, and any function prototypes, within an extern "C" {…} block, as Darin Dimitrov suggested.

Although if you're going to use a third-party DLL (so you can't modify it) or you just don't want to expose decorated names for some reason, you can specify the function's name explicitly:

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