Option Explicit
'==========================================================
' The declarations necessary to recycle (delete)
'==========================================================
Const FO_DELETE = &H3
Const FOF_ALLOWUNDO = &H40
Private Type SHFILEOPSTRUCT
hwnd As Long
wFunc As Long
pFrom As String
pTo As String
fFlags As Integer
fAnyOperationsAborted As Long
hNameMappings As Long
lpszProgressTitle As Long
End Type
Private Declare Function SHFileOperation _
Lib "shell32.dll" Alias "SHFileOperationA" ( _
lpFileOp As SHFILEOPSTRUCT) As Long
'==========================================================
' To disable TextBox default right click popup menu
'==========================================================
Private Declare Function LockWindowUpdate _
Lib "user32" (ByVal hwndLock As Long) As Long
'==========================================================
' The declaration necessary to Run and Edit files
'==========================================================
Private Declare Function ShellExecute _
Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hwnd As Long, _
ByVal lpOperation As String, _
ByVal lpFile As String, _
ByVal lpParameters As String, _
ByVal lpDirectory As String, _
ByVal nShowCmd As Long) As Long
'==========================================================
' General Program Declarations
'==========================================================
' Captions:
Const FMCAPTION = "File Viewer"
Const SHCAPTION = "Show Pictures"
' The minimum window width is set here
Const MINWD! = 9780
' A textbox can only hold a few more bytes than 57000
' edit this if a RichTextBox is substituted.
Const MAXBYTES& = 57000
' Since the mnuRecent() array starts at 0, this constant
' effectively allows 10 recent directories.
Const MAXRECENT = 9
' Format strings
Const F11 = "###,###,###", F14 = "##,###,###,###"
' Constants to Identify Columns
Private Enum columnEnum
NAM = 1
EXT
SIZ
DAT
End Enum
' Window position and size
Dim FmLt!, FmTp!, FmWd!, FmHt!
' Flags
Dim InViewFlag As Boolean
Dim KeyPressedElsewhere As Boolean
' Various other form level vars
Dim iniFile$, oldPath$, lastDir%, currSortKey%
'==========================================================
' Click Menu Items
'==========================================================
Private Sub mnuRecent_Click(Index%)
On Error GoTo md1
'First change the Drive if necessary
If LCase$(Left$(mnuRecent(Index).Caption, 1)) <> _
LCase$(Left$(Drive1.Drive, 1)) Then
Drive1.Drive = mnuRecent(Index).Caption
End If
'Next change the directory. By making equal
' to oldPath the ListView will be filled.
oldPath = mnuRecent(Index).Caption
Dir1.Path = oldPath
Dir1_Click
GoTo md2
md1: MsgBox mnuRecent(Index).Caption & " Error"
Resume md2
md2: On Error GoTo 0
End Sub
Private Sub mnuPicOpt_Click()
With mnuPicOpt
Select Case .Caption
Case SHCAPTION
.Caption = "Don't " & SHCAPTION
Case Else
.Caption = SHCAPTION
End Select
End With
End Sub
'==========================================================
' Navigation Events
'==========================================================
Private Sub Drive1_Change()
On Error GoTo DriveHandler
Dir1.Path = CurDir(Drive1.Drive)
Exit Sub
DriveHandler:
Drive1.Drive = Dir1.Path
End Sub
Private Sub Dir1_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
oldPath = Dir1.List(Dir1.ListIndex)
Dir1_Click
End If
End Sub
' 1. How to create and manage a dynamic menu.
Private Sub Dir1_Click()
Dir1.Path = Dir1.List(Dir1.ListIndex)
'The first click on a directory will not fill the
' Listview. 2nd click (on same directory) will.
If oldPath <> Dir1.Path Then
oldPath = Dir1.Path
Exit Sub
End If
Dim j%, t$
'The number of folders is handily returned
' by Dir1 - so show it in a label.
t = CStr(Dir1.ListCount) & " folder"
If Dir1.ListCount <> 1 Then t = t & "s"
Label1.Caption = t
'Check if this is one of the stored "recent" paths
t = LCase$(oldPath)
Do Until j >= lastDir
If LCase$(mnuRecent(j).Caption) = t Then Exit Do
j = j + 1
Loop
'Assign as necessary
If j > MAXRECENT Then
'Not found & at max - assign to last.
j = MAXRECENT
ElseIf j >= lastDir Then
'Not found & not at max - create new.
If j Then Load mnuRecent(j)
mnuRecent(j).Enabled = True
lastDir = lastDir + 1
End If
'Assignment if found - redundant but no problem
mnuRecent(j).Caption = Dir1.Path
ShuffleUp j
FilesGet lvwAscending, NAM
End Sub
'Just bring the desired "Recent" choice up to index 0
Private Sub ShuffleUp(i%)
Dim j%, sl$
sl = mnuRecent(i).Caption
For j = i To 1 Step -1
mnuRecent(j).Caption = mnuRecent(j - 1).Caption
Next
mnuRecent(0).Caption = sl
End Sub
'==========================================================
' Events While Viewing
'==========================================================
Private Sub Form_KeyDown(KeyCode%, Shift%)
Text1_KeyDown KeyCode, Shift
End Sub
Private Sub Text1_KeyDown(KeyCode%, Shift%)
Select Case KeyCode
Case 14 To 26, 28 To 31, 33 To 47
Case Else
KeyPressedElsewhere = True
ViewOut
End Select
End Sub
'14. How to suppress textbox default right click popup.
Private Sub Text1_MouseDown(Button%, Shift%, X!, Y!)
If Button = vbRightButton Then
' Avoid the disabled gray text by locking updates
LockWindowUpdate Text1.hwnd
' A disabled TextBox will not display default menu
Text1.Enabled = False
PopupMenu mnuLVpop
Text1.Enabled = True
LockWindowUpdate 0&
End If
End Sub
Private Sub Text1_MouseUp(Button%, Shift%, X!, Y!)
If Button = vbLeftButton Then ViewOut
End Sub
Private Sub Form_MouseUp(Button%, Shift%, X!, Y!)
If Button = vbLeftButton Then ViewOut
End Sub
Private Sub Form_MouseDown(Button%, Shift%, X!, Y!)
If Button = vbRightButton Then PopupMenu mnuLVpop
End Sub
Private Sub Image1_MouseUp(Button%, Shift%, X!, Y!)
If Button = vbLeftButton Then ViewOut
End Sub
Private Sub Image1_MouseDown(Button%, Shift%, X!, Y!)
If Button = vbRightButton Then PopupMenu mnuLVpop
End Sub
'==========================================================
' ListView Events
'==========================================================
Private Sub ListView1_KeyUp(KeyCode%, Shift%)
Static j%
'KeyPressedElsewhere is basically a fix ... where the
' keydown happened in another control, but when the
' key comes up you are subject to the suddenly visible,
' active, and focused Listview.
Select Case KeyCode
Case vbKeyReturn, vbKeySpace
If KeyPressedElsewhere Then Exit Sub
ListView1_MouseUp 1, 0, 0, 0
KeyCode = 0
Case vbKeyDelete
mnuDelete_Click
KeyCode = 0
Case vbKeyF2
mnuRename_Click
KeyCode = 0
Case vbKeyF4
mnuEdit_Click
KeyCode = 0
Case vbKeyF5
mnuRun_Click
KeyCode = 0
Case vbKeyEscape
If KeyPressedElsewhere Then Exit Sub
Unload Me
Case Else
CheckSelected
End Select
End Sub
Private Sub ListView1_KeyDown(KeyCode%, Shift%)
KeyPressedElsewhere = False
End Sub
' 2. How to create and show a popup menu.
Private Sub ListView1_MouseUp(Button%, Shift%, X!, Y!)
Static j%
j = CheckSelected
If j = 0 Then Exit Sub
If Button = vbRightButton Then
SuppressEditChoice j
PopupMenu mnuLVpop
mnuEdit.Visible = True
Else
mnuView.Caption = "Back"
SuppressEditChoice j
Caption = Text2.Text
Select Case LCase$(ListView1.ListItems(j).SubItems(1))
Case "jpg", "gif", "jpeg", "bmp", "ico"
If mnuPicOpt.Caption = SHCAPTION Then
ShowPic
Exit Sub
End If
End Select
ShowText
End If
End Sub
'These file types are not to editable.
' So that choice is just made unavailable.
Private Sub SuppressEditChoice(i%)
Select Case LCase$(ListView1.ListItems(i).SubItems(1))
Case "com", "exe", "pif", "zip"
mnuEdit.Visible = False
End Select
End Sub
'12. How to display any file in a textbox
Private Sub ShowText()
Dim f%, j&, byts&, t$
On Error GoTo st1
f = FreeFile
Open Caption For Binary As f
byts = LOF(f)
Select Case byts
Case Is > MAXBYTES: byts = MAXBYTES
Case 0: GoTo st2
End Select
t = Space$(byts)
Get f, , t
'Replace all Chr$(0) in the file with a space
' (that char terminates textbox display)
For j = 1 To byts
If Mid$(t, j, 1) = vbNullChar Then _
Mid$(t, j, 1) = " "
Next
Text1 = t
InViewFlag = True
Picture1.Visible = False
mnuMain.Visible = False
mnuPicOpt.Visible = False
Text1.Visible = True
Text1.SetFocus
GoTo st2
st1: Resume st2
st2: On Error GoTo 0
Close
End Sub
'16. How to proportion an image to fit inside a Form.
Private Sub ShowPic()
Const MNUHEIGHT! = 285
Dim sc$, fh!, fw!, ph!, pw!
Dim reread As Boolean
On Error GoTo sp1
InViewFlag = True
Picture1.Visible = False
mnuMain.Visible = False
mnuPicOpt.Visible = False
fw = ScaleWidth
fh = ScaleHeight + MNUHEIGHT
With Image1
.Move 0, 0, fw, fh
Set .Picture = LoadPicture(Caption)
ph = Fix(ScaleY(.Picture.Height, _
vbHimetric, vbTwips))
pw = Fix(ScaleX(.Picture.Width, _
vbHimetric, vbTwips))
sc = " Actual:" & picSize(pw, ph)
If pw > fw Then
If ph > fh Then
'both dimensions > container
If (pw / fw) > (ph / fh) Then
'if the ratio of the
'width > ratio of height
'then we need to limit
'the image height to
'maintain proportion
.Height = ph * fw / pw
Else
'vice versa
.Width = pw * fh / ph
End If
Else
'just the width > container
.Height = ph * fw / pw
End If
reread = True
ElseIf ph > fh Then
'just the height > container
.Width = pw * fh / ph
reread = True
Else
'image will fit in container
' without change
.Height = ph
.Width = pw
End If
ph = .Height: pw = .Width
'Center the image in the frame
If ph < fh Then .Top = (fh - ph) / 2
If pw < fw Then .Left = (fw - pw) / 2
If reread Then
Set .Picture = LoadPicture(Caption)
sc = sc & " Shown:" & picSize(pw, ph)
End If
Caption = Caption & sc
.Visible = True
End With
GoTo sp3
sp1: MsgBox Error(Err)
Resume sp2
sp2: ViewOut
sp3: On Error GoTo 0
End Sub
Private Function picSize$(w!, h!)
picSize = CStr(Fix(w / 15 + 0.5)) & "W x " & _
CStr(Fix(h / 15 + 0.5)) & "H"
End Function
'10. How to sort a ListView by clicking columnheaders.
Private Sub ListView1_ColumnClick( _
ByVal ColumnHeader As ColumnHeader)
With ListView1
If .ListItems.Count < 2 Then Exit Sub
'11. How to sort numeric data in a ListView.
' The listview is an alpha sort - to make it
' work with numbers first pad with zeros
If ColumnHeader.Index = SIZ Then ZerosPad
'Column 4 is the date - displaying
' the most recent on the first sort.
Select Case ColumnHeader.Index
Case currSortKey: .SortOrder = 1 - .SortOrder
Case DAT: .SortOrder = lvwDescending
Case Else: .SortOrder = lvwAscending
End Select
'Do the actual sort and remember the column so if
' it is clicked again the order will be reversed.
currSortKey = ColumnHeader.Index
.SortKey = currSortKey - 1
.Sorted = True
'Remove the padded zeros
If ColumnHeader.Index = SIZ Then ZerosOut
.ListItems(1).Selected = True
End With
End Sub
'==========================================================
' Misc ListView Routines
'==========================================================
Private Function CheckSelected%()
Static j%
'Check the Listview items to see if one is selected
For j = ListView1.ListItems.Count To 1 Step -1
If ListView1.ListItems(j).Selected Then Exit For
Next
If j Then
'Place full path in the long textbox
Text2.Text = _
FilePathName(mnuRecent(0).Caption, LVfilename(j))
Else
Text2.Text = ""
End If
CheckSelected = j
End Function
Private Function LVfilename$(ByVal num%)
With ListView1.ListItems(num)
LVfilename = Trim$(.Text) & "." & Trim$(.SubItems(1))
End With
End Function
'==========================================================
' Popup Menu Selections
'==========================================================
Private Sub mnuView_Click()
If InViewFlag Then
ViewOut
Else
ListView1_MouseUp 1, 0, 0, 0
End If
End Sub
' 5. How to move a file to the recycle bin.
' When delete is chosen - the file is moved
' to the recycle bin - Kill does not
Private Sub mnuDelete_Click()
Dim SHop As SHFILEOPSTRUCT
If InViewFlag Then ViewOut
If CheckSelected = 0 Then Exit Sub
With SHop
.wFunc = FO_DELETE
.pFrom = Text2.Text
.fFlags = FOF_ALLOWUNDO
End With
SHFileOperation SHop
KeyPressedElsewhere = True
If Dir$(Text2.Text) = "" Then _
FilesGet ListView1.SortOrder, currSortKey
End Sub
' 6. How to move a file to another directory with Name.
' Rename using an InputBox for dialog.
Private Sub mnuRename_Click()
Dim j%, tmp$
Dim startName$, newName$, startPath$, newPath$
If InViewFlag Then ViewOut
j = CheckSelected
If j = 0 Then Exit Sub
startName = Text2.Text
startPath = LCase$(Parse(startName, tmp, "\"))
KeyPressedElsewhere = True
newName = InputBox("Change the path to move the file.", _
"Rename File", startName)
newName = Trim$(newName)
If newName = "" Then Exit Sub
If newName = startName Then Exit Sub
newPath = LCase$(Parse(newName, tmp, "\"))
If Left$(startPath, 1) <> Left$(newPath, 1) Then
MsgBox "Can not move to another drive."
Exit Sub
End If
On Error GoTo r1
Name startName As newName
If startPath = newPath Then
With ListView1.ListItems(j)
.Text = Parse(tmp, tmp)
.SubItems(1) = tmp
End With
CheckSelected
Else
FilesGet ListView1.SortOrder, currSortKey
End If
GoTo r2
r1: MsgBox Error(Err), , "Rename Error!"
Resume r2
r2: On Error GoTo 0
End Sub
' 3. How to run another program from VB.
Private Sub mnuRun_Click()
ShellExec False
End Sub
' 4. How to launch a file's associated program from VB.
Private Sub mnuEdit_Click()
ShellExec True
End Sub
Private Sub ShellExec(EditFlag As Boolean)
Dim j%, sn$, sp$
j = CheckSelected
If j = 0 Then Exit Sub
If InViewFlag Then ViewOut
sn = Text2.Text
If EditFlag Then
'Interestingly most file types are edited with their
' associated programs that "open" them. These are
' some exceptions that are edited with notepad.
Select Case LCase$(ListView1.ListItems(j).SubItems(1))
Case "htm", "html", "bat", "css", ""
sp = sn
sn = "notepad.exe"
End Select
End If
ShellExecute hwnd, "open", sn, sp, mnuRecent(0).Caption, 1
End Sub
'13. How to make all controls on a PictureBox visible.
' The Picture1 serves as container for Labels, Dir1,
' Drive1 and Listview1. So when it is made visible
' all those controls are visible as well.
Private Sub ViewOut()
InViewFlag = False
Text1.Visible = False
Image1.Visible = False
mnuMain.Visible = True
mnuPicOpt.Visible = True
mnuEdit.Visible = True
Picture1.Visible = True
mnuView.Caption = "View"
Caption = FMCAPTION
ListView1.SetFocus
Text1.Text = ""
End Sub
'==========================================================
' Populate the ListView
'==========================================================
Private Sub FilesGet(so As ListSortOrderConstants, sk%)
Dim files%, filesize#, t$
ListView1.ListItems.Clear
' 8. How to find all files in a directory with Dir$.
t = Dir$(FilePathName(Dir1.Path, "*.*"))
' Get all the files in this loop
Do Until t = ""
files = files + 1
filesize = filesize + FileAdd(t)
t = Dir$
Loop
'The label with the directory bytes and num of files
t = CStr(files) & " file"
If files <> 1 Then t = t & "s"
Label2.Caption = Format$(filesize, F14) & " bytes " & t
'Sort the listview by file name
With ListView1
.SortOrder = so
.SortKey = sk - 1
If sk = SIZ Then ZerosPad
.Sorted = True
If sk = SIZ Then ZerosOut
If .ListItems.Count Then _
.ListItems(1).Selected = True
.SetFocus
End With
currSortKey = sk
'Checkselected will fill the long testbox
CheckSelected
End Sub
'This procedure does double duty by returning file size
Private Function FileAdd#(ByVal fn$)
Static fName$, fExt$, LI As ListItem
fName = Parse(fn, fExt)
' 9. How to populate a ListView.
Set LI = ListView1.ListItems.Add(, , fName)
fn = FilePathName(Dir1.Path, fn)
With LI
.SubItems(1) = fExt
.SubItems(3) = Format$(FileDateTime(fn), _
"yyyy.mm.dd hh:mm:ss")
FileAdd = fSize(fn)
.SubItems(2) = fn
End With
End Function
Private Function fSize#(fs$)
Static l&
l = FileLen(fs)
fs = Trim$(Format$(l, F11))
If fs = "" Then fs = "0"
fSize = CDbl(l)
End Function
'==========================================================
' General String Handling
'==========================================================
Private Function FilePathName$(ByVal filepath$, filename$)
FilePathName = AddSlash(filepath) & filename
End Function
Private Function AddSlash$(ByVal fp$)
If Right$(fp, 1) <> "\" Then fp = fp & "\"
AddSlash = fp
End Function
' Delim = "." Returns: fName ~ fx = fExtension
' Delim = "\" Returns: fPath ~ fx = fName.fExt
Private Function Parse$(ByVal fn$, fx$, _
Optional delim$ = ".")
Static j%, l%
fx = ""
l = Len(fn)
For j = l To 1 Step -1
If Mid$(fn, j, 1) = delim Then Exit For
Next
If j > 1 Then
If j < l Then fx = Right$(fn, l - j)
fn = Left$(fn, j - 1)
End If
Parse = fn
End Function
Private Sub ZerosPad()
Dim i%, j%, k%, s2$, s1$, t$
With ListView1
For i = 1 To .ListItems.Count
s1 = Trim$(.ListItems(i).SubItems(2))
k = 9
s2 = String$(k, "0")
For j = Len(s1) To 1 Step -1
t = Mid$(s1, j, 1)
If t <> "," Then
Mid$(s2, k, 1) = t
k = k - 1
End If
Next
.ListItems(i).SubItems(2) = s2
Next
End With
End Sub
Private Sub ZerosOut()
Dim j%, s$
For j = 1 To ListView1.ListItems.Count
With ListView1.ListItems(j)
s = Format$(.SubItems(2), "###,###,###")
If s = "" Then s = "0"
.SubItems(2) = s
End With
Next
End Sub
'==========================================================
' Initialization and Termination
'==========================================================
Private Sub Form_Load()
Dim f%, sl$
Caption = FMCAPTION
Text1.Visible = False
Text1.FontBold = True
Text2.FontBold = True
Image1.Stretch = True
Image1.Visible = False
Label1.FontBold = True
Label2.Alignment = vbRightJustify
Label2.FontBold = True
Dir1.FontBold = True
Drive1.FontBold = True
Picture1.BorderStyle = vbBSNone
ListView1.Font.Size = 10
ListView1.Font.Bold = True
mnuPicOpt.Caption = SHCAPTION
With ListView1.ColumnHeaders
.Add , , "Name"
.Add , , "Type"
.Add , , "Size ", 1420, lvwColumnRight
.Add , , "Date \ Time ", _
2300, lvwColumnRight
End With
'Defaults
FmWd = MINWD
FmHt = 6675
mnuRecent(lastDir).Caption = "C:\"
iniFile = FilePathName(App.Path, App.EXEName & ".ini")
'Get the INI info
On Error GoTo fl2
f = FreeFile
Open iniFile For Input As f
'Get the window position and size
Input #f, FmLt, FmTp, FmWd, FmHt
'Get the recent directories
Do Until EOF(f)
Input #f, sl
If Len(sl) > 1 Then
If lastDir Then Load mnuRecent(lastDir)
mnuRecent(lastDir).Caption = sl
mnuRecent(lastDir).Enabled = True
lastDir = lastDir + 1
End If
Loop
fl1: On Error GoTo 0
Close
'Sizing the form will initiate the resize event
Move FmLt, FmTp, FmWd, FmHt
Exit Sub
fl2: Resume fl1
End Sub
Private Sub Form_Resize()
Const UNIT! = 240, DirWdth! = 2645
Const UNITX2! = UNIT * 2, MINHT! = 3600
If WindowState = vbMinimized Then Exit Sub
If Width < MINWD Then Width = MINWD: Exit Sub
If Height < MINHT Then Height = MINHT: Exit Sub
FmLt = Left
FmTp = Top
FmWd = Width
FmHt = Height
Text1.Move 0, 0, ScaleWidth, ScaleHeight
Picture1.Move 0, ScaleTop, ScaleWidth, ScaleHeight
Dir1.Move 0, UNITX2, DirWdth, _
ScaleHeight - Drive1.Height - UNITX2
Drive1.Move 0, Dir1.Top + Dir1.Height, DirWdth
Label1.Move 100, UNIT, 1040, UNIT
Label2.Move ScaleWidth - 2700, UNIT, 2600, UNIT
Dim lt!
lt = Label1.Left + Label1.Width
Text2.Move lt, UNIT - 60, Label2.Left - lt, UNIT
'15. How to dynamically resize ListView Columns.
With ListView1
.Move DirWdth, UNITX2, ScaleWidth - DirWdth, _
ScaleHeight - UNITX2
'270 needed for scrollbar width
lt = .Width - 270 _
- .ColumnHeaders(SIZ).Width _
- .ColumnHeaders(DAT).Width
.ColumnHeaders(NAM).Width = lt * 0.7
.ColumnHeaders(EXT).Width = lt * 0.3
End With
End Sub
Private Sub Form_Activate()
mnuRecent_Click 0
End Sub
' 7. How to keep an INI file in the App.Path.
Private Sub Form_Unload(Cancel%)
Dim f%, j%
f = FreeFile
Open iniFile For Output As f
'Save the window position and size
If WindowState = vbMinimized Then
Write #f, FmLt, FmTp, FmWd, FmHt
Else
Write #f, Left, Top, Width, Height
End If
'Save the recent directories
For j = 0 To lastDir - 1
Write #f, mnuRecent(j).Caption
Next
Close
End Sub
|