リストビューにアイコンを表示するには?

解決


れい子  2004-08-09 15:00:07  No: 85050  IP: [192.*.*.*]

いつもお世話になってます。
リストビューにコンピューターのアイコンを表示させたいと思ってます。

イメージリストのプロパティで表示したいアイコンを挿入して、
リストビューのプロパティの欄でイメージリストを指定すればいいのだと
思ったですが、うまくいきません。

やはりコードを書く必要があるのでしょうか?

ご存知の方、ご指導お願いいたします。

編集 削除
Max  2004-08-10 12:28:52  No: 85051  IP: [192.*.*.*]

Add メソッド (ListItems コレクション)
の引数を調べてみてください。

編集 削除
いどう  2004-08-10 13:17:21  No: 85052  IP: [192.*.*.*]

http://www.takeittechies.com/vbtomo/boards/vbchoshoqa.php?do=spread&num=1023

編集 削除
りっとっと  2004-08-11 19:49:21  No: 85053  IP: [192.*.*.*]

どのようにうまくいっていないのかはわかりませんが、
前回のスレッドとほぼ同じ内容ですよね。
サンプルを作ってみましたので試してみてください。

Option Explicit

Private Type IconType
    cbSize As Long
    picType As PictureTypeConstants
    hIcon As Long
End Type

Private Type SHFILEINFO
  hIcon As Long
  iIcon As Long
  dwAttributes As Long
  szDisplayName As String * 260
  szTypeName As String * 80
End Type

Private Type CLSIdType
    id(16) As Byte
End Type

Private Declare Function SHGetSpecialFolderLocation Lib "shell32" (ByVal hwndOwner As Long, ByVal nFolder As Long, pidl As Long) As Long

Private Declare Function SHGetFileInfo Lib "shell32.dll" Alias "SHGetFileInfoA" (ByVal pszPath As Any, ByVal dwFileAttributes As Long, psfi As SHFILEINFO, ByVal cbFileInfo As Long, ByVal uFlags As Long) As Long

Private Declare Function OleCreatePictureIndirect Lib "oleaut32.dll" _
        (pDicDesc As IconType, riid As CLSIdType, ByVal fown As Long, _
        lpUnk As Object) As Long

'スペシャル(システム)なフォルダを取得するための定数
'なのだがサンプルでは未使用
Private Const CSIDL_DESKTOP = &H0
Private Const CSIDL_INTERNET = &H1
Private Const CSIDL_PROGRAMS = &H2
Private Const CSIDL_CONTROLS = &H3
Private Const CSIDL_PRINTERS = &H4
Private Const CSIDL_PERSONAL = &H5
Private Const CSIDL_FAVORITES = &H6
Private Const CSIDL_STARTUP = &H7
Private Const CSIDL_RECENT = &H8
Private Const CSIDL_SENDTO = &H9
Private Const CSIDL_BITBUCKET = &HA
Private Const CSIDL_STARTMENU = &HB
Private Const CSIDL_MYDOCUMENTS = &HC
Private Const CSIDL_MYMUSIC = &HD
Private Const CSIDL_MYVIDEO = &HE
Private Const CSIDL_DESKTOPDIRECTORY = &H10
Private Const CSIDL_DRIVES = &H11
Private Const CSIDL_NETWORK = &H12
Private Const CSIDL_NETHOOD = &H13
Private Const CSIDL_FONTS = &H14
Private Const CSIDL_TEMPLATES = &H15
'Private Const CSIDL_COMMON_STARTMENU = &H16
'Private Const CSIDL_COMMON_PROGRAMS = &H17
'Private Const CSIDL_COMMON_STARTUP = &H18
'Private Const CSIDL_COMMON_DESKTOPDIRECTORY = &H19
Private Const CSIDL_APPDATA = &H1A
Private Const CSIDL_PRINTHOOD = &H1B
Private Const CSIDL_LOCAL_APPDATA = &H1C
Private Const CSIDL_ALTSTARTUP = &H1D
Private Const CSIDL_COMMON_ALTSTARTUP = &H1E
Private Const CSIDL_COMMON_FAVORITES = &H1F
Private Const CSIDL_INTERNET_CACHE = &H20
Private Const CSIDL_COOKIES = &H21
Private Const CSIDL_HISTORY = &H22

Private Const SHGFI_ICON = &H100
Private Const SHGFI_LARGEICON = &H0
Private Const SHGFI_SMALLICON = &H1
Private Const SHGFI_PIDL = &H8
Private Const SHGFI_DISPLAYNAME = &H200&

Private ret As Long

