- PR -

Win32APIの呼び出し

1
投稿者投稿内容
wataru
会議室デビュー日: 2006/07/29
投稿数: 5
投稿日時: 2006-07-29 04:57
C#からWin32APIを呼び出そうとしてマネージドとアンマネージドなリソースがよくわからなくなってしましました。
まず
http://www.atmarkit.co.jp/fdotnet/csharp_abc2/csabc2_020/cs2_020_03.html#cs2008
の解説ではポインタを使用してないのでアンセーフなコードではなく、メモリ等は管理されているとあります。
一方、
http://www.pinvoke.net/default.aspx/shell32/ExtractIconEx.html
のサンプルコードを参考にするとポインタを直接扱っていないにもかかわらずunsafeをつけています。さらにIconDestroyも呼び出し、Intptrに入ったIconのハンドルを破棄しています。
実際に同様のコードをコンパイルして実行してみたところunsafeにかかわらず実行は可能でした。
私は、
1、unsafeはポインタを直接扱っていないので必要ない。
2、IntptrはマネージドなC#で宣言されたので管理されている。(破棄等は必要ない)
と考えたのですがどうでしょうか?
1、2が正しければ
3、win32APIを呼び出したとしても直接ポインタを扱わない限り、特に留意する必要はない?
となると思うのですが・・
2はIntptrとポインタ、メモリ管理の関係があやふやなため特によくわかりません。

以上よろしくおねがいします。


Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-07-29 08:01
引用:

ポインタを使用してないのでアンセーフなコードではなく、メモリ等は管理されているとあります。


メモリは管理されてますがそれ以外はそうでもありません。メモリの管理のついでにそれ以外の管理もやってもらうってのはよくありますが。
ついでに、セーフコードであってもアンマネージドなメモリを確保する事はできます。

引用:

1、unsafeはポインタを直接扱っていないので必要ない。


そうですね。
unsafe コンテキストは、ポインタを使用するという宣言です。ポインタを使用しないのなら不要で、しかも IntPtr 型と Marshal クラスを使用すればほぼポインタの代用となります。当然どれだけ IntPtr を使おうがポインタは使ってないので unsafe コンテキストである必要はありません。

引用:

2、IntptrはマネージドなC#で宣言されたので管理されている。(破棄等は必要ない)


IntPtr は確かにマネージドなオブジェクトです。これは .NET が管理し、不要になればヒープ/スタックから削除してくれます。
でも、IntPtr が示す先の何かは普通マネージドではありません。.NET の管理外です。Icon オブジェクトなら確かに .NET が管理できますが、ExtractIconEx 関数で取得できるのは所詮ただの数値です。その数値をどうするかはプログラマに委ねられています。大体、.NET から見た場合 IntPtr は IntPtr であってそれ以上の判断基準を持てないのだから、CloseHandle すればいいのか DestroyIcon なのか、はたまた GlobalFree なのかなんて判断しようもありません。
と言う事で、IntPtr が示す先の何かについては、プログラマ側が DestroyIcon とか使って解放してやらなければなりません。

引用:

3、win32APIを呼び出したとしても直接ポインタを扱わない限り、特に留意する必要はない?


何を留意するんですか?
unsafe キーワードを使うかどうか、という点では確かに気にする必要はありませんが。


unsafe ステートメントを使うには、コンパイル時に /unsafe オプションを付ける必要があります。
このオプションを使うと、アセンブリ(exe/dll)に UnverifiableCodeAttribute 属性が付けられます(厳密にはアセンブリじゃなくてモジュールですが)。
この属性が付いていると、そのアセンブリは検証不能であると"事前に"分かるため、.NET ランタイムはそのアセンブリが信頼できない(ネットワーク越しだとかで)状況では実行を許可しません。
// Marshal クラスのメソッドの使用でも同じように実行許可が判断されますが、こちらは事前には分からないので実際にそのメソッドが呼び出される時まで判断が遅延してしまいます。
wataru
会議室デビュー日: 2006/07/29
投稿数: 5
投稿日時: 2006-07-29 14:03
Hongliangさん、ありがとうございます。
Intptr自体は管理されているがそれが示しているアドレスにある何かは管理対象外ということですね。
留意するというのは主に2のようなメモリ管理に関することです。ポインタを返すようなWin32APIを使い、なおかつポインタが示すものが.netのデータ型になくIntPtrで受け取った場合、受け取ったポインタのアドレスの先にあるものはプログラマが解放する必要があるということでよいですか? ポインタが示すものが.netのデータ型にあるものなら参照渡しすることで管理してもらえるんですよね。
これでよければだいたいわかった気がします。
1

スキルアップ/キャリアアップ(JOB@IT)