aharisuのごみ箱スマートフォン用の表示で見るaharisuのごみ箱この広告は、90日以上更新していないブログに表示しています。2009-04-01アンマネージコードにC#のデリゲートを渡すC#今回はC#のトピックスの紹介です。内容はタイトル通りアンマネージコードにC#レベルのデリゲートを渡す方法です。前提知識として、アンマネージコードとはWin32APIの関数だとか自分で書いたC,C++のコードを指します。C#を使っていても、なんだかんだでアンマネージコードを呼び出す機会はあるわけで、そしてその関数がコールバック関数を要求することもたまーにあります。いう場合C#の側では、コールバック関数のシグネチャに対応するシグネチャでデリゲートを定義し、そのデリゲートを渡すことによってコールバック関数を実現します。);という関数があります。この第一引数のWNDENUMPROCはコールバック関数なので、C#からこの関数を呼び出したい場合はC#からデリゲートを渡してあげないといけません。WNDENUMPROCのシグネチャを調べ、それに対応するC#のデリゲートを定義してあげます。lParam);になると思います。ついでにEnumWindowsのDllImportも書いておきます。lParam);このとき引数のデリゲートに属性[MarshalAs(UnmanagedType.FunctionPtr)]をつけることをお勧めします。DllImportの場合自動的に判断されてうまいこと渡されるのですが、明示的に書いておいたほうがわかりやすいと思います。重要なのがComImportしたインタフェースの中にデリゲートを渡す必要のあるメソッドがある場合、先述の属性が必ず必要になります。ないと悲しいことになります。皆さん僕の二の舞にはならないように。ここまではWin32APIのようにあらかじめ用意されている関数に対してデリゲートを渡す方法です。ほかにも自分でアンマネージコードの関数を作りそいつがコールバック受け取るようにももちろんできます。できますがその際気をつけなければならないことがあります。アンマネージコードにとってコールバック関数を受け取るということはつまり関数ポインタを引数にとるということです。戻り値intで引数もintを一つ受け取る関数の関数ポインタの定義は普通に考えるとint(*pFunc)(int)になると思います。このように書いた関数ポインタに対して、上に書いたようにC#が対応するデリゲートを書いてアンマネージコードに渡し実行した場合、おそらく落ちます。その理由は呼び出し規約にあります。VCでは標準の呼び出し規約は__cdeclになっていると思います。関数ポインタも__cdeclだと認識されます。.netのメソッドはすべて__stdcallになっています。呼び出し規約の違うものが渡されたので呼び出しちゃうとご臨終というわけです。僕は.netのメソッドを__cdeclにする方法を知りません。デリゲートを__cdeclにする方法があるようです。詳細はコメント欄にあります。)なので受け取る側であるアンマネージコードが合わせてやる必要があります。その関数ポインタの書き方は次のようになります。*pFunc)(int)__stdcallというキーワードがついただけです。これで実行はうまくいくはずです。この__stdcallというキーワードをどこにつけるかを四苦八苦しながら探したということは秘密。余談ですが、上に書いたWNDENUMPROCの定義にあるCALLBACKというものは実は単なる__stdcallのtypedefだったりします。ほかにもおなじみWINAPIというのも同じく__stdcallのtypedefです。これまでに書いたまでで、普通に使うには問題ありません。デリゲートをアンマネージコードに渡す場合もうひとつ気をつけなければならないことがあります。今回の本題はそっちです。本題にまだ入ってないのですが、そろそろ長くなってきたので本題はまた次回に。Wrightのmatchを読むVimはもっと外の世界につながろうプラグイン作りました月別アーカイブはてなブログをはじめよう!aharisuさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。