我们需要运行VBA程序来更新500多个工作簿(删除和更改每个工作簿中的工作表)。
下面的VBA程序对所有工作簿进行递归遍历。
问题
在执行50、200或有时400的任何操作后,宏停止。没有错误。它只是在屏幕上留下一个打开的工作簿。它总是一本不同的工作簿,并且常常会处理犯罪者,因此它似乎与内容无关。
我认为可能是
GetFilesRecursive fso.GetFolder(directory), "xlsx", files, fso
由于使用SAVE更新工作簿而感到困惑。但是我也尝试过将通过SAVAS的输出放在单独的文件夹树中,这不会影响任何事情。
有人知道如何调试这种问题吗?
Const ProgDir = "D:\Staffing\SkillsUpdate\ProgramOfficeData"
Sub allPrograms(directory As String)
Dim fso As New Scripting.FileSystemObject
Dim files As New Collection
Dim file As Scripting.file
Dim result As Boolean
Dim index As Integer
clearErrors
GetFilesRecursive fso.GetFolder(directory), "xlsx", files, fso
index = 1
For Each file In files
If file Is Nothing Then
' Do nothing
Else
result = oneProgram(file.ParentFolder.path, file.Name)
Application.StatusBar = "Processing " & index & " of " & files.count
If (result) Then
index = index + 1
End If
End If
' logError "allPrograms(): processed:", 0, directory & "\" & file
Next file
Application.ThisWorkbook.Activate
Worksheets("Main").Cells(4, 3).Value = "Last Update: " + Format(Now(), "General Date")
End Sub
Function oneProgram(directory As String, fileName As String) As Boolean
Dim wbk As Workbook
Dim filePath As String
Dim result As Boolean
filePath = directory & "\" & fileName
Set wbk = safeOpen(filePath, result)
If (Not result) Then
oneProgram = False
Exit Function
End If
killSkillNames wbk
clearProgSkills wbk
copyDropList wbk
copySkillsList wbk
addSkillNames wbk
addWinPercent wbk
hideProgSheets wbk
wbk.Close SaveChanges:=True
oneProgram = True
End Function
Sub hideProgSheets(wbk As Workbook)
wbk.Worksheets("SkillsList").Visible = False
wbk.Worksheets("DropLists").Visible = False
End Sub
Sub copyDropList(wbk As Workbook)
Dim source As Worksheet
Dim target As range
Dim dest As Worksheet
Set source = Application.ThisWorkbook.Worksheets("DropLists")
Set dest = wbk.Sheets("DropLists")
wbk.Names("YesNoList").Delete
Set target = wbk.Worksheets("StaffRequest").range("J3:K3")
target.Validation.Delete 'delete previous validation
Application.DisplayAlerts = False
dest.Delete
Application.DisplayAlerts = True
source.Copy wbk.Sheets(Sheets.count)
wbk.Names.Add Name:="YesNoList", RefersTo:=wbk.Sheets("DropLists").range("A1:A2")
End Sub
Sub addWinPercent(wbk As Workbook)
Dim target As range
wbk.Names.Add Name:="WinPercent", RefersTo:=wbk.Sheets("DropLists").range("B1:B5")
Set target = wbk.Worksheets("StaffRequest").range("J3:K3")
With target.Validation
.Add Type:=xlValidateList, _
Operator:=xlBetween, _
AlertStyle:=xlValidAlertStop, _
Formula1:="=WinPercent"
End With
End Sub
Sub clearProgSkills(wbk As Workbook)
Dim target As range
Set target = wbk.Worksheets("StaffRequest").range("H10:J100")
For Each cell In target
If (cell.Value <> "") And (cell.Value <> "Total") Then
cell.Value = "No Skill"
End If
Next cell
End Sub
Sub RUNME_PROGRAMS()
allPrograms (ProgDir)
End Sub
Sub GetFilesRecursive(f As Scripting.Folder, filter As String, c As Collection, fso As Scripting.FileSystemObject)
Dim sf As Scripting.Folder
Dim file As Scripting.file
For Each file In f.files
If InStr(1, fso.GetExtensionName(file.Name), filter, vbTextCompare) = 1 Then
c.Add file, file.path
End If
Next file
For Each sf In f.SubFolders
GetFilesRecursive sf, filter, c, fso
Next sf
End Sub
Function safeOpen(filePath As String, result As Boolean) As Workbook
result = True
Dim book As Workbook
Dim lockTest As Boolean
Dim errCode As Integer
Dim errText As String
lockTest = IsWorkBookOpen(filePath, errCode, errText)
If (lockTest) Then
logError "safeOpen: Open Problem with: " & filePath, errCode, errText
result = False
Exit Function
End If
On Error Resume Next ' turn off error trapping
Set book = Workbooks.Open(fileName:=filePath, ReadOnly:=False, UpdateLinks:=False)
On Error GoTo 0 ' turn on error trapping
If book Is Nothing Then
logError "safeOpen: cannot Open File: " & filePath, errCode, errText
result = False
End If
Set safeOpen = book
End Function
Function safeCellRead(rng As range) As Double
If (IsNumeric(rng.Value)) Then
safeCellRead = CDbl(rng.Value)
Else
safeCellRead = 0
End If
End Function
Function IsWorkBookOpen(strFileName As String, errCode As Integer, errText As String) As Boolean
On Error Resume Next
' If the file is already opened by another process,
' and the specified type of access is not allowed,
' the Open operation fails and an error occurs.
Open strFileName For Binary Access Read Write Lock Read Write As #1
Close #1
errCode = Err.Number
errText = Err.description
'If no error, file is not open.
If Err.Number = 0 Then
IsWorkBookOpen = False
End If
'Error #70 is another user has the file open in edit mode.
If Err.Number = 70 Then
IsWorkBookOpen = True
End If
'Error #75 is another user has the file open in read only mode.
If Err.Number = 75 Then
IsWorkBookOpen = False
End If
On Error GoTo 0 ' turn on error trapping
End Function
Sub copySkillsList(wbk As Workbook)
Dim source As Worksheet
Dim dest As Worksheet
Set source = Application.ThisWorkbook.Worksheets("SkillsList")
Set dest = wbk.Sheets("SkillsList")
dest.Unprotect Password:="****"
Application.DisplayAlerts = False
dest.Delete
Application.DisplayAlerts = True
source.Copy wbk.Sheets(Sheets.count)
End Sub
Sub killSkillNames(wkb As Workbook)
Dim skills As Worksheet
Dim range As range
Dim tag As String
Dim cell As range
Set skills = wkb.Worksheets("SkillsList")
Set range = skills.range("A1:AZ1")
For Each cell In range
If cell <> "" Then
tag = cell.Value
wkb.Names(tag).Delete
End If
Next cell
End Sub
Sub addSkillNames(wkb As Workbook)
Dim skills As Worksheet
Dim values As range
Dim top As range
Dim bottom As range
Dim tag As String
Dim cell As range
Set skills = wkb.Worksheets("SkillsList")
Set headers = skills.range("A1:AZ1")
For Each cell In headers
If cell <> "" Then
tag = cell.Value
Set top = cell.Offset(1, 0)
Set bottom = top.End(xlDown)
Set values = range(top, bottom)
wkb.Names.Add Name:=tag, RefersTo:=values
End If
Next cell
End Sub
Sub clearErrors()
Dim eSheet As Worksheet
Set eSheet = Worksheets("ErrorLog")
eSheet.range("A2:E4000").Clear
eSheet.range("A1").Value = 1
Application.DisplayStatusBar = True
Application.StatusBar = ""
End Sub
Sub logError(errText As String, errNum As Integer, errDescription As String)
Dim eSheet As Worksheet
Dim eCount As Integer
Set eSheet = ThisWorkbook.Worksheets("ErrorLog")
eCount = CInt(eSheet.range("A1"))
eCount = eCount + 1
eSheet.Cells(eCount, 2).Value = errNum
eSheet.Cells(eCount, 3).Value = errText
eSheet.Cells(eCount, 4).Value = errDescription
Application.StatusBar = "ERROR: " & eText
eSheet.range("A1").Value = eCount
End Sub