C3374:デリゲートインスタンスを作成しない限り、「関数」のアドレスを取得できません
質問
サードパーティのライブラリ登録関数を使用してコールバックを登録するのが困難です。C++ CLI で記述しており、C または C++ で記述されたライブラリにアクセスしています。
上記のコンパイラエラーは何を意味するのでしょうか?
これはベンダーによって定義された登録関数です。
MYCO int WINAPI MyCo_Device_Register_CallbackFunc(LPVOID func, LPVOID lpParam, DWORD mask);
これはベンダーによって定義されたコールバックです。
typedef void (CALLBACK* MyCo_Device_CallbackProc)(DWORD ddStatus, LPVOID lpParam);
私のコールバック関数:
public ref class Device
{
void CallBackFunc(DWORD ddStatus, LPVOID lpParam) {};
}
私の呼び出し(失敗):
MyCo_Device_Register_CallbackFunc((LPVOID) Device::CallBackFunc, nullptr, 0xFFFF);
解決
推測を行わなければならなかった場合、管理対象関数のアドレスを取得し、それをネイティブ関数ポインターとして渡そうとしています。それはまったく機能しません。ネイティブブリッジを作成するか(より難しく、おそらく利点がない)、または(これがより簡単なアプローチです)、デリゲートを作成して Marshal.GetFunctionPointerForDelegate 。デリゲートは、ネイティブコードがコールバックする予定の期間、生き続ける必要があることを忘れないでください。そのため、おそらくどこかに保存する必要があります。
ああ、refクラスまたはvalueクラス内のすべての関数は、明確でない場合に備えてマネージ関数です。
[編集]回答を拡大してコメントの質問をカバーします。最初のステップは、一致するデリゲートを作成することです。指定した関数については、次のようになります。
public delegate void CallbackFuncDelegate(DWORD ddStatus, LPVOID lpParam);
次に、作成する必要があります:
CallbackFuncDelegate del = gcnew CallbackFuncDelegate(CallbackFunc);
前述のように、クラスが消失しないことを確認するために、そのINをメンバーとして保存する必要があります。最後に、関数ポインタを取得して渡す必要があります。
MyCo_Device_Register_CallbackFunc((MyCo_Device_CallbackProc) Marshal::GetFunctionPointerForDelegate(del).ToPointer(), 0, 0);
これですべてがカバーされると思います。名前空間システムを使用するだけです。大丈夫です。
他のヒント
コールバック関数はメンバーです。メンバーへのポインターと関数へのポインターは別のものです。
Promit のソリューションでも次のようになります。
CallbackFuncDelegate(CallbackFunc)
CallbackFunc をクラス メンバーにすることはできません
シンプルに書くこともできます
public ref class Device
{
static void CallBackFunc(DWORD ddStatus, LPVOID lpParam) {};
}
そして使用します
Device::CallBackFunc