|
 |
連載:深入り.NETプログラミング
アンマネージ・コードの型情報と連携する
NyaRuRu
Microsoft MVP Windows - DirectX(Jan 2004 - Dec 2009)
2009/07/21 |
|
C#やVisual Basicなどのコードからアンマネージ・コード(ネイティブ・コード)を呼び出すための「P/Invoke(Platform Invoke、プラットフォーム呼び出し)」には定型作業が多い。例えばC/C++用のマクロ定数は、C#ではenum型として扱いたいところだ。これには例えば次のような書き換えが必要になる。
#define PAGE_NOACCESS 0x01
#define PAGE_READONLY 0x02
#define PAGE_READWRITE 0x04
#define PAGE_WRITECOPY 0x08
(以下略) |
|
C/C++用のマクロ定数定義の例 |
[Flags]
public enum MemoryProtection : uint
{
PAGE_NOACCESS = 0x01,
PAGE_READONLY = 0x02,
PAGE_READWRITE = 0x04,
PAGE_WRITECOPY = 0x08,
(以下略)
} |
|
C/C++用のマクロ定数をC#のenum型で表現した例 |
これを実現する安直な方法は、この作業をすべて手で行うというものだ。まずはオリジナルのC/C++コードをC#コード上にコピーし、微妙な文法の違いを行ごとに書き換えていく。義務感に駆られて<summary>タグによるドキュメント・コメントも付け始めると、作業量はさらに増える。Document Explorerで該当するドキュメントを探し、ドキュメント・コメントに1つ1つコピーすれば、とても親切なP/Invokeコードが出来上がることだろう。
このような手作業方式は、ひたすらに手を動かすだけあって、なんだかずいぶん仕事をした気になってしまう。筆者もよく現実逃避にP/Invokeコードを書いてしまうのだが、自戒も込めて、こんな逃避先はつぶしてしまいたい。というわけで、今回はC/C++と.NETの橋渡しに関する使えそうな技術を紹介しよう。
【コラム】エディタの機能で楽をする |
たいていのエディタには、記録したキー操作を繰り返すマクロ機能や、強力なテキスト置換の機能が付いている。うまく一発で変換できるマクロを作れたときの達成感はひとしおだ。これまた仕事をした気になってしまう。 |
【コラム】pinvoke.net |
P/Invokeといえば、http://pinvoke.netに投稿されているコードを使うという方法もある。筆者はあまりこのサイトを使っていないのだが、深い理由があるわけではなく、ドキュメント・コメントの付け方がまちまちであったり、SafeHandle型を使うべきところでIntPtr型を使っているものが混ざっていたりと、コードの質がバラバラなのが単に気になるというだけである。なお、一部のAPIには非常に詳細な解説が付いており、それが忘れていたことや重要な注意点を思い出させてくれることもある。 |
■P/Invoke Interop Assistant
P/Invokeには、実に便利なツールがすでにある。Code Plex上のCLR Interopチームのサイトで公開されている「P/Invoke Interop Assistant」というツールは、P/Invokeまたは、逆P/Invokeで用いる型定義の自動生成を行ってくれる。
 |
図1 P/Invoke Interop Assistantの実行例:[SigImp Search]タブ |
[SigImp Search]タブからは、windows.hファイルに含まれる型情報を検索することができる。P/Invokeコードを生成したい要素を選択し、[Generate]ボタンを押すと、右側のペインにソース・コードが生成される。この画面の例ではC#となっているが、Visual Basicでコードを生成することも可能だ。事前作成された型情報データベースを使用するので、実行環境にWindows SDKは必要ない。 |
 |
図2 P/Invoke Interop Assistantの実行例:[SigImp Translate Snippet]タブ |
[SigImp Translate Snippet]タブからは、C++のソース・コードを基に、その場でP/Invokeコードを生成することもできる。例えばビット・フィールドを用いた構造体もこのとおり。 |
さて、P/Invoke Interop Assistantはどのようにコードを生成しているのだろうか? ソース・コードが公開されているので、その実装方法を調べてみた。
結論からいえば、P/Invoke Interop AssistantはC/C++用の「手書きパーサー」を内蔵している。ただし、C/C++文法を完全に網羅しているわけではなく、あくまでWindows SDKのヘッダ・ファイルに登場する程度の文法をサポートするぐらいのものと考えればよいだろう。それでも大仕事である。それを既存のライブラリを一切使わず、自前のパーサーでやってのけるのには恐れ入る。テストもしっかり書かれており、PInvokeTool\UnmanagedToManaged\PInvokeTest\SampleFiles以下に定義されているテスト・ケースは58にも及ぶ。ちなみにこのパーサー、実装言語はVisual Basicである。
また、プリプロセッサ・マクロの解釈も部分的にサポートしている。先ほど「#define」で定義された定数の取り込みに成功していたことを思い出してほしい。Windows SDKのヘッダ・ファイルというある種のDSL(ドメイン特定言語)のインポートに特化したパーサーといえる。
Insider.NET 記事ランキング
本日
月間