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