Private Sub NewSource()
With fiSrc
Dim s As String, sOld As String
On Error GoTo FailNewSource
sOld = fiSrc
‘ Assign a file name to a file information object
fiSrc = txtSrc.Text
‘ Get back all the information about the file
s = s & “Display name: “ & .DisplayName & sCrLf
s = s & “Type name: “ & .TypeName & sCrLf
s = s & “Length: “ & .Length & “ bytes” & sCrLf
s = s & “Created: “ & .Created & sCrLf
s = s & “Last modified: “ & .Modified & sCrLf
s = s & “Last accessed: “ & .Accessed & sCrLf
lblSrc.Caption = s
Set imgLIcon.Picture = .ShellIcon()
Set imgSIcon.Picture = .SmallIcon()
Set imgLIconSel.Picture = .ShellIcon(SHGFI_SELECTED)
Set imgSIconSel.Picture = .SmallIcon(SHGFI_SELECTED)
Set imgLIconLink.Picture = .ShellIcon(SHGFI_LINKOVERLAY)
Set imgSIconLink.Picture = .SmallIcon(SHGFI_LINKOVERLAY)
§
Private Sub NewSpecialFolder(ByVal iInc As Long)
Do
On Error Resume Next
fiFolder = udSpecLoc ‘ Folder to CFileInfo object
If Err = 0 Then Exit Do
udSpecLoc.Value = udSpecLoc + iInc ‘ Skip missing numbers
‘ Wrap property doesn’t work on assignment
If udSpecLoc = udSpecLoc.Min Then udSpecLoc = udSpecLoc.Max
If udSpecLoc = udSpecLoc.Max Then udSpecLoc = udSpecLoc.Min
Loop
lblSpecLoc.Caption = “Special folder: “ & fiFolder.DisplayName
imgLSpecLoc = fiFolder.ShellIcon
imgSSpecLoc = fiFolder.SmallIcon
End Sub
Private Enum EItemState
eisNotCreated
eisFile ‘ File or directory
eisDrive ‘ Drive
eisID ‘ PIDL passed to us
eisFolder ‘ PIDL created by us from special folder
End Enum
Private eis As EItemState ‘ How object was created
Private vItem As Variant ‘ File name or PIDL
Private shfi As SHFILEINFO ‘ Info from SHGetFileInfo
Private fd As WIN32_FIND_DATA ‘ Info from FindFirstFile
Private afAttr As Long ‘ File attributes
Private afOption As Long ‘ Options for SHGetFileInfo
Property Let Item(vItemA As Variant)
Dim h As Long, f As Long, af As Long
Destroy ‘ Clear any previous assignment
If VarType(vItemA) = vbString Then
‘ String item is a file, directory, or drive
If Len(vItemA) <= 3 And Mid$(vItemA, 2, 1) = “:” Then
‘ Must be drive, get attributes
afAttr = 0: afOption = 0
Else
‘ No terminating backslashes
MUtility.DenormalizePath vItemA
‘ For file, get information in advance
h = FindFirstFile(vItemA, fd)
If h = hInvalid Then ApiRaise Err.LastDllError
FindClose h
afAttr = fd.dwFileAttributes
afOption = SHGFI_USEFILEATTRIBUTES
End If
eis = eisFile
af = afOption And (Not SHGFI_PIDL) Or _
SHGFI_DISPLAYNAME Or SHGFI_TYPENAME
f = SHGetFileInfo(vItemA, afAttr, shfi, LenB(shfi), af)
Else
‘ Integer item is a special folder constant or pidl
If vItemA < 50 Then
‘ Turn special folder location into a pidl
Dim pidl As Long
SHGetSpecialFolderLocation 0, CLng(vItemA), pidl
vItemA = pidl
eis = eisFolder
Else
eis = eisID
pidl = vItemA
End If
‘ For special folders or other PIDLs, everything comes from system
afAttr = 0: afOption = 0
‘ Get item ID pointer, but don’t use attributes
af = SHGFI_PIDL Or SHGFI_DISPLAYNAME Or _
SHGFI_TYPENAME
f = SHGetItemInfo(pidl, afAttr, shfi, Len(shfi), af)
End If
If f Then
vItem = vItemA
Else
eis = eisNotCreated
End If
End Property
Function SmallIcon(Optional afOverlay As Long = 0) As Picture
Dim shfiT As SHFILEINFO
If eis = eisNotCreated Then Exit Function
' Filter out any invalid flags -- only overlays allowed
afOverlay = afOverlay And (SHGFI_LINKOVERLAY Or SHGFI_SELECTED _
Or SHGFI_OPENICON)
' Add in standard and small icon flags
afOverlay = afOverlay Or afOption Or SHGFI_ICON Or SHGFI_SMALLICON
GetFileItemInfo vItem, shfiT, afOverlay, afAttr
Set SmallIcon = MPicTool.IconToPicture(shfiT.hIcon)
End Function
You can probably guess the implementation of the Length, Created, Modified, and Accessed methods, which use data received from the call to FindFirstFile. There’s a lot more detail to the CFileInfo class. For example, it also handles drives and supplies appropriate drive data in properties—but I’ll leave you to struggle through that yourself.
SHGetFileInfo retrieves additional data not used in the CFileInfo class. For example, large and small icons used by the system are maintained in two internal ImageLists. Unfortunately, the Visual Basic ImageList control doesn’t give you a way to use them. It’s possible to iterate through the system ImageList control directly by using ImageList API functions with SHGetFileInfo. This technique is illustrated in the Windows Interface Tricks application. It turned out to be a dead end, however; I couldn’t find anything useful to do with system ImageLists in Visual Basic that couldn’t be done more easily without them.