DOBON.NET DOBON.NETプログラミング掲示板過去ログ

アイコン取得でエラー

環境/言語:[XPSP1 or 2000SP4 VB.net]
分類:[.NET]

状況は以下の通りです
リストビューでアイコンを取得しているのですが、ファイルの数が少ないうちは
ちゃんと動いていますが、ファイルが800以上とか、タイマーで再表示していると
そのうちにエラーになります
あと、たまにですがメモリが足りないというメッセージも出ます
どうすればいいのでしょう

Listbox側
For Each _li In _form1.ListView1.Items
 _li.Remove()
Next
_form1.ImageList1.Dispose()
_form1.ImageList2.Dispose()
   :
   :
Call _Get_Icon_1(_cur_dir_1 + _file_ary_1(i)._f_name)
_form1.ListView1.Items(i).ImageIndex = i

アイコン取得
Sub _Get_Icon_1(ByVal _icn_tgt As String)
shinfo1 = New SHFileInfo
hSuccess = SHGetFileInfo(_icn_tgt, 0, shinfo1, Marshal.SizeOf(shinfo1), SHGFI_ICON Or SHGFI_SMALLICON)
If hSuccess.Equals(IntPtr.Zero) = False Then
 Try
  _curIcon = Icon.FromHandle(shinfo1.hIcon)
  _form1.ImageList1.Images.Add(_curIcon)
  _curIcon.Dispose()
  Catch ex As Exception
  _form1.ImageList1.Images.Add(SystemIcons.WinLogo)
 End Try
Else
 _form1.ImageList1.Images.Add(SystemIcons.WinLogo)
End If
shinfo1 = Nothing

エラーメッセージ
System.InvalidOperationException: イメージを ImageList に追加できませんでした。
at System.Windows.Forms.ImageList.AddIconToHandle(Original original, Icon icon)
at System.Windows.Forms.ImageCollection.Add(Original original)
at System.Windows.Forms.ImageCollection.Add(Icon value)
at .Module1._Get_Icon_2(String _icn_tgt)

System.ObjectDisposedException: "Icon" という名前の、破棄されたオブジェクトにアクセスできません。
オブジェクト名 : "Icon" です。
at System.Drawing.Icon.get_Handle()
at System.Windows.Forms.ImageList.AddIconToHandle(Original original, Icon icon)
at System.Windows.Forms.ImageCollection.Add(Original original)
at System.Windows.Forms.ImageCollection.Add(Icon value)
at .Module1._Get_Icon_2(String _icn_tgt)

System.InvalidOperationException: ImageList ハンドルの作成に失敗しました。
at System.Windows.Forms.ImageList.CreateHandle()
at System.Windows.Forms.ImageList.get_Handle()
at System.Windows.Forms.ListView.set_SmallImageList(ImageList value)
at .Module1._Mak_ListView2()
Disposeしたものにアクセスしちゃだめですよ。
■No13570に返信(中博俊さんの記事)
> Disposeしたものにアクセスしちゃだめですよ。
上のは誤登録です、すみません

レスありがとうございます

>>Disposeしたものにアクセスしちゃだめですよ。

元々は無かったんですが、メモリ不足って言われるんで深く考えずに
足してしまいました
でも状況は変わってないんですよね…
(取りあえずdisposeは外しときます)
んー
再度ImageListを作るときに古いImageListをどうしていますか?
ImageListに入れているImageで再利用しないものは、明示的にDisposeしなくちゃいけません。

もうちょっとせいりしてみてちょ
試行錯誤中ですが、現時点では

リストビュー側
_form1.ListView1.Items.Clear()
_form1.ImageList1.Images.Clear()
_form1.ImageList2.Images.Clear()
 :
_form1.ListView1.Items.Add(_file_ary_1(i)._f_name)
Call _Get_Icon_1(_cur_dir_1 + _file_ary_1(i)._f_name)
_form1.ListView1.Items(i).ImageIndex = i

アイコン取得ルーチン
Sub _Get_Icon_1(ByVal _icn_tgt As String)
_ret = SHGetFileInfo(_icn_tgt, 0, ShInfo, Marshal.SizeOf(ShInfo), SHGFI_ICON Or SHGFI_SMALLICON)
If ShInfo.hIcon.Equals(IntPtr.Zero) = False Then
 _form1.ImageList1.Images.Add(Icon.FromHandle(ShInfo.hIcon))
Else
 _form1.ImageList1.Images.Add(SystemIcons.Application) ※ここが3478
End If

で、エラーが相変わらず
Moduleの_Get_Icon_1でエラーが発生しました
System.InvalidOperationException: イメージを ImageList に追加できませんでした。
at System.Windows.Forms.ImageList.AddIconToHandle(Original original, Icon icon)
at System.Windows.Forms.ImageCollection.Add(Original original)
at System.Windows.Forms.ImageCollection.Add(Icon value)
at .Module1._Get_Icon_1(String _icn_tgt) in \Module1.vb:line 3478

