|
.NET TIPS Win32 APIやDLL関数を呼び出すには?泉 祐介2003/05/09 |
![]() |
|
|
|
.NET Frameworkのクラス・ライブラリには、アプリケーション構築用として非常に多くの機能が用意されている。しかし、WindowsシステムのAPIであるWin32 APIの機能のすべてが、クラス・ライブラリとして用意されているわけではない。このような機能を.NETプログラムから使用する必要がある場合には、ここで紹介する方法によりWin32 APIを直接呼び出すことができる。また、.NET以前の環境でDLLファイルとして作成されたライブラリも同様に呼び出し可能である。
.NET Framework上で動作するプログラムから、従来形式の(.NETアセンブリなどではない)DLLファイルがエクスポートしている関数を呼び出すには、DllImport属性(System.Runtime.InteropServices名前空間)を利用し、その関数が外部にあることをあらかじめ宣言しておけばよい。これは、Win32 APIを呼び出す場合にも同様である。
例えば、マシンに内蔵されているブザー(高機能なサウンド・デバイスではない)からビープ音を鳴らすBeepというWin32 APIがWindowsには用意されている。このAPIの書式は次のとおりである(パラメータなどの詳細についてはMSDNドキュメントを参照)。
BOOL Beep(DWORD dwFreq, DWORD dwDuration);
このAPIをC#で利用するには、適当なクラスの内部に以下のような宣言を加えればよい。
[DllImport("kernel32.dll")]
extern static bool Beep(uint dwFreq, uint dwDuration);
この宣言により、通常のメソッドと同様に、プログラム内からBeep関数を呼び出すことができるようになる。
DllImport属性は、プログラムから利用する関数をエクスポートしているDLLのファイル名を指定するための属性である。Win32 APIに対するDLLファイル名は、MSDNドキュメントにある各APIの解説で、「インポート ライブラリ」という項目に記述されたファイル名から知ることができる。具体的には、kernel32.libと記述されていればkernel32.dll、user32.libであればuser32.dll、gdi32.libであればgdi32.dllとなる。一般に、ほとんどの場合はインポート・ライブラリの欄に記述されたファイル名の拡張子をdllに変更したものを指定すればよい。先のBeep関数は、ドキュメントによればインポート・ライブラリはkernel32.libであるため、DllImport属性のパラメータとしてkernel32.dllを指定している。
また、DllImport属性を付けたWin32 APIやDLL関数の宣言では、関数の実体が外部にあることを表すextern修飾子と、静的なメンバであることを表すstatic修飾子を必ず指定する。なお、ここではpublicやprivateなどのアクセス修飾子は省略したが、必要であれば指定することもできる。
BOOLやDWORDといったパラメータや戻り値の型に関しては、対応するC#の型を指定する必要がある。例えば、前出の例ではBOOLに対してbool、DWORDに対してuintを指定している。主要なWin32 APIでの型名と、それに対応するC#の型は以下の表のようになっている。もちろん、この対応表はWin32 APIではない一般的なDLL関数に対しても利用できる。
| APIでの型名 (括弧内は対応するC言語の型) |
対応するC#の型 (括弧内は.NET Frameworkでの型名) |
| HANDLE (void *) | System.IntPtr |
| BYTE (unsigned char) | byte (System.Byte) |
| SHORT (short) | short (System.Int16) |
| WORD (unsigned short) | ushort (System.UInt16) |
| INT (int) LONG (long) |
int (System.Int32) |
| UINT (unsigned int) DWORD, ULONG (unsigned long) |
uint (System.UInt32) |
| BOOL (long) | bool (System.Boolean) |
| CHAR (char) | char (System.Char) |
| LPSTR (char *) LPWSTR (wchar_t *) |
System.Text.StringBuilder |
| LPCSTR (const char *) LPCWSTR (const wchar_t *) |
string (System.String) |
| FLOAT (float) | float (System.Single) |
| DOUBLE (double) | double (System.Double) |
| Win32 APIでの型名と対応するC#の型 WindowsのDLL(Win32 API)と.NET Frameworkとでは型の管理方法が違うため、実際には型の相互変換(マーシャリング)が行われる。なお、BOOL型の実体はLONG型と同じなので、boolの代わりにintを指定することも可能である。 |
|
Win32 APIの具体的な利用例として、Beep関数を利用したサンプル・プログラムを1つ挙げておこう。以下のリストは、マシン内蔵のスピーカから「ドレミファソラシド」を鳴らすプログラムである。マシン内蔵のブザーを使用するため、音を鳴らすといってもサウンド・デバイスは必要ない。
|
|
| マシン内蔵のスピーカから「ドレミファソラシド」を鳴らすプログラム(beep.cs) | |
参照渡しのパラメータを含むDLL関数の場合
先のBeep関数では、パラメータとして2つの数値を渡すだけの単純なDLL呼び出しで済むが、一部または全部のパラメータが参照渡しになっているAPIやDLL関数も存在する。
例えば、マウスボタンの数を取得するWin32 APIであるGetNumberOfConsoleMouseButtons関数の書式は次のようになっている。
BOOL GetNumberOfConsoleMouseButtons(LPDWORD lpNumberOfMouseButtons);
パラメータのlpNumberOfMouseButtonsはLPDWORD型(DWORD型の値へのポインタ)であるが、実際にはDWORD型の値を参照渡しで渡すことを意味している。
このような参照渡しのパラメータを含む関数を宣言するには、参照渡しになっているパラメータをrefパラメータとして宣言すればよい。よって、GetNumberOfConsoleMouseButtons関数の宣言は以下のようになる。
[DllImport("kernel32.dll")]
extern static bool GetNumberOfConsoleMouseButtons(ref uint lpNumberOfMouseButtons);
ただし、呼び出し側から値を渡す必要がないことが分かっている場合はoutパラメータと宣言しても構わない。先のGetNumberOfConsoleMouseButtons関数も値を渡す必要はないので、以下のように宣言することもできる。
[DllImport("kernel32.dll")]
extern static bool GetNumberOfConsoleMouseButtons(out uint lpNumberOfMouseButtons);
定数を使用するDLL関数の場合
Win32 APIやDLL関数を利用する際に、関数のパラメータとして何らかの定数を指定する場合がある。特にWin32 APIに関しては、それらの定数がプラットフォームSDKに含まれるヘッダ・ファイル(windows.hなど)で定義されているが、C#ではこれらのヘッダ・ファイルを扱うことができないため、必要に応じて定数を自分で定義しなければならない。
Win32 APIやDLL関数に定数を渡す方法はいくつか考えられるが、必要な定数をconstキーワードで定義する方法が最も一般的だろう。例えば、以下のサンプル・プログラムは、IsProcessorFeaturePresentというWin32 APIを利用して、プロセッサがMMX命令セットをサポートしているかどうかを調べるプログラムである。IsProcessorFeaturePresent関数はプロセッサが特定のプロセッサ機能をサポートしているかどうかを調べるAPIであり、プロセッサ機能の種類を表す定数をパラメータにとる。このプログラムでは、SSE命令セットを表すPF_XMMI_INSTRUCTIONS_AVAILABLE定数を宣言し、それをパラメータとして渡している(詳細はMSDNドキュメント(英語)を参照)。なお、定数の実際の値(この場合は6)を知るには、プラットフォームSDKに含まれるヘッダ・ファイルを参照する必要がある。
|
|
| プロセッサのSSE命令セットのサポートの有無を調べるプログラム(ssechk1.cs) | |
独自の列挙型を宣言し、その列挙型を関数のパラメータや戻り値として宣言する方法もある。例として、IsProcessorFeaturePresent関数のパラメータを列挙型として宣言したサンプル・プログラムを以下に示す。
|
|
| プロセッサのSSE命令セットのサポートの有無を調べるプログラム(ssechk2.cs) | |
この程度のプログラムでは、列挙型を定義するメリットはあまりなく、むしろ列挙体を定義することがかえって手間になっている。しかし、特に複数の種類の定数を利用する場合は、パラメータを列挙型として宣言しておけば、その列挙型のメンバ以外の値を直接パラメータに渡すことができなくなるので、コーディング上のミスを抑えることが可能になる。また、Visual Studio .NETのIntelliSence機能では、パラメータの型としてこの列挙型が表示されるため、どの定数を指定すればよいかが一目で分かるようになる。これは戻り値についても同様である。必要に応じてconstによる方法と使い分けるとよいだろう。
なお、文字列や構造体をパラメータに指定するDLL関数呼び出しについては、TIPS:Win32 APIやDLL関数に文字列や文字列バッファを渡すには? やTIPS:Win32 APIやDLL関数に構造体を渡すには? を参照していただきたい。![]()
| カテゴリ:クラス・ライブラリ 処理対象:Win32 API 使用ライブラリ:DllImport属性(System.Runtime.InteropServices名前空間) 関連TIPS:Win32 APIやDLL関数に文字列や文字列バッファを渡すには? 関連TIPS:Win32 APIやDLL関数に構造体を渡すには? |
|
||||||||||||||||||||||||||||
| 「.NET TIPS」 |
ホワイトペーパー(TechTargetジャパン)
- LocalConnection APIと動的なスタイリング (2010/2/9)
Webページ上の複数のSilverlightアプリ間でメッセージ通信をする方法とは? コントロールの見た目を動的に設定する方法とは? - ASP.NET MVC 2:モデルの検証 (2010/2/8)
ASP.NET MVC 2で導入される入力検証機能を使った実装を紹介。シンプルな属性の追加によるエレガントな実装が可能となっている - ASP.NETによる3階層Webアプリ「ITブック」構築 (2010/2/5)
ちょっとした改造で、あなたのWebアプリは劇的に使いやすく、かっこよくなる。まずは元となるWebアプリを標準的手法で構築 - .NET TIPS - .NET開発のテクニックとヒント集 - (2010/2/4)
− カスタムMVCビューエンジンを利用するには?(活用編)
− フォーム全体へのドッキングでつまみを表示するには?
− リストボックスでTextBlockの文字列を折り返すには?
|
|
スキルアップ/キャリアアップ(JOB@IT)
スポンサーからのお知らせ
- - PR -
- - PR -
お勧め求人情報

