Die Community zu .NET und Classic VB.
Menü

VB 5/6-Tipp 0281: Listview als Exploreransicht

 von 

Beschreibung 

Das Listview ermöglicht das Browsen in Verzeichnissen, wie ausreichend durch den Windows-Explorer bekannt. Es wird zu jeder Dateiendung konsequent das passende Icon sowohl in der Detailansicht als auch in der Symbolansicht herausgesucht, wobei dieses Vorgehen bei größeren Verzeichnissen nicht sehr ressourcenschonend ist. Zudem werden die gängigen Informationen wie Dateityp, Größe, letztes Zugriffsdatum und natürlich die Attribute in gewohnter Form dargestellt.

Schwierigkeitsgrad:

Schwierigkeitsgrad 3

Verwendete API-Aufrufe:

FileTimeToSystemTime, FindClose, FindFirstFileA (FindFirstFile), FindNextFileA (FindNextFile), OleCreatePictureIndirect, SHGetFileInfoA (SHGetFileInfo)

Download:

Download des Beispielprojektes [5,19 KB]

'Dieser Quellcode stammt von http://www.activevb.de
'und kann frei verwendet werden. Für eventuelle Schäden
'wird nicht gehaftet.

'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
'Ansonsten viel Spaß und Erfolg mit diesem Source!

'------------- Anfang Projektdatei Project1.vbp -------------
' Die Komponente 'Microsoft Windows Common Controls 5.0 (SP2) (COMCTL32.OCX)' wird benötigt.

'--------- Anfang Formular "Form1" alias Form1.frm  ---------
' Steuerelement: Listenansichtsetuerelement "ListView1"
' Steuerelement: Optionsfeld-Steuerelement "Option1" (Index von 0 bis 3)
' Steuerelement: Verzeichnisauswahlliste "Dir1"
' Steuerelement: Festplattenauswahlliste "Drive1"
' Steuerelement: Bilderliste "ImageList2"
' Steuerelement: Bilderliste "ImageList1"
'Dieser Source stammt von http://www.ActiveVB.de

'Sollten Sie Fehler entdecken oder Fragen haben, dann
'mailen Sie mir bitte unter: Reinecke@ActiveVB.de

Option Explicit

Option Compare Text

Private Declare Function FindFirstFile Lib "kernel32" Alias _
        "FindFirstFileA" (ByVal lpFileName As String, _
        lpFindFileData As WIN32_FIND_DATA) As Long
        
Private Declare Function FindNextFile Lib "kernel32" Alias _
        "FindNextFileA" (ByVal hFindFile As Long, _
        lpFindFileData As WIN32_FIND_DATA) As Long
        
Private Declare Function FindClose Lib "kernel32" (ByVal _
        hFindFile As Long) As Long
        
Private Declare Function SHGetFileInfo Lib "shell32.dll" Alias _
        "SHGetFileInfoA" (ByVal pszPath As String, ByVal _
        dwFileAttributes As Long, psfi As ShellFileInfoType, ByVal _
        cbFileInfo As Long, ByVal uFlags As Long) As Long

Private Declare Function FileTimeToSystemTime Lib "kernel32" _
        (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) _
        As Long
        
Private Declare Function OleCreatePictureIndirect Lib "oleaut32.dll" _
        (pDicDesc As IconType, riid As CLSIdType, ByVal fown As Long, _
        lpUnk As Object) As Long
        

Const SHGFI_TYPENAME = &H400&
Const MAX_PATH = 259
Const Large = &H100
Const Small = &H101

Private Type FILETIME
  dwLowDateTime As Long
  dwHighDateTime As Long
End Type

Private Type WIN32_FIND_DATA
  dwFileAttributes As Long
  ftCreationTime As FILETIME
  ftLastAccessTime As FILETIME
  ftLastWriteTime As FILETIME
  nFileSizeHigh As Long
  nFileSizeLow As Long
  dwReserved0 As Long
  dwReserved1 As Long
  cFileName As String * MAX_PATH
  cAlternate As String * 14
End Type