Moduleの_Get_Icon_1でエラーが発生しました
System.ObjectDisposedException: "Icon" という名前の、破棄されたオブジェクトにアクセスできません。
オブジェクト名 : "Icon" です。
at System.Drawing.Icon.get_Handle()
at System.Windows.Forms.ImageList.AddIconToHandle(Original original, Icon icon)
at System.Windows.Forms.ImageCollection.Add(Original original)
at System.Windows.Forms.ImageCollection.Add(Icon value)
at .Module1._Get_Icon_1(String _icn_tgt) in \Module1.vb:line 3478

同じファイルでなるという訳ではなく、毎回ランダムなファイルでエラーになります
ともかくアイコンのハンドルが取れてないのは確かです
で、その時に代替アイコンを追加しようとしてコケてると
2005/11/02(Wed) 11:57:52 編集(投稿者)
2005/11/02(Wed) 11:56:02 編集(投稿者)

えっと、ちょっと試して見ました
#OS:XPSP1、メモリ:1.12GB(ノートPC)

# For I As Integer = 0 To count
#  Me.ImageList1.Images.Add(SystemIcons.Application)
# Next

としたとき、countが3400を超えたあたりから、フォームの
タイトルバーが表示されない/IMEのアイコンの色がおかしくなる等、
動作が不安定になりました。

疲れた さんのソースを拝見しますと、すべてのファイルのアイコンを
ImageListに取り込んでおられるようですので、そのあたりが
メモリ不足の原因になったりしていないかなぁと考えます。

私も同じようなことをやったことがありますが、そのときは、
Hashtable(キー:拡張子、値:ImageListのIndex)と
ImageListを組み合わせ、同じファイルの種類(=アイコン)を
ImageList上で一意となるようにしてました。

こんな感じだったと思います。
# 1.アイコンのハンドルが取れないファイル(a)や、
#  フォルダアイコン(b)はデザイン時に設定し、
#  HashTableをForm_Loadで(a)と(b)のキーと値を初期設定
# 2.ファイル検索時の繰り返し処理
#  1). フォルダの場合、ImageListの(b)のIndexを参照
#  2). ファイルの場合、ファイルの拡張子でHashtableを検索
#   -1. Hitしたらその値でImageListを参照
#   -2. Hitしなかったら、アイコンを取得
#    -a. アイコンが取得できたら、ImageListにアイコン追加
#      と、Hashtableに拡張子とIndexを追加、且つ、
#      追加したアイコンのIndexを使用
#    -b. 取得できなかったら、ImageListの(a)のIndexを参照

この方法の場合、以前に使用した拡張子のアイコンは再利用?
されるので、ImageListのクリアは行いません。
もっといい方法があれば、そちらをご使用願います。
この方法でやったところ、クラッシュしなくなったし早くなったしと
いいことづくめでした
ありがとうございました

■No13577に返信(にゃらんたさんの記事)
> 2005/11/02(Wed) 11:57:52 編集(投稿者)
> 2005/11/02(Wed) 11:56:02 編集(投稿者)
> > えっと、ちょっと試して見ました
> #OS:XPSP1、メモリ:1.12GB(ノートPC)
> > # For I As Integer = 0 To count
> #  Me.ImageList1.Images.Add(SystemIcons.Application)
> # Next
> > としたとき、countが3400を超えたあたりから、フォームの
> タイトルバーが表示されない/IMEのアイコンの色がおかしくなる等、
> 動作が不安定になりました。
> > 疲れた さんのソースを拝見しますと、すべてのファイルのアイコンを
> ImageListに取り込んでおられるようですので、そのあたりが
> メモリ不足の原因になったりしていないかなぁと考えます。
> > 私も同じようなことをやったことがありますが、そのときは、
> Hashtable(キー:拡張子、値:ImageListのIndex)と
> ImageListを組み合わせ、同じファイルの種類(=アイコン)を
> ImageList上で一意となるようにしてました。
> > こんな感じだったと思います。
> # 1.アイコンのハンドルが取れないファイル(a)や、
> #  フォルダアイコン(b)はデザイン時に設定し、
> #  HashTableをForm_Loadで(a)と(b)のキーと値を初期設定
> # 2.ファイル検索時の繰り返し処理
> #  1). フォルダの場合、ImageListの(b)のIndexを参照
> #  2). ファイルの場合、ファイルの拡張子でHashtableを検索
> #   -1. Hitしたらその値でImageListを参照
> #   -2. Hitしなかったら、アイコンを取得
> #    -a. アイコンが取得できたら、ImageListにアイコン追加
> #      と、Hashtableに拡張子とIndexを追加、且つ、
> #      追加したアイコンのIndexを使用
> #    -b. 取得できなかったら、ImageListの(a)のIndexを参照
> > この方法の場合、以前に使用した拡張子のアイコンは再利用?
> されるので、ImageListのクリアは行いません。
> もっといい方法があれば、そちらをご使用願います。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板