Introduction
In this example, I will show you how to get directories in TreeView
and files in ListView
from .rar or .zip files using SharpCompress.dll library.
For this example, I'm using SplitContainer
, on the left side, I use TreeView
, on the right side, I use ListView
.
When you open a .rar or .zip file, all directories go in TreeView
and when you select a directory from TreeView
, all files goes in ListView
if that directory contains files (like the example below).
Background
Probably this method can work with different library, I haven't tested it.
Using the Code
First import SharpCompress.dll into your project, and use Imports
like the example below:
#Region " Imports "
Option Explicit On
Imports System.IO
Imports System.Runtime.InteropServices
Imports SharpCompress.Archives
Imports SharpCompress.Common
#End Region
In Form Class
, declare this:
Public Class Form1 : Inherits Form
#Region " Declares "
<System.Diagnostics.CodeAnalysis.SuppressMessage("Code Quality", _
"IDE0069:Disposable fields should be disposed", Justification:="<Pending>")>
Private WithEvents Archive As IArchive
Private szArchivePath As String
Private ReadOnly listViewItems As New List(Of ListViewItem)()
Public listViewItem As ListViewItem
Private ReadOnly _ImgListFileType As New List(Of String)() From {"Empty"}
#End Region
End Class
I create Sub
Procedures to use the code easily. In form should look like this:
#Region " Imports "
ption Explicit On
Imports System.IO
Imports System.Runtime.InteropServices
Imports SharpCompress.Archives
Imports SharpCompress.Common
#End Region
Public Class Form1 : Inherits Form
#Region " Declares "
<System.Diagnostics.CodeAnalysis.SuppressMessage("Code Quality", _
"IDE0069:Disposable fields should be disposed", Justification:="<Pending>")>
Private WithEvents Archive As IArchive
Private szArchivePath As String
Private ReadOnly listViewItems As New List(Of ListViewItem)()
Public listViewItem As ListViewItem
Private ReadOnly _ImgListFileType As New List(Of String)() From {"Empty"}
#End Region
#Region " GetFileType "
Private Sub GetFileType(ByVal GetFrom As String, SearchIn As List(Of String))
If Not SearchIn.Contains(GetFrom) Then
SearchIn.Add(GetFrom)
SearchIn.Remove(String.Empty)
End If
End Sub
#End Region
#Region " List Icons "
Private Sub ListIcons()
For Each iFound In _ImgListFileType
If Not iFound = Nothing Then
If Not ImgLargeListView.Images.ContainsKey(iFound) Then
If InvokeRequired Then
Invoke(Sub() ImgListView.Images.Add(iFound, GetFileIcon_
(iFound, IconSize.SHGFI_SMALLICON)))
Invoke(Sub() ImgLargeListView.Images.Add(iFound, GetFileIcon_
(iFound, IconSize.SHGFI_LARGEICON)))
Else
ImgListView.Images.Add(iFound, GetFileIcon_
(iFound, IconSize.SHGFI_SMALLICON))
ImgLargeListView.Images.Add(iFound, GetFileIcon_
(iFound, IconSize.SHGFI_LARGEICON))
End If
End If
End If
Next iFound
End Sub
#End Region
#Region " Close Archive "
Private Sub CloseArchive()
If Not (Archive Is Nothing) Then
Archive.Dispose()
End If
End Sub
#End Region
#Region " Fill TreeView "
Private Sub FillTreeView(ByVal TreeViewEntryes As TreeView)
CloseArchive()
TreeViewEntryes.Sort()
TreeViewEntryes.Nodes.Clear()
LstEntrys.Clear()
Try
Archive = ArchiveFactory.Open(szArchivePath)
Dim _ImgListFolders As New List(Of Image)()
Dim folder As String = _
Environment.GetFolderPath(Environment.SpecialFolder.Windows)
_ImgListFolders.Add(GetFolderIcon(folder, False))
ImgListTree.Images.AddRange(_ImgListFolders.ToArray())
ImgListTree.Images.Add(GetFileIcon(Path.GetExtension(szArchivePath), _
IconSize.SHGFI_SMALLICON))
TreeViewEntryes.Nodes.Add(Path.GetFileName(szArchivePath))
TreeViewEntryes.Nodes(0).ImageIndex = ImgListTree.Images.Count - 1
TreeViewEntryes.Nodes(0).SelectedImageIndex = ImgListTree.Images.Count - 1
For Each iEntry In Archive.Entries.Where(Function(e) Not e.IsDirectory)
If Archive IsNot Nothing Then
GetFileType(Path.GetExtension(iEntry.Key), _ImgListFileType)
End If
Next iEntry
ListIcons()
For Each _Entry In Archive.Entries.Where(Function(e) e.IsDirectory)
Dim nodes As TreeNodeCollection = TreeViewEntryes.Nodes(0).Nodes
If Archive.Type = ArchiveType.Rar Then
TreeEntryes.PathSeparator = "\"
For Each PathSep As String In _Entry.Key.Split("\"c)
If Not nodes.ContainsKey(PathSep) Then
nodes.Add(PathSep, PathSep)
End If
nodes = nodes(PathSep).Nodes
Next PathSep
ElseIf Archive.Type = ArchiveType.Zip Then
TreeEntryes.PathSeparator = "/"
For Each PathSep As String In _Entry.Key.TrimEnd("/").Split("/"c)
If Not nodes.ContainsKey(PathSep) Then
nodes.Add(PathSep, PathSep)
End If
nodes = nodes(PathSep).Nodes
Next PathSep
End If
Next _Entry
TreeViewEntryes.Focus()
TreeViewEntryes.Nodes(0).Expand()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
#End Region
#Region " Fill ListView"
Private Sub FillListView(ByVal ListEntrys As ListView)
ListEntrys.Items.Clear()
listViewItems.Clear()
For Each Entry In Archive.Entries.Where(Function(D) Not D.IsDirectory)
If Path.GetExtension(Entry.Key) = Nothing Then
listViewItem = New ListViewItem(Path.GetFileName(Entry.Key), _
ImgLargeListView.Images.IndexOfKey("Empty"))
Else
listViewItem = New ListViewItem(Path.GetFileName(Entry.Key), _
ImgLargeListView.Images.IndexOfKey(Path.GetExtension(Entry.Key)))
End If
If TreeEntryes.Nodes(0).IsSelected Then
If Entry.Key.StartsWith(Path.GetFileName(Entry.Key)) Then
listViewItems.Add(listViewItem)
End If
Else
Dim szRarFullPathReplace As String = _
TreeEntryes.SelectedNode.FullPath.Replace_
(Path.GetFileName(szArchivePath), "").TrimStart("\")
Dim szRarSelectedNode As String = Entry.Key.StartsWith_
(szRarFullPathReplace & "\" & Path.GetFileName(Entry.Key))
Dim szZipFullPathReplace As String = _
TreeEntryes.SelectedNode.FullPath.Replace_
(Path.GetFileName(szArchivePath), "").TrimStart("/")
Dim szZipSelectedNode As String = _
Entry.Key.StartsWith(szZipFullPathReplace & "/" & _
Path.GetFileName(Entry.Key))
If szRarSelectedNode OrElse szZipSelectedNode Then
listViewItems.Add(listViewItem)
End If
End If
Next Entry
ListEntrys.Items.AddRange(listViewItems.ToArray())
End Sub
#End Region
End Class
On Button Click Event
, I call _OpenRarDlg
as New
OpenFileDialog
to open .rar or .zip file.
#Region " Button Open "
Private Sub BtnOpen_Click(sender As Object, e As EventArgs) Handles BtnOpen.Click
Dim _OpenRarDlg As New OpenFileDialog
With _OpenRarDlg
.DefaultExt = ".rar"
.Filter = "Supported Files (*.rar, *.zip)|*.rar;*.zip"
End With
If _OpenRarDlg.ShowDialog = DialogResult.OK Then
szArchivePath = _OpenRarDlg.FileName
FillTreeView(TreeEntryes)
End If
End Sub
#End Region
On TreeView AfterSelect Event
, I call
FillListView(LstEntrys)
. When TreeView
Node (Directory) is selected and if that directory contains files, then all files from selected directory will be displayed in ListView.
#Region " TreeView AfterSelect Event "
Private Sub TreeEntryes_AfterSelect(sender As Object, e As TreeViewEventArgs) _
Handles TreeEntryes.AfterSelect
FillListView(LstEntrys)
End Sub
#End Region
On FormClosed Event
, the archive should be closed.
#Region " On Form Closed Event "
Protected Overrides Sub OnFormClosed(e As FormClosedEventArgs)
MyBase.OnFormClosed(e)
CloseArchive()
End Sub
#End Region
And now the Module
. This Module
is to get icons for each file type by extension, I decided to put this Module
in Form Class
because I don't want to create a new .vb file for this Module
.
#Region " Get Icon Module"
odule GetIcon
Private Const MAX_PATH As Int32 = 260
Private Const SHGFI_ICON As Int32 = &H100
Private Const SHGFI_USEFILEATTRIBUTES As Int32 = &H10
Private Const FILE_ATTRIBUTE_NORMAL As Int32 = &H80
Private Const SHGFI_LARGEICON As Integer = &H0
Private Const SHGFI_SMALLICON As Integer = &H1
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
Private Structure SHFILEINFO
Public hIcon As IntPtr
Public iIcon As Integer
Public dwAttributes As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)>
Public szDisplayName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)>
Public szTypeName As String
End Structure
Public Enum IconSize
SHGFI_LARGEICON = 0
SHGFI_SMALLICON = 1
End Enum
<DllImport("shell32.dll", CharSet:=CharSet.Auto)>
Private Function SHGetFileInfoW(<[In](), MarshalAs(UnmanagedType.LPTStr)> _
ByVal pszPath As String, ByVal dwFileAttributes As Int32, _
ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Int32, ByVal uFlags As Int32) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)>
Private Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean
End Function
Public Function GetFileIcon(ByVal fileExt As String, _
Optional ByVal ICOsize As IconSize = IconSize.SHGFI_LARGEICON) As Bitmap
Dim shinfo As New SHFILEINFO
shinfo.szDisplayName = New String(Chr(0), MAX_PATH)
shinfo.szTypeName = New String(Chr(0), 80)
SHGetFileInfoW(fileExt, FILE_ATTRIBUTE_NORMAL, shinfo, _
Marshal.SizeOf(shinfo), SHGFI_ICON Or ICOsize Or SHGFI_USEFILEATTRIBUTES)
Dim bmp As Bitmap = Icon.FromHandle(shinfo.hIcon).ToBitmap
DestroyIcon(shinfo.hIcon)
Return bmp
End Function
Public Function GetFolderIcon_
(ByVal PathName As String, ByVal LargeIco As Boolean) As Bitmap
Dim fi As New SHFILEINFO
If LargeIco Then
SHGetFileInfoW(PathName, 0, fi, Marshal.SizeOf(fi), SHGFI_ICON Or SHGFI_LARGEICON)
Else
SHGetFileInfoW(PathName, 0, fi, Marshal.SizeOf(fi), SHGFI_ICON Or SHGFI_SMALLICON)
End If
Dim bm As Bitmap = Icon.FromHandle(fi.hIcon).ToBitmap
DestroyIcon(fi.hIcon)
Return bm
End Function
End Module
#End Region
The all Form
code looks like this:
#Region " Imports "
ption Explicit On
Imports System.IO
Imports System.Runtime.InteropServices
Imports SharpCompress.Archives
Imports SharpCompress.Common
#End Region
Public Class Form1 : Inherits Form
#Region " Declares "
<System.Diagnostics.CodeAnalysis.SuppressMessage("Code Quality", _
"IDE0069:Disposable fields should be disposed", Justification:="<Pending>")>
Private WithEvents Archive As IArchive
Private szArchivePath As String
Private ReadOnly listViewItems As New List(Of ListViewItem)()
Public listViewItem As ListViewItem
Private ReadOnly _ImgListFileType As New List(Of String)() From {"Empty"}
#End Region
#Region " GetFileType "
Private Sub GetFileType(ByVal GetFrom As String, SearchIn As List(Of String))
If Not SearchIn.Contains(GetFrom) Then
SearchIn.Add(GetFrom)
SearchIn.Remove(String.Empty)
End If
End Sub
#End Region
#Region " List Icons "
Private Sub ListIcons()
For Each iFound In _ImgListFileType
If Not iFound = Nothing Then
If Not ImgLargeListView.Images.ContainsKey(iFound) Then
If InvokeRequired Then
Invoke(Sub() ImgListView.Images.Add(iFound, _
GetFileIcon(iFound, IconSize.SHGFI_SMALLICON)))
Invoke(Sub() ImgLargeListView.Images.Add(iFound, _
GetFileIcon(iFound, IconSize.SHGFI_LARGEICON)))
Else
ImgListView.Images.Add(iFound, _
GetFileIcon(iFound, IconSize.SHGFI_SMALLICON))
ImgLargeListView.Images.Add(iFound, _
GetFileIcon(iFound, IconSize.SHGFI_LARGEICON))
End If
End If
End If
Next iFound
End Sub
#End Region
#Region " Close Archive "
Private Sub CloseArchive()
If Not (Archive Is Nothing) Then
Archive.Dispose()
End If
End Sub
#End Region
#Region " Fill TreeView "
Private Sub FillTreeView(ByVal TreeViewEntryes As TreeView)
CloseArchive()
TreeViewEntryes.Sort()
TreeViewEntryes.Nodes.Clear()
LstEntrys.Clear()
Try
Archive = ArchiveFactory.Open(szArchivePath)
Dim _ImgListFolders As New List(Of Image)()
Dim folder As String = _
Environment.GetFolderPath(Environment.SpecialFolder.Windows)
_ImgListFolders.Add(GetFolderIcon(folder, False))
ImgListTree.Images.AddRange(_ImgListFolders.ToArray())
ImgListTree.Images.Add(GetFileIcon(Path.GetExtension(szArchivePath), _
IconSize.SHGFI_SMALLICON))
TreeViewEntryes.Nodes.Add(Path.GetFileName(szArchivePath))
TreeViewEntryes.Nodes(0).ImageIndex = ImgListTree.Images.Count - 1
TreeViewEntryes.Nodes(0).SelectedImageIndex = ImgListTree.Images.Count - 1
For Each iEntry In Archive.Entries.Where(Function(e) Not e.IsDirectory)
If Archive IsNot Nothing Then
GetFileType(Path.GetExtension(iEntry.Key), _ImgListFileType)
End If
Next iEntry
ListIcons()
For Each _Entry In Archive.Entries.Where(Function(e) e.IsDirectory)
Dim nodes As TreeNodeCollection = TreeViewEntryes.Nodes(0).Nodes
If Archive.Type = ArchiveType.Rar Then
TreeEntryes.PathSeparator = "\"
For Each PathSep As String In _Entry.Key.Split("\"c)
If Not nodes.ContainsKey(PathSep) Then
nodes.Add(PathSep, PathSep)
End If
nodes = nodes(PathSep).Nodes
Next PathSep
ElseIf Archive.Type = ArchiveType.Zip Then
TreeEntryes.PathSeparator = "/"
For Each PathSep As String In _Entry.Key.TrimEnd("/").Split("/"c)
If Not nodes.ContainsKey(PathSep) Then
nodes.Add(PathSep, PathSep)
End If
nodes = nodes(PathSep).Nodes
Next PathSep
End If
Next _Entry
TreeViewEntryes.Focus()
TreeViewEntryes.Nodes(0).Expand()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
#End Region
#Region " Fill ListView"
Private Sub FillListView(ByVal ListEntrys As ListView)
ListEntrys.Items.Clear()
listViewItems.Clear()
For Each Entry In Archive.Entries.Where(Function(D) Not D.IsDirectory)
If Path.GetExtension(Entry.Key) = Nothing Then
listViewItem = New ListViewItem(Path.GetFileName(Entry.Key), _
ImgLargeListView.Images.IndexOfKey("Empty"))
Else
listViewItem = New ListViewItem(Path.GetFileName(Entry.Key), _
ImgLargeListView.Images.IndexOfKey(Path.GetExtension(Entry.Key)))
End If
If TreeEntryes.Nodes(0).IsSelected Then
If Entry.Key.StartsWith(Path.GetFileName(Entry.Key)) Then
listViewItems.Add(listViewItem)
End If
Else
Dim szRarFullPathReplace As String = _
TreeEntryes.SelectedNode.FullPath.Replace_
(Path.GetFileName(szArchivePath), "").TrimStart("\")
Dim szRarSelectedNode As String = _
Entry.Key.StartsWith(szRarFullPathReplace & "\" & _
Path.GetFileName(Entry.Key))
Dim szZipFullPathReplace As String = _
TreeEntryes.SelectedNode.FullPath.Replace_
(Path.GetFileName(szArchivePath), "").TrimStart("/")
Dim szZipSelectedNode As String = _
Entry.Key.StartsWith(szZipFullPathReplace & "/" & _
Path.GetFileName(Entry.Key))
If szRarSelectedNode OrElse szZipSelectedNode Then
listViewItems.Add(listViewItem)
End If
End If
Next Entry
ListEntrys.Items.AddRange(listViewItems.ToArray())
End Sub
#End Region
#Region " Button Open "
Private Sub BtnOpen_Click(sender As Object, e As EventArgs) Handles BtnOpen.Click
Dim _OpenRarDlg As New OpenFileDialog
With _OpenRarDlg
.DefaultExt = ".rar"
.Filter = "Supported Files (*.rar, *.zip)|*.rar;*.zip"
End With
If _OpenRarDlg.ShowDialog = DialogResult.OK Then
szArchivePath = _OpenRarDlg.FileName
FillTreeView(TreeEntryes)
End If
End Sub
#End Region
#Region " TreeView AfterSelect Event "
Private Sub TreeEntryes_AfterSelect(sender As Object, e As TreeViewEventArgs) _
Handles TreeEntryes.AfterSelect
FillListView(LstEntrys)
End Sub
#End Region
#Region " On Form Closed Event "
Protected Overrides Sub OnFormClosed(e As FormClosedEventArgs)
MyBase.OnFormClosed(e)
CloseArchive()
End Sub
#End Region
End Class
#Region " Get Icon Module"
odule GetIcon
Private Const MAX_PATH As Int32 = 260
Private Const SHGFI_ICON As Int32 = &H100
Private Const SHGFI_USEFILEATTRIBUTES As Int32 = &H10
Private Const FILE_ATTRIBUTE_NORMAL As Int32 = &H80
Private Const SHGFI_LARGEICON As Integer = &H0
Private Const SHGFI_SMALLICON As Integer = &H1
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
Private Structure SHFILEINFO
Public hIcon As IntPtr
Public iIcon As Integer
Public dwAttributes As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)>
Public szDisplayName As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)>
Public szTypeName As String
End Structure
Public Enum IconSize
SHGFI_LARGEICON = 0
SHGFI_SMALLICON = 1
End Enum
<DllImport("shell32.dll", CharSet:=CharSet.Auto)>
Private Function SHGetFileInfoW(<[In](), MarshalAs(UnmanagedType.LPTStr)> _
ByVal pszPath As String, ByVal dwFileAttributes As Int32, _
ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Int32, ByVal uFlags As Int32) As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)>
Private Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean
End Function
Public Function GetFileIcon(ByVal fileExt As String, _
Optional ByVal ICOsize As IconSize = IconSize.SHGFI_LARGEICON) As Bitmap
Dim shinfo As New SHFILEINFO
shinfo.szDisplayName = New String(Chr(0), MAX_PATH)
shinfo.szTypeName = New String(Chr(0), 80)
SHGetFileInfoW(fileExt, FILE_ATTRIBUTE_NORMAL, shinfo, _
Marshal.SizeOf(shinfo), SHGFI_ICON Or ICOsize Or SHGFI_USEFILEATTRIBUTES)
Dim bmp As Bitmap = Icon.FromHandle(shinfo.hIcon).ToBitmap
DestroyIcon(shinfo.hIcon)
Return bmp
End Function
Public Function GetFolderIcon(ByVal PathName As String, _
ByVal LargeIco As Boolean) As Bitmap
Dim fi As New SHFILEINFO
If LargeIco Then
SHGetFileInfoW(PathName, 0, fi, _
Marshal.SizeOf(fi), SHGFI_ICON Or SHGFI_LARGEICON)
Else
SHGetFileInfoW(PathName, 0, fi, _
Marshal.SizeOf(fi), SHGFI_ICON Or SHGFI_SMALLICON)
End If
Dim bm As Bitmap = Icon.FromHandle(fi.hIcon).ToBitmap
DestroyIcon(fi.hIcon)
Return bm
End Function
End Module
#End Region
History
- 6th October, 2019: Initial version