Private Sub Form_Load()
    Dim DispName As String
    Dim IPic As IPictureDisp
    Dim CSIDL As Long
    Dim ImgCnt As Long
    Dim SHFI As SHFILEINFO
    Dim pid As Long
    
    ListView1.Arrange = lvwAutoTop
    'CSIDL_XXXXという定数を使用して行うのだが、めんどいのでFor文でループ
    For CSIDL = 0 To &H22
        Select Case CSIDL
            Case &HF, &H16 To &H19
            Case Else
                'スペシャルフォルダのPIDLを取得
                ret = SHGetSpecialFolderLocation(Me.hWnd, CSIDL, pid)
                'スペシャルフォルダの小さいアイコンのハンドル取得
                ret = SHGetFileInfo(pid, 0, SHFI, Len(SHFI), SHGFI_PIDL Or SHGFI_ICON Or SHGFI_SMALLICON)
                Set IPic = IconToIPicture(SHFI.hIcon)
                If Not (IPic Is Nothing) Then
                    ImgCnt = ImgCnt + 1
                    ImageList1.ListImages.Add , , IPic
                    'スペシャルフォルダの表示文字列及び大きいアイコンのハンドル取得
                    ret = SHGetFileInfo(pid, 0, SHFI, Len(SHFI), SHGFI_PIDL Or SHGFI_ICON Or SHGFI_LARGEICON Or SHGFI_DISPLAYNAME)
                    Set IPic = IconToIPicture(SHFI.hIcon)
                    ImageList2.ListImages.Add , , IPic
                    If ImgCnt = 1 Then
                        ListView1.SmallIcons = ImageList1
                        ListView1.Icons = ImageList2
                    End If
                    ListView1.ListItems.Add , , SHFI.szDisplayName, ImgCnt
                End If
        End Select
    Next
End Sub

Private Sub Form_Resize()
    If Me.ScaleWidth <= 0 Then Exit Sub
    With ListView1
        .Left = 0
        .Top = 0
        .Width = Me.ScaleWidth
        .Height = Me.ScaleHeight
    End With
End Sub

Private Function IconToIPicture(hIcon As Long) As IPictureDisp
    Dim pic As IconType
    Dim IPic As IPictureDisp
    Dim IID_IDispatch As CLSIdType
    Dim ret As Long
    
    IID_IDispatch.id(8) = &HC0
    IID_IDispatch.id(15) = &H46
    With pic
        .cbSize = Len(pic)
        .picType = vbPicTypeIcon
        .hIcon = hIcon
    End With
    ret = OleCreatePictureIndirect(pic, IID_IDispatch, 1, IPic)
    Set IconToIPicture = IPic
End Function

編集 削除
れい子  2004-08-12 20:28:02  No: 85054  IP: [192.*.*.*]

返信が遅れて申し訳ありません。
りっとっとさんご丁寧にありがとうございます。

現在別の業務と平行して進めているので、
時間がかかると思いますが、試してみます。

まだVBを初めて間もないので、サンプルのコードを
理解できるかわかりませんが、自分なりに調べながら
やってみます。

また報告いたしますのでよろしくお願いいたします。

編集 削除
Yoo  URL  2004-08-17 08:52:22  No: 85055  IP: [192.*.*.*]

りっとっとさん提示のサンプルコードをためさせていただいたのですが、
WinXpならいいのですが、Win2000ですと、マイドキュメントアイコンがうまく取得できないようです。
うまく取得できる方法は、あるのでしょうか?

編集 削除
れい子  2004-08-17 18:12:15  No: 85056  IP: [192.*.*.*]

たいへん申し訳ないんですが、まだVBを始めたばかりで
りっとっとさんのサンプルコードを全く理解できませんでした。
コピー&ペーストすると確かにアイコンを表示できるのですが・・・
ごめんなさい
もっと詳しく解説をしていただけるとうれしいのですが
わがまま言ってすいません。

編集 削除
プッツン  2004-08-18 11:12:15  No: 85057  IP: [192.*.*.*]

回答ではありません。

> りっとっとさんのサンプルコードを全く理解できませんでした。
> もっと詳しく解説をしていただけるとうれしいのですが

その前に、他の板で質問した件は解決したんですか?
http://www.takeittechies.com/vbtomo/boards/vbchoshoqa.php?do=spread&num=1023

サンプルコード全般の解説を求めるのではなく、解からない部分に絞って、
質問すべきでしょう?

編集 削除
れい子  2004-08-18 11:35:23  No: 85058  IP: [192.*.*.*]

>その前に、他の板で質問した件は解決したんですか?
申し訳ございません。同じ件を二つの板で書いてしまいました。
せっかくお答え頂いたので違う方法も覚えられたらと
思ったのですが。

>サンプルコード全般の解説を求めるのではなく、解からない部分に絞って、
質問すべきでしょう?
おっしゃるとおりです。私も自分で調べたりしてから、
できるだけ絞って質問しようと思ったのですが、調べ方も
ままならない状況レベルなんです。
自分でもう少し努力してみます。

編集 削除
りっとっと  2004-08-18 17:09:43  No: 85059  IP: [192.*.*.*]

サンプルプログラムの説明。

