11

c#コンソールアプリでhttp://msdn.microsoft.com/en-us/library/ms235636.aspxに表示されている単純なc ++ dllをバインドしようとしましたが、実行時にdll内にAddの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をロードして、[エクスポート機能]リストを確認できます。これにはDumpBinを使用することもできます。

デフォルトでは、C++またはCDLLからエクスポートされた関数は、名前装飾(名前マングリングとも呼ばれます)を使用しています。

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 に答える