Const FILE_ATTRIBUTE_ARCHIVE = &H20
Const FILE_ATTRIBUTE_COMPRESSED = &H800
Const FILE_ATTRIBUTE_DIRECTORY = &H10
Const FILE_ATTRIBUTE_HIDDEN = &H2
Const FILE_ATTRIBUTE_NORMAL = &H80
Const FILE_ATTRIBUTE_READONLY = &H1
Const FILE_ATTRIBUTE_SYSTEM = &H4
Const FILE_ATTRIBUTE_TEMPORARY = &H100

Private Type SYSTEMTIME
  wYear As Integer
  wMonth As Integer
  wDayOfWeek As Integer
  wDay As Integer
  wHour As Integer
  wMinute As Integer
  wSecond As Integer
  wMilliseconds As Integer
End Type

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

Private Type CLSIdType
  id(16) As Byte
End Type

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

Private Type FileType
  Name As String
  Ext As String
  IcoIndex As Integer
End Type

Private Type DIRLISTTYPE
  Ext As String
  File As String
  Type As String
  Attributes As Long
  FileLen As Long
  LastWrite As FILETIME
End Type

Dim DirList() As DIRLISTTYPE

Private Sub Form_Load()
  Dim TPX&
  
    TPX = Screen.TwipsPerPixelX
    ListView1.ColumnHeaders.Add , , "Dateiname", 140 * TPX, 0
    ListView1.ColumnHeaders.Add , , "Größe", 70 * TPX, 1
    ListView1.ColumnHeaders.Add , , "Typ", 160 * TPX, 0
    ListView1.ColumnHeaders.Add , , "Geändert am", 120 * TPX, 0
    ListView1.ColumnHeaders.Add , , "Attribute", 60 * TPX, 1
    Drive1.Drive = "C:\"
End Sub

Private Sub Form_Unload(Cancel As Integer)
  Set ListView1.Icons = Nothing
  Set ListView1.SmallIcons = Nothing
  ImageList1.ListImages.Clear
  ImageList2.ListImages.Clear
End Sub

Private Sub ListView1_DblClick()
  Dim x&, aa$
  
    x = ListView1.SelectedItem.Index
    If x <> 0 Then
      If DirList(x - 1).Type = "Verzeichnis" Then
        aa = Dir1.Path
        If Right$(aa, 1) <> "\" And Right$(aa, 1) <> "/" Then
          aa = aa & "\"
        End If
        Dir1.Path = aa & DirList(x - 1).File
      End If
    End If
End Sub

Private Sub Option1_Click(Index As Integer)
  Select Case Index
    Case 0: ListView1.View = lvwReport
    Case 1: ListView1.View = lvwList
    Case 2: ListView1.View = lvwSmallIcon
    Case 3: ListView1.View = lvwIcon
  End Select
End Sub

Private Sub Dir1_Change()
  Call ViewFolder(Dir1.Path, "*.*")
End Sub

Private Sub Drive1_Change()
  Dir1.Path = Drive1.Drive
End Sub

Private Sub ViewFolder(Root$, Patt$)
  Dim Tmp As ListItem, x%, y&, Ext$
  
    MousePointer = vbHourglass
    ListView1.ListItems.Clear
    If Not GetFiles(Root, Patt) Then Exit Sub
    MousePointer = vbDefault
    DoEvents
      
    Set ListView1.Icons = ImageList2
    Set ListView1.SmallIcons = ImageList1
       
    For x = 0 To UBound(DirList) - 1
      Ext = DirList(x).Ext
      If Ext <> "" Then
        Set Tmp = ListView1.ListItems.Add(, , DirList(x).File, _
                                          Ext, Ext)
                                          
        If Ext <> "Folder" Then
          y = DirList(x).FileLen \ 1024 + 1
          Tmp.SubItems(1) = y & " KB"
        End If
      End If

      Tmp.SubItems(2) = DirList(x).Type
      Tmp.SubItems(3) = CalcFTime(DirList(x).LastWrite)
      Tmp.SubItems(4) = GetAttributes(DirList(x).Attributes)
      If x Mod 1000 = 0 Then ListView1.Refresh
    Next x
