アプリケーションに mono 2.10.8 を埋め込んでいますが、登録されている機能に問題があります。mono_add_internal_call
私がメソッドを管理しているとしましょう:
internal delegate void Win32ServiceHandler(long statusCode);
internal static class Win32Service
{
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void Test(Win32ServiceHandler handler);
}
それは管理されていない定義です:
void icall_TestDelegateCallback(MonoDelegate *ftn) {
LPHANDLER_FUNCTION f = (LPHANDLER_FUNCTION)mono_delegate_to_ftnptr(ftn);
f(SERVICE_CONTROL_STOP);
}
テストするコード:
protected virtual void ServiceHandler(Win32ServiceControl statusCode)
{
Console.WriteLine("here");
}
public void MakeTest()
{
Console.WriteLine("before");
Win32Service.Test(this.ServiceHandlerInternal);
Console.WriteLine("after");
}
コンソール アプリケーションから実行し、MakeTest() を呼び出すと、出力は次のようになります。
before
here
そして、アプリケーションは決して戻りません。
実際には単純化された例です。実際のプログラムでは、関数ポインターをコールバックとして渡す必要があるRegisterServiceCtrlHandler
ため、mono_runtime_invoke
(btw は正常に動作します) などは必要ありません。
問題は、MonoDelegate から取得した関数ポインターを呼び出す適切な方法は何ですか? または、それをコールバックとして渡す他の正しい方法はありますか?
私のプラットフォームは Windows 7 x64 です
更新:
興味深い発見。コードを次のように変更したら:
internal static class Win32Service
{
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void Test(Action handler);
}
と
typedef VOID (*TESTFTN)();
void icall_TestDelegateCallback(MonoDelegate *ftn) {
TESTFTN f = (TESTFTN)mono_delegate_to_ftnptr(ftn);
f();
}
と:
public void MakeTest()
{
Console.WriteLine("before");
Win32Service.Test(() => Console.WriteLine("here"));
Console.WriteLine("after");
}
すべてがうまく機能します。では、問題は DWORD への長いマーシャリングにありますか? これでどのように解決できますか?