非常に悩んでおり、教えてください。
■環境VS2008と作成したプロジェクト
① C#のCOM DLLを作りました
② ①を呼び出すC++ MFCを作りました。
③ ①を呼び出すC# Formを作りました。
■行いたい動作
②もしくは③にコールバック関数を作成し、①へそのコールバック関数を設定する。
①の何かしらのアクション時にコールバック関数を呼び出したい。
お願いします。
うーん、
まず、
1.
>、①へそのコールバック関数を設定する。
これは、DLLを使う以上無理だと思います。
2.
>②もしくは③にコールバック関数を作成し、
設定も②もしくは③で行う。
3.
>①の何かしらのアクション時にコールバック関数を呼び出したい。
Dllとアプリケーションと共通のユ-ザーイベントを作る。
DLLとアプリケーションの間なのでレジストリー登録しないといけないのかな?
です。
あくまで、コールバック関数は、アプリケーション側で作成・実行ですね。
DLLは、初期化コードを実行することが出来ないので、コールバック関数等は
作成・実行はできないと思います。
WIN32API等で設定されているコールバック関数は別です。
動作する可能性はあります。
ご連絡有難うございます。
②,③にコールバック関数の実態(A)を作ります。
(A)を①のDLLへ設定したいですが、
コールバック関数ポインタの受け渡しがどうもわからず、悩んでます。
これは、DLLを使う以上無理との事でしたが
C#で作成したDinamicLinkLibrary~Form間では行えました。
C#で作成したCOM DLLでは難しいのでしょうか?
備考:目的はDLL~アプリ間の通知になります。
この場合SendMessageを使った方がとも考えてます。
https://msdn.microsoft.com/ja-jp/library/d186xcf0(v=vs.110).aspx
これでいいのかな?
これだとDLLはC#ではなくなっちゃいますね。
ITOさん
ご連絡ありがとうございます。
はい、仰る通りです。
簡単に行える方法ですとアンマネージでの実装しかなさそうですね。
今回は簡単なMessage関数で進めようと思います。
有難うございました。
Atata!!です。
C++と.NET間のコールバックは実装可能です。
> これは、DLLを使う以上無理との事でしたが
> C#で作成したDinamicLinkLibrary~Form間では行えました。
上記のC#のDLLとForm間のコールバックはdelegateで実装されていると思いますが、
delegateはC++では単純な関数ポインタに変換できます。
ただ、罠がいくつかあります。
まずは、delegateでコールバック関数を定義したC# COM DLLから
タイプライブラリを生成するとdelegateはCOMインターフェース呼び出しに変換されます
。
[ComVisible(true)]
[Guid(C1D8EC39-99AB-4633-A8D9-EFE42033AC64)]
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void Hoge();
[ComVisible(true)]
[Guid(4EA9428B-E8BA-43DB-9B91-C22933B5E825)]
public interface ICallbackTest
{
[DispId(1)]
void SetCallback(Hoge hoge);
[DispId(2)]
void TestCallback();
}
このようなコードをタイプライブラリに変換するとdelegateのHogeは_HogeというCOMイン
ターフェースに変換されます。
これをそのままC++から利用しようとすると変換された_Hogeインターフェースを実装する
必要があり、
ややめんどくさい話になります。
(↑のインターフェースはIDispatchであり、Invokeメソッドだけ実装すれば機能します
が・・・)
これを関数ポインタとして扱うためには以下のようにMarshalAs属性を付与します。
[ComVisible(true)]
[Guid(C1D8EC39-99AB-4633-A8D9-EFE42033AC64)]
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void Hoge();
[ComVisible(true)]
[Guid(4EA9428B-E8BA-43DB-9B91-C22933B5E825)]
public interface ICallbackTest
{
[DispId(1)]
void SetCallback([MarshalAs(UnmanagedType.FunctionPtr)] Hoge hoge);
[DispId(2)]
void TestCallback();
}
これで生成されるコールバックは32ビットまたは64ビットの整数になります。
ビット数は使用するTLBEXPのビット数とアンマネージDLLのビット数によって決定されま
す。
これはC++側が32ビットと64ビットの両方に対応しなければならない場合、
別々のTLBを参照しなければならないため、めんどくさいことになります。
これらの問題をすっきり解消するにはコールバック関数と言う考えを捨てて、
コールバックをCOMインターフェースとして定義した方が良いです。
MFCで実装する場合はC#側はCOMイベントとして定義した方が結果的に簡単かもしれません
。
Atata!!さん
この方法が知りたかったです!
アドバイスありがとうございます。
C++では単純な関数ポインタとして扱うにはマーシャル関数を用いるのですね。
上記の実装はC# COM DLL側のCSファイルに記述する内容でしょうか?
また、MFC側へは単純に変換したC++では単純な関数ポインタとして
扱えるということですか?
> 上記の実装はC# COM DLL側のCSファイルに記述する内容でしょうか?
その通りです。
適用している属性に差はあるかもしれませんが、
基本的にはCOM公開しているメソッドの引数に
MarshalAs属性を付けることが重要になります。
> また、MFC側へは単純に変換したC++では単純な関数ポインタとして
> 扱えるということですか?
これもその通りですが、32ビット環境では呼び出し規約の制限を受けます。
C#側では呼び出し規約は以下の属性で指定しています。
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
この場合、C++側は__stdcall呼び出し規約で関数を宣言する必要があります。
VC++なら単純にCALLBACKキーワードを付けるのが簡単で良いです。
あとC++の場合、メンバ関数では駄目でstaticな関数でなければなりません。
この辺は通常のコールバック関数を呼び出すのと変わりません。
Atata!!さん
なるほど、C++/CLIを勉強しながら試してみます。
有難うございました
老婆心ながら、
いまからC++/CLIを勉強しても何の役にもたたないのでやめましょう。
MSさん自身が非推奨としていることを考えると
今後、この言語が使用されることはまずありえないと考えられます。
(vv;)
仲澤さん
ありがとうございます。
C++/CLIの技術文献が少なくなっているのは分かりますが
MSは非推奨としているのですか?
そのような内容を見つける事ができなかったので・・・。
VS2012、VS2013で、C++/CLIプロジェクトを新規作成する
簡単な方法がないことからも明らかですが。
以下のページのVS2012の説明「統合開発環境」の項目に
はっきりとした記述があります。
https://msdn.microsoft.com/ja-jp/library/vstudio/bb531344(v=vs.110).aspx
からの抜粋・・・
・C++/CLI を使った Windows フォーム アプリケーションの作成は推奨しません。ただし
、既存の C++/CLI UI アプリケーションの保守はサポートされます。 Windows フォーム
アプリケーション、またはそのほかの .NET アプリケーション UI は、使用、C または V
isual Basic 作成する必要があります。 相互運用性の目的に制限は C++/CLI を使用しま
す。
ということですね。C++/CLIのことは忘れましょう。
仲澤さん
仰る通り、C++/CLIに関する最近の情報は少なすぎますね。
また記事の抜粋有難うございます。
なるべく避けてとおる様に進めてみます^^
本当に色々と有難うございました。