EntryPointNotFoundException при связывании C++ DLL в C#

Я пытаюсь связать простую dll C++, показанную в http://msdn.microsoft.com/en-us/library/ms235636.aspx в моем консольном приложении C#, но я получаю исключение EntryPointNotFoundException для Add в 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));
        }
    }
}

Что не правильно?

2 ответа

Решение

Вы можете попробовать объявить функции вне класса, а также экспортировать их с 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));
        }
    }
}

В таких случаях вы можете скачать Dependency Walker, загрузить в него свою DLL и посмотреть список функций экспорта. Вы также можете использовать DumpBin для этого.

По умолчанию функции, экспортируемые из DLL C++ или C, используют оформление имен (также называемое преобразованием имен).

Как сказано в MSDN:

Декорированное имя для функции C++ содержит следующую информацию:

  • Название функции.
  • Класс, членом которого является функция, если она является функцией-членом. Это может включать в себя класс, который включает класс функции, и так далее.
  • Пространство имен, к которому принадлежит функция (если оно является частью пространства имен).
  • Типы параметров функции.
  • Соглашение о вызовах.
  • Тип возврата функции.

Так украшено название для вашего Add функция, например, будет выглядеть Add@MyMathFuncs@MathFuncs@@SANNN@Z,

Но можно заставить компилятор C++ отображать недекорированные имена для функций C++, заключая функцию и любые прототипы функций в пределах extern "C" {…} блок, как предложил Дарин Димитров.

Хотя, если вы собираетесь использовать стороннюю DLL-библиотеку (то есть вы не можете ее изменить) или просто не хотите по каким-то причинам выставлять декорированные имена, вы можете явно указать имя функции:

[DllImport("MathFuncsDll.dll", EntryPoint = "Add@MyMathFuncs@MathFuncs@@SANNN@Z")]
public static extern double Add(double a, double b);
Другие вопросы по тегам