web-dev-qa-db-ja.com

C#でC ++ dllを呼び出すときにエントリポイントが見つかりません

P/Invokeを学習しようとしているので、C++で単純なDLLを作成しました

KingFucs.h:

namespace KingFuncs
{
    class KingFuncs
    {
    public:
        static __declspec(dllexport) int GiveMeNumber(int i);
    };
}

KingFuns.cpp:

#include "KingFuncs.h"
#include <stdexcept>

using namespace std;

namespace KingFuncs
{
    int KingFuncs::GiveMeNumber(int i)
    {
        return i;
    }
}

したがって、コンパイルされた後、次のコードを使用して、このdllをWPFのデバッグフォルダーにコピーしました。

[DllImport("KingFuncDll.dll", EntryPoint = "GiveMeNumber", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern int GiveMeNumber(
              int i
              );

そしてボタンクリックでそれを呼び出す:

private void Button_Click(object sender, RoutedEventArgs e)
{
    int num = GiveMeNumber(123);
}

しかし、それは私に例外を与えます:

DLL 'KingFuncDll.dll'で 'GiveMeNumber'という名前のエントリポイントが見つかりません。

本当に....何が悪いのでしょうか... DLLを見つけることができるのは明らかですが、それ以外の場合は別の例外になります。しかし、私のメソッド名はまったく同じです。他の理由は考えられません。

19
King Chan

C++名のマングリングを抑制するために、関数をエクスポートするときはextern "C"を使用する必要があります。また、クラスのメンバーにp/invokeを実行しないでください。代わりに無料の関数を使用してください:

extern "C" {
    __declspec(dllexport) int GiveMeNumber(int i)
    {
        return i;
    }
}

管理側では、DllImport属性がすべて間違っています。 Win32 API専用のSetLastErrorを使用しないでください。テキストパラメータがない場合は、CharSetを設定しないでください。 ExactSpellingは必要ありません。そして、呼び出し規約はおそらくCdeclです。

[DllImport("KingFuncDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int GiveMeNumber(int i);
33
David Heffernan

Dllファイルのエントリポイント名は、他のソースファイルが存在するデバッグフォルダーにある.expファイルで指定されます。 dumpbinが機能しない場合は、これを試すことができます。

0

問題は、C++クラス内でC++「関数」を宣言し、P/InvokeにStdCallを使用するように指示していることです。

クラスの外でC++関数を宣言し、あなたがしたようにそれをエクスポートしてみてください。その後、コードは機能するはずです。

クラス内にC++関数が本当に必要な場合は、CallingConvention.ThisCallをご覧ください。ただし、アンマネージクラスインスタンスを作成し、それをP/Invoke呼び出しの最初のパラメーターとして渡す必要があります。

0
Pedro