web-dev-qa-db-ja.com

アンマネージDLLから.netアプリへのコールバックインターフェイスを実装する方法は?

次のプロジェクトでは、C++の既存のコードにGUIを実装したいと考えています。私の計画は、C++の部分をDLLでラップし、C#でGUIを実装することです。私の問題は、アンマネージドからのコールバックを実装する方法がわからないことですDLLをマネージC#コードに追加しました。C#で既にいくつかの開発を行っていますが、マネージコードとアンマネージコードのインターフェイスは初めてです。ヒントやヒント、簡単な例を教えてもらえますか?残念ながら私は何も役に立たなかった。

23
chrmue

Marshal.GetFunctionPointerForDelegate()を使用する必要はありません。P/ Invokeマーシャラーが自動的に実行します。シグネチャがC++側の関数ポインター宣言と互換性があるC#側でデリゲートを宣言する必要があります。例えば:

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

class UnManagedInterop {
  private delegate int Callback(string text);
  private Callback mInstance;   // Ensure it doesn't get garbage collected

  public UnManagedInterop() {
    mInstance = new Callback(Handler);
    SetCallback(mInstance);
  }
  public void Test() {
    TestCallback();
  }

  private int Handler(string text) {
    // Do something...
    Console.WriteLine(text);
    return 42;
  }
  [DllImport("cpptemp1.dll")]
  private static extern void SetCallback(Callback fn);
  [DllImport("cpptemp1.dll")]
  private static extern void TestCallback();
}

アンマネージDLLを作成するために使用される対応するC++コード:

#include "stdafx.h"

typedef int (__stdcall * Callback)(const char* text);

Callback Handler = 0;

extern "C" __declspec(dllexport)
void __stdcall SetCallback(Callback handler) {
  Handler = handler;
}

extern "C" __declspec(dllexport)
void __stdcall TestCallback() {
  int retval = Handler("hello world");
}

それであなたはそれを使い始めるのに十分です。トラブルに巻き込まれる可能性のある詳細情報は100万あります。この種のコードを実行するより生産的な方法は、C++/CLI言語でラッパーを記述することです。これにより、C++クラスをラップすることもできます。これは、P/Invokeでは実行できません。まともなチュートリアルは ここから入手できます。

50
Hans Passant

P/Invokeは、マネージデリゲートを関数ポインターにマーシャリングできます。したがって、DLLからコールバック関数を登録するAPIを公開し、C#でその関数にデリゲートを渡す場合は、.

EnumWindows関数でこれを行う [〜#〜] msdn [〜#〜] の例があります。その記事では、ポイント4の次の行に注意してください。

ただし、コールが戻った後にコールバック関数を呼び出すことができる場合、管理された呼び出し元は、コールバック関数が完了するまでデリゲートが収集されないようにするための手順を実行する必要があります。ガベージコレクションの防止の詳細については、「プラットフォームの呼び出しによる相互運用マーシャリング」を参照してください。

つまり、マネージコードへの参照をコード内で保持するか固定することによって、マネージコードがデリゲートを呼び出すまで、デリゲートがガベージコレクションされないようにする必要があります。

6
shf301

アンマネージコードからマネージ(つまりC#コード)を呼び出すための関数ポインターを提供する Marshal.GetFunctionPointerForDelegate を参照してください。

1
Håvard S

これを見てください Marshal.GetDelegateForFunctionPointer

0
t0mm13b