End Sub

Private Function GetFiles(Root$, Patt$) As Boolean
  Dim File$, hFile&, FD As WIN32_FIND_DATA
  Dim Ext$, Lcnt%, x&, y&, Extr%, Folder As Boolean
  Dim Descrp$, DescrpCol$
  Const Extra = "|zico=Symbol|zexe=Anwendung|" & _
                "zlnk=Verknüpfung|zcur=Cursor|"

    If Right$(Root, 1) <> "\" And Right$(Root, 1) <> "/" Then
      Root = Root & "\"
    End If

    DescrpCol = "|Folder=Verzeichnis|"
    ReDim DirList(0)
    Set ListView1.Icons = Nothing
    Set ListView1.SmallIcons = Nothing
    ImageList1.ListImages.Clear
    ImageList2.ListImages.Clear
  
    hFile = FindFirstFile(Root & Patt, FD)
    If hFile = 0 Then Exit Function
    Do
       File = Left(FD.cFileName, InStr(FD.cFileName, Chr(0)) - 1)
       If (FD.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) _
         = FILE_ATTRIBUTE_DIRECTORY Then
         If (File <> ".") And (File <> "..") Then
           With DirList(UBound(DirList))
             .Attributes = FD.dwFileAttributes
             .FileLen = FD.nFileSizeLow
             .LastWrite = FD.ftLastWriteTime
             .Ext = "Folder"
             .File = File
             .Type = "Verzeichnis"
           End With
           ReDim Preserve DirList(0 To UBound(DirList) + 1)
           If Not Folder Then Folder = True
         End If
       Else
         Ext = "z" & LCase(GetExtension(File))
         
         x = InStr(1, DescrpCol, "|" & Ext & "=")
         y = InStr(1, Extra, "|" & Ext & "=")
         
         If x = 0 Or y <> 0 Then
           If y <> 0 Then
             y = y + Len(Ext) + 2
             x = InStr(y, Extra, "|")
             Descrp = Mid$(Extra, y, x - y)
             
             Ext = Ext + CStr(Extr)
             Extr = Extr + 1
           Else
             Descrp = GetFileType(Root & File)
             DescrpCol = DescrpCol & Ext & "=" & Descrp & "|"
           End If
           ImageList1.ListImages.Add , Ext, LoadIcon(Small, Root & File)
           ImageList2.ListImages.Add , Ext, LoadIcon(Large, Root & File)
           Lcnt = Lcnt + 1
         Else
           x = x + Len(Ext) + 2
           y = InStr(x, DescrpCol, "|")
           Descrp = Mid$(DescrpCol, x, y - x)
         End If
         
         With DirList(UBound(DirList))
           .Attributes = FD.dwFileAttributes
           .FileLen = FD.nFileSizeLow
           .LastWrite = FD.ftLastWriteTime
           .Ext = Ext
           .File = File
           .Type = Descrp
         End With
         ReDim Preserve DirList(0 To UBound(DirList) + 1)
       End If
    Loop While FindNextFile(hFile, FD)
    Call FindClose(hFile)
    
    If Folder Then
      ImageList1.ListImages.Add , "Folder", LoadIcon(Small, App.Path)
      ImageList2.ListImages.Add , "Folder", LoadIcon(Large, App.Path)
    End If
    
    If UBound(DirList) > 0 Then
      Call SortName
      GetFiles = True
    End If
End Function

Private Function GetExtension(ByVal FileName$) As String
  Dim aa$, BB$, x&
    For x = Len(FileName) To 1 Step -1
      If Mid$(FileName, x, 1) = "." Then Exit For
    Next x
    GetExtension = Mid$(FileName, x + 1)
End Function

Private Function LoadIcon(Size&, File$) As IPictureDisp
  Dim Result&
  Dim Unkown As IUnknown
  Dim Icon As IconType
  Dim CLSID As CLSIdType
  Dim ShellInfo As ShellFileInfoType

    Call SHGetFileInfo(File, 0, ShellInfo, Len(ShellInfo), Size)
 
    Icon.cbSize = Len(Icon)
    Icon.picType = vbPicTypeIcon
    Icon.hIcon = ShellInfo.hIcon
    CLSID.id(8) = &HC0
    CLSID.id(15) = &H46
    Result = OleCreatePictureIndirect(Icon, CLSID, 1, Unkown)
    Set LoadIcon = Unkown