・SHGetSpecialFolderLocation関数
特殊フォルダのITEMIDLIST構造体へのポインタを取得します。
第1引数は、この関数を実行するアプリケーションのウィンドウハンドルを設定します。フォームのウィンドウハンドルでかまいません。
第2引数には、特殊フォルダを示す定数(CSIDL_XXXX)を設定します。
第3引数には、取得するためのLong型変数を設定します。
SHGetSpecialFolderLocation関数を実行すると、第3引数に設定した変数にポインタが取得されます。
ITEMIDLIST構造体は、ITEMIDLISTでグーグルなどで検索すると詳しい情報が得られます。
つまりは、指定した特殊フォルダが、ITEMIDLISTのどの位置なのかをポインタ(pIDL)で取得する関数です。

・SHGetFileInfo関数
ファイルまたはフォルダに関する情報を取得します。
取得できる情報は、SHFILEINFO構造体の定義を見るとわかるとおり
Private Type SHFILEINFO
  hIcon As Long                   '関連付けされているアイコンのハンドル
  iIcon As Long                   '関連付けされているアイコンのシステムイメージリストでのインデックス値
  dwAttributes As Long            '属性
  szDisplayName As String * 260   '表示名
                                  'フォルダのみ、フォルダ名と表示名が違う場合設定されている。
                                  'たとえば、"マイドキュメント"というフォルダは、実際のフォルダ名は"My Document"である。
                                  'この"マイドキュメント"という文字列がここに入る。
  szTypeName As String * 80       'タイプ
End Type
です。
第一引数は、情報を取得したいファイルまたはフォルダのフルパス(String型)を本来設定するのですが、
今回は、特殊フォルダの情報を取得するため、SHGetSpecialFolderLocationで取得したITEMIDLISTへのポインタ(Long型)を
設定しています。
第2引数は取得するファイルの属性のマスク値を設定します。第5引数にSHGFI_USEFILEATTRIBUTESが含まれているときのみ有効です。
第3引数は取得するSHFILEINFO構造体の変数を設定します。関数を実行するとこの変数に情報が取得されます。
第4引数はSHFILEINFO構造体(変数)のバイト数を設定します。
第5引数は取得したい情報のフラグを設定します。フラグはビットデータですので複数設定する場合は Or 演算子を使用します。
SHGFI_ICON             '関連付けされているアイコンのハンドルを取得
SHGFI_SYSICONINDEX     '関連付けされているアイコンのシステムイメージリストでのインデックスを取得
SHGFI_LARGEICON        '関連付けされているアイコンの情報を取得時に大きいアイコンの情報を取得する。(SHGFI_ICONまたはSHGFI_SYSICONINDEXと組み合わせて使用)
SHGFI_SMALLICON        '同じく小さいアイコンの情報を取得
SHGFI_SHELLICONSIZE    '(Shell(システム)での)規定サイズのアイコンの情報を取得
SHGFI_PIDL             'ITEMIDLISTへのポインタを使用して情報を取得
SHGFI_DISPLAYNAME      '表示文字列を取得
SHGFI_USEFILEATTRIBUTES'ファイル属性を取得
SHGFI_TYPENAME         'タイプを取得("システム フォルダ"・"ファイル フォルダ"といったタイプ名が取得される)
SHGFI_EXETYPE          '実行ファイルの種類を取得
                       '(SHGetFileInfo関数の戻り値(Long型)として取得。値によってWindowsアプリ・MS-DOSアプリ・Win32コンソールアプリかを判断できる)

・OleCreatePictureIndirect関数
PICDESC構造体(サンプルプログラムではIconType構造体)に設定した情報を元にピクチャーオブジェクトを作成。
第1引数は情報を設定したPICDESC構造体を設定します。
第2引数はIDispatchインタフェースのGUIDを設定します。
第3引数は取得するピクチャーオブジェクトのインタフェース変数を設定します。(サンプルではピクチャーオブジェクトのクラスにあわせてIpictureDispとしている)

これらの関数を使用してアイコンを取得しています。
サンプルプログラムの流れは、
SHGetSpecialFolderLocation関数にて特殊フォルダのITEMIDLISTへのポインタを取得。
SHGetFileInfo関数でポインタを元に関連付けられているアイコンのハンドルを取得。
OleCreatePictureIndirect関数で取得したアイコンハンドルを元にピクチャーオブジェクトを作成して、
作成したピクチャーオブジェクトをリストビューに関連付けしているイメージリストに追加。
追加後、リストビューにアイテムを追加。
という流れです。
リストビューにイメージリストを設定する場合、何もイメージ(画像)ないイメージリストを設定しようとすると
初期化されていないというエラーが発生しますので、イメージリストに1つ追加したとき(ImgCnt = 1)に設定しています。

編集 削除
すっぽん  2004-08-18 18:58:29  No: 85060  IP: [192.*.*.*]

りっとっとさんのサンプルコードで、
PIDLとアイコンハンドルの後始末を忘れている様な?

編集 削除
れいこ  2004-08-23 09:19:35  No: 85061  IP: [192.*.*.*]

おかげさまでリストビューにアイコンを表示することが
できました。みなさん何度もご指導くださって
ありがとうございました。

編集 削除