1

アプリケーションに 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 への長いマーシャリングにありますか? これでどのように解決できますか?

4

1 に答える 1

0

DWORD は 32 ビット整数型ですが、C# の long は 64 ビット型です。

于 2012-05-15T08:54:44.083 に答える