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を見つけることができるのは明らかですが、それ以外の場合は別の例外になります。しかし、私のメソッド名はまったく同じです。他の理由は考えられません。
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);
Dllファイルのエントリポイント名は、他のソースファイルが存在するデバッグフォルダーにある.expファイルで指定されます。 dumpbinが機能しない場合は、これを試すことができます。
問題は、C++クラス内でC++「関数」を宣言し、P/InvokeにStdCallを使用するように指示していることです。
クラスの外でC++関数を宣言し、あなたがしたようにそれをエクスポートしてみてください。その後、コードは機能するはずです。
クラス内にC++関数が本当に必要な場合は、CallingConvention.ThisCallをご覧ください。ただし、アンマネージクラスインスタンスを作成し、それをP/Invoke呼び出しの最初のパラメーターとして渡す必要があります。