End Function

Private Function GetFileType(File$) As String
  Dim Result&
  Dim ShellInfo As ShellFileInfoType
    
    Call SHGetFileInfo(File, 0, ShellInfo, Len(ShellInfo), _
                       SHGFI_TYPENAME)
                       
    Result = InStr(1, ShellInfo.szTypeName, Chr$(0)) - 1
    GetFileType = Left(ShellInfo.szTypeName, Result)
End Function

Private Function GetAttributes(Att&) As String
  Dim aa$
  
    If Att And FILE_ATTRIBUTE_TEMPORARY Then aa = "T"
    If Att And FILE_ATTRIBUTE_READONLY Then aa = aa & "R"
    If Att And FILE_ATTRIBUTE_HIDDEN Then aa = aa & "H"
    If Att And FILE_ATTRIBUTE_SYSTEM Then aa = aa & "S"
    If Att And FILE_ATTRIBUTE_NORMAL Then aa = aa & "N"
    If Att And FILE_ATTRIBUTE_COMPRESSED Then aa = aa & "C"
    If Att And FILE_ATTRIBUTE_ARCHIVE Then aa = aa & "A"
    GetAttributes = aa
End Function


Private Function CalcFTime(FTime As FILETIME) As String
  Dim Datum$, Zeit$, aa$, hh$, mm$, ss$, DT As Date
  Dim Da$, Mo$, Ye$
  Dim STime As SYSTEMTIME
  
    Call FileTimeToSystemTime(FTime, STime)
    With STime
      Da = .wDay
      If Len(Da) < 2 Then Da = "0" & Da
      
      Mo = .wMonth
      If Len(Mo) < 2 Then Mo = "0" & Mo
      
      Ye = CStr(.wYear)
      
      mm = Trim$(CStr(.wMinute))
      If Len(mm) < 2 Then mm = "0" & mm
      
      ss = Trim$(CStr(.wSecond))
      If Len(ss) < 2 Then ss = "0" & ss
      
      hh = Trim$(CStr(.wHour))
      If Len(.wHour) < 2 Then hh = "0" & hh

      CalcFTime = Da & "." & Mo & "." & Ye & " " _
                  & hh & ":" & mm & ":" & ss
    End With
End Function

Private Function SortName()
  Dim x%, Mem As DIRLISTTYPE, Max%
  
   For x = 0 To UBound(DirList) - 1
     If DirList(x).Type = "Verzeichnis" Then
       Mem = DirList(Max)
       DirList(Max) = DirList(x)
       DirList(x) = Mem
       Max = Max + 1
     End If
   Next x
   
   If Max <> 0 Then Call QuickSort(0, Max - 1)
   If Max < UBound(DirList) Then
     Call QuickSort(Max, UBound(DirList) - 1)
   End If
End Function

Private Sub QuickSort(ByVal LB&, ByVal UB&)
  Dim P1&, P2&, Ref$, TEMP As DIRLISTTYPE

    P1 = LB
    P2 = UB
    Ref = DirList((P1 + P2) / 2).File
    
    Do
      Do While (DirList(P1).File < Ref)
        P1 = P1 + 1
      Loop
 
      Do While (DirList(P2).File > Ref)
        P2 = P2 - 1
      Loop

      If P1 <= P2 Then
        TEMP = DirList(P1)
        DirList(P1) = DirList(P2)
        DirList(P2) = TEMP
            
        P1 = P1 + 1
        P2 = P2 - 1
      End If
    Loop Until (P1 > P2)

    If LB < P2 Then Call QuickSort(LB, P2)
    If P1 < UB Then Call QuickSort(P1, UB)
End Sub


'---------- Ende Formular "Form1" alias Form1.frm  ----------
'-------------- Ende Projektdatei Project1.vbp --------------