**先週の人気講座ランキング**
〜CCNA編〜
| ◆ | 企業の仮想化に足りない“発想”とは? 仮想化運用管理のキモは意外なところに! New! |
| ◆ | 操作もマニュアルも分かりやすい! ユーザー視点で開発されたPC管理ツール New! |
| ◆ | 仮想化すればコストは削減できるか? 仮想化に必要な「3つの視点」を解説する |

| ◆ | セキュリティを知り尽くす上野氏が登壇! @ITメールソリューションLive! in Tokyo |
| ◆ | 運用管理の課題を“2つの観点”から分析 ユーザー満足度の高い「仮想環境」とは? |
| ◆ | 世界に通用するストレージの作り方とは? 製品に込めた思いを富士通の開発者に聞く |

| ◆ | OSSで手間も時間も、障害も減った―― 「マピオンの事例」オープンソース活用法 |
| ◆ | 「ノートPCの持ち出し禁止」で大丈夫? 情報漏えいを防ぐ管理手法とインフラは? |
| ◆ | 1日の処理を1秒に――MySQLの達人が語る 「コスト削減」できるチューニング |

| ◆ | ドキュメント作成を自動化して、SEの作業 効率を大幅アップ! Visio 2007の魅力 |
| ◆ | 急速に広がるHyper-Vでのサーバ仮想化 そのベストプラクティスをデルが解説 |
| ◆ | @IT主催セミナーで語られた、「担当者に 求められるセキュリティ対策」をレポート |

| ◆ | @IT「Windows 7」 特設サイトオープン! 最新情報・移行ノウハウを公開しています |