Tipp-Kompatibilität:

Windows/VB-VersionWin32sWin95Win98WinMEWinNT4Win2000WinXP
VB4
VB5
VB6

Hat dieser Tipp auf Ihrem Betriebsystem und mit Ihrer VB-Version funktioniert?

Ja, funktioniert!

Nein, funktioniert nicht bei mir!

VB-Version:

Windows-Version:

Ihre Meinung  

Falls Sie Fragen zu diesem Artikel haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 8 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von harper am 30.10.2006 um 23:22

Hallo SHM,

ich finde es gerade gut, dass hier nicht so viele Komentare enthalten sind. Es nutzt ja nix, wenn man Code nur nutzt ohne zu verstehen wie das funktioniert. Das gilt insbesondere für den Einsatz von API. Ohne Komentare ist man gezwungen die Stellen, die man im Kopf beim Lesen nicht verfolgen kann, genauer zu analysieren eben ggf. per Einzelschritt. Jeder hat da sicher seine eigenen Methoden schnell einen klaren Überblick zu bekommen, aber nur so verstht man am Ende auch was passiert und wie API funktioniert, was am Ende einen Lerneffekt hat und darauf kommt es an. Weißt Du, hier und auf anderen Seiten findet man so viel Quellcode, dass Du richtig große Anwendungen aus den einzelnen Modulen zusammenbauen kannst, aber was nützt das, wenn Du später nicht mehr in der Lage bist, auftretende Fehler unter Kontrolle zu bekomnmen? Für eine Fehlerbeseitigung brauchst Du das Verständnis zum Code und musst auch Wissen und vor allem Verstehen was in den einzelnen Functionen genau passiert.

LG Harper

Kommentar von SHM am 21.10.2004 um 15:11

Wäre schön, wenn den Beispielen hin und wieder ein paar erklärende Sätze mitgegeben würden. Gerne auch ein bißchen ausführlich. Geht flott und hilft ungemein.

So aber ist es - für Anfänger jedenfalls - eher fast sinnlos?

Kommentar von Wim am 14.12.2002 um 20:54

Nur beim Zugriff auf den 'Ordner' Recycled gibt es probeleme.
Da gibt es Fehlermeldungen 481 usw.
Kann mann natürlich abfangen, nur ein Zugriff ist nicht möglich
odr mann Schaltet die Atrribute H und S dieses 'Ordners' aus.
Hat da jemand ne lösung gefunden?
Ich helfe mir zurzeit damit das ich einfach die Fehler abfange und ein Standart Icon zuweise.

Kommentar von Simon Rohleder am 24.04.2002 um 20:39

Hallo,
wie erreiche ich, dass ich im Explorerfenster die Einträge durch das Drücken der Spaltentitel sortieren kann?

Kommentar von Ferdinand am 13.02.2002 um 15:53

Benutze die obige funktion LoadIcon(Small,"C:\autoexec.bat")
Wichtig: !!!! Small !!!!

Kommentar von Michael Kellermann am 10.12.2001 um 10:37

Hallo,
ich möcht unter NT4.0 und kleinem Zeichensatz in einem Listview SmallIcons darstellen. Leider liefert ExtractIconEx nur große Icons. Kann mir jemand sagen was ich falsch mache??

Kommentar von jhbob am 26.10.2001 um 22:38

Es werden bei mir in Verzeichnissen ohne Unterverzeichnisse keine Dateien angezeigt.....
Scheint ein Fehler zu sein. Das Dateidatum wird allerdings richtig angezeigt.

Kommentar von Ralf Endregat am 25.01.2001 um 21:50

Kleine Anmerkung zum Tip 'Listview als Exploreransicht':
ich habe festgestellt,
das das Dateidatum gegenüber dem Windows Explorer um einen Tag und um eine Stunde zurückliegt.
Ich habe dann in der Funktion 'CalcFTime' die API-Funktion
'FileTimeToLocalFileTime' eingebaut, und zwar vor dem Aufruf von 'FileTimeToSystemTime'. Nun stimmt das
Datum zwischen Windows Explorer und diesem Beispiel.