I am new to VBA in excel and I ran into an error that I am unsure how to interpret. I was wondering if somebody could help. I am trying to create s table of contents for an excel file and I found a macro online. It is posted below:
Sub Create_TOC()
Dim wbBook As Workbook
Dim wsActive As Worksheet
Dim wsSheet As Worksheet
Dim lnRow As Long
Dim lnPages As Long
Dim lnCount As Long
Set wbBook = ActiveWorkbook
With Application
.DisplayAlerts = False
.ScreenUpdating = False
End With
'If the TOC sheet already exist delete it and add a new
'worksheet.
On Error Resume Next
With wbBook
.Worksheets(“TOC”).Delete
.Worksheets.Add Before:=.Worksheets(1)
End With
On Error GoTo 0
Set wsActive = wbBook.ActiveSheet
With wsActive
.Name = “TOC”
With .Range(“A1:B1”)
.Value = VBA.Array(“Table of Contents”, “Sheet # – # of Pages”)
.Font.Bold = True
End With
End With
lnRow = 2
lnCount = 1
‘Iterate through the worksheets in the workbook and create
‘sheetnames, add hyperlink and count & write the running number
‘of pages to be printed for each sheet on the TOC sheet.
For Each wsSheet In wbBook.Worksheets
If wsSheet.Name <> wsActive.Name Then
wsSheet.Activate
With wsActive
.Hyperlinks.Add .Cells(lnRow, 1), “”, _
SubAddress:=”‘” & wsSheet.Name & “‘!A1”, _
TextToDisplay:=wsSheet.Name
lnPages = wsSheet.PageSetup.Pages().Count
.Cells(lnRow, 2).Value = “‘” & lnCount & “ - ” & lnPages
End With
lnRow = lnRow + 1
lnCount = lnCount + 1
End If
Next wsSheet
wsActive.Activate
wsActive.Columns(“A:B”).EntireColumn.AutoFit
With Application
.DisplayAlerts = True
.ScreenUpdating = True
End With
End Sub
The error which I received was this:
Compile Error: Variable TOS not defined.
I am really new to this and I am unsure about what this means. Could somebody provide a detailed explanation on what the problem is and how to go about fixing it.
I believe the problem is in the quotation marks, there are angled/curly brackets being used and this is stopping the code being read properly.
Taking the first instance of the issue: -
.Worksheets(“TOC”).Delete
You receive the error:-
Compile Error:
Variable not defined
and “TOC” is highlighted. This is occurring because the wrong quotation marks are being so TOC is not being seen as a literal string but instead “TOC” is being presumed to be a variable, that is not defined (i.e. does not exist).
This can be fixed by going through your code and replacing all the below: -
Change “ (Angled open quotation) to " (straight quotation (shift+2)
Change ” (Angled close quotation) to " (straight quotation (shift+2)
Change ‘ (Angled apostrophe) to ' (straight single quotation (', shares the # key)
Related
Sometimes our workbooks at work get so overloaded with named ranges, which we don't even use, that the tool we normally use to remove names, or even the name manager, will no longer function. I did some digging around here and after finding this post: VBA Remove 100k + named ranges, I started using the below code:
Sub dlname()
Dim j As Long
For j = 20000 To 1 Step -1
If j <= ActiveWorkbook.Names.Count Then
ActiveWorkbook.Names(j).Delete
End If
Next j
ActiveWorkbook.Save
End Sub
For the most part this gets the job done (very slowly) however it periodically just stops working, and I'd prefer for this to be done on a loop until the job is done with the workbook being saved every time. If I use code that doesn't try and do the job in chunks then I just get a memory error so I'm pretty sure it needs to be done piece meal.
Sorry I am not a coder so I'm unsure how to update. Any help would be appreciated.
Thanks,
I don't see anything really "wrong" with your code - it could be tidied up a bit, but the essential process is the same:
'remove all names from activeworkbook
Sub RemoveNames()
With ActiveWorkbook.Names
Do While .Count > 0
.Item(1).Delete
Loop
End With
End Sub
'create a lot of names for testing...
Sub AddNames()
Dim i As Long
For i = 1 To 10000
ActiveWorkbook.Names.Add "Test_" & Format(i, "0000000"), ActiveSheet.Cells(i, 1)
Next i
End Sub
The process of deleting UNUSED names can be complicated. This is an example of searching through all the defined names in a workbook and deleting ONLY those NOT USED in a formula.
The bit at the top and bottom of the routine will greatly speed up the process...
Option Explicit
Sub DeleteAllUnusedNames()
'--- disable all interactions for SPEED
With Application
.EnableEvents = False
.DisplayAlerts = False
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Dim totalNames As Long
Dim namesDeleted As Long
Dim definedName As Variant
For Each definedName In ThisWorkbook.names
Dim nameIsUsed As Boolean
nameIsUsed = True
totalNames = totalNames + 1
Dim sheet As Worksheet
For Each sheet In ThisWorkbook.Sheets
If Not NameIsInFormula(definedName.name, sheet) Then
nameIsUsed = False
Exit For
End If
Next sheet
If Not nameIsUsed Then
namesDeleted = namesDeleted + 1
definedName.Delete
End If
Next definedName
Debug.Print totalNames & " names found, " & namesDeleted & " deleted"
'--- re-enable all interactions
With Application
.EnableEvents = True
.DisplayAlerts = True
.ScreenUpdating = True
.Calculation = xlCalculationAutomatic
End With
End Sub
Public Function NameIsInFormula(ByVal thisName As String, _
ByRef thisSheet As Worksheet) As Boolean
On Error Resume Next
Dim cellsWithFormulas As Range
Set cellsWithFormulas = thisSheet.Cells.SpecialCells(xlCellTypeFormulas)
If cellsWithFormulas Is Nothing Then
NameIsInFormula = False
Exit Function
End If
On Error GoTo 0
Dim cellsFound As Range
Set cellsFound = cellsWithFormulas.Find(What:=thisName, LookIn:=xlFormulas, _
LookAt:=xlPart, MatchCase:=False, _
SearchFormat:=False)
'--- optional if you want to see where it is...
' If Not cellsFound Is Nothing Then
' Debug.Print vbTab & thisName & " found in " & _
' thisSheet.name & "!" & cellsFound.Address
' End If
NameIsInFormula = (Not cellsFound Is Nothing)
End Function
The VBA code I have has worked perfectly on two other machines and with several other worksheets without the data reappearing. I've created a macro that takes a master spreadsheet and creates a new spreadsheet for each school listed in the table. I just got a new laptop and installed Excel 365 on it. I copied the VBA code to the new machine, but when I ran it, each new worksheet still contained the data for all the schools, not just the school for that particular file. I stepped through the code, and the schools did delete, but when it got to the part where the filter was removed from the table ws.ListObjects("Data").AutoFilter.ShowAllData, all the deleted rows reappeared. I'm stumped on why this is happening - It didn't happen on the other two machines and other iterations of the file that I've used this macro on. I don't know if it's an Excel setting or a setting on this particular master file. The other two machines - one used Excel 365, and the other Excel 2016. The data is not part of PowerPivot and is not a PowerQuery, so the data only lives in the table in the worksheet.
Here is the macro:
Dim i As Integer, wb As Workbook, schools() As Variant, schools_to_delete() As Variant
Dim ws As Worksheet, rng As Range, dt As String
schools = SchoolsInList()
dt = MonthName(Month(Now)) & " " & Year(Now)
Set wb = ActiveWorkbook
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.DisplayAlerts = False
For i = 1 To UBound(schools)
wb.SaveCopyAs ("Galileo " & dt & " " & schools(i) & ".xlsx")
Workbooks.Open ("Galileo " & dt & " " & schools(i) & ".xlsx")
Workbooks("Galileo " & dt & " " & schools(i) & ".xlsx").Activate
Set ws = Sheets("Data")
ws.Activate
schools_to_delete = schools
schools_to_delete(i) = "x"
Set rng = ws.ListObjects("Data").DataBodyRange
With ws
.AutoFilterMode = False
ws.ListObjects("Data").Range.AutoFilter Field:=18, Criteria1:= _
Array(schools_to_delete), Operator:=xlFilterValues
ws.Range(rng.Address).SpecialCells(xlCellTypeVisible).Delete
.AutoFilterMode = False
ws.ListObjects("Data").AutoFilter.ShowAllData
End With
ActiveWorkbook.RefreshAll
Call SelectA1
ActiveWorkbook.Save
ActiveWorkbook.Close
Next i
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.DisplayAlerts = True
End Sub
Function SchoolsInList() As Variant
Dim schools() As String
Dim C As Collection
Dim r As Range
Dim i As Long
Dim last_row As Long
last_row = Cells(Rows.Count, 1).End(xlUp).Row
Set C = New Collection
On Error Resume Next
For Each r In Worksheets("Data").Range("R2:R" & last_row).Cells
C.Add r.Value, CStr(r.Value)
Next
On Error GoTo 0
ReDim A(1 To C.Count)
For i = 1 To C.Count
A(i) = C.Item(i)
Next i
SchoolsInList = A
End Function
Sub SelectA1()
Dim i As Long
For i = 1 To ActiveWorkbook.Sheets.Count
Sheets(i).Activate
ActiveWindow.ScrollColumn = 1
ActiveWindow.ScrollRow = 1
Range("A1").Select
Next i
ActiveWorkbook.Worksheets(2).Activate
End Sub
I found the problem - the .AutoFilterMode = False didn't actually clear the filters that had already been placed on the table in question. The visible data WAS deleted, but the data that was filtered before the macro was run remained, and when the ws.ListObjects("Data").AutoFilter.ShowAllData ran, it cleared the previous filter, showing the rows that had been filtered before. I added the .ShowAllData code to the beginning of the With statement to avoid the same problem at a future date.
I have a really weird problem about VBA.
I tried to list circular references at activeworkbook and i have written below code for that. It only works if i press ALT+F11. So if VBA Editor window is open, code runs correctly but otherwise it is not working.
By the way, code is in a module at Addin and i call it from ribbon. You may see the code below.
Your help is highly appreciated. Bruteforce solution works. I hope someone can find decent solution than me.
Type SaveRangeCir
Val As Variant
Addr As String
Preaddress As String
Shtname As String
Workbname As String
End Type
Public OldCir() As SaveRangeCir
Sub DonguselBasvurulariBul(control As IRibbonControl)
Dim wba As Workbook
Dim ws As Worksheet
Dim wsa As Worksheet
Dim sht As Worksheet
Dim sht2 As Worksheet
Dim dummy As Worksheet
Dim Item As Range
Dim crcell As Range
Dim cll As Range
un = "Sayin " & Environ("UserName")
muyarcirc = MsgBox("Lutfen Oncelikle Dosyanizi Kaydedin" & vbNewLine & vbNewLine & _
"-->> Dosyanizi Kaydettiniz mi?", vbExclamation + vbYesNo, un)
If muyarcirc = vbno Then
muyar2 = MsgBox("Dongusel Basvuru Arama Islemi Iptal Edildi", vbInformation, un)
Exit Sub
End If
'BruteForce Solution
With Application
.DisplayAlerts = False
.ScreenUpdating = False
.EnableEvents = False
.VBE.MainWindow.Visible = True
.Wait Now + TimeValue("00:00:01")
.VBE.MainWindow.Visible = False
End With
On Error Resume Next
Set wba = ActiveWorkbook
Set wsa = wba.ActiveSheet
wba.Worksheets.Add
Set dummy = ActiveSheet
For Each sht2 In wba.Sheets
If sht2.Name = "Dongusel Basvurular" Then
sht2.Delete
End If
Next sht2
wba.Worksheets.Add
Set ws = wba.ActiveSheet
dummy.Delete
With ws
.Name = "Dongusel Basvurular"
.Range("A1") = "Dongusel Basvuru Hucresi"
.Range("B1") = "Dongusel Basvuru Hucresi Formul Degeri"
.Range("C1") = "Bagli Oldugu Alan"
.Range("D1") = "Bulundugu Sayfa"
.Range("E1") = "Bulundugu Dosya"
End With
With wba
For Each sht In .Worksheets
If sht.CodeName <> ws.CodeName Then
sht.Activate
crcell = Nothing
Do
Set crcell = sht.CircularReference
If Not crcell Is Nothing Then
ReDim Preserve OldCir(1 To crcell.Precedents.Cells.Count)
i = 0
For Each cll In crcell.Precedents
i = i + 1
OldCir(i).Addr = cll.Address
OldCir(i).Val = cll.Formula
OldCir(i).Preaddress = cll.Precedents.Address
OldCir(i).Shtname = cll.Parent.Name
OldCir(i).Workbname = cll.Parent.Parent.Name
cll.Value = cll.Value
Next cll
For j = LBound(OldCir) To UBound(OldCir)
lr = ws.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
ws.Cells(lr, 1) = OldCir(j).Addr
ws.Cells(lr, 2) = "'" & OldCir(j).Val
ws.Cells(lr, 3) = OldCir(j).Preaddress
ws.Cells(lr, 4) = OldCir(j).Shtname
ws.Cells(lr, 5) = OldCir(j).Workbname
ws.Hyperlinks.Add Anchor:=ws.Cells(lr, 1), Address:="", SubAddress:=ws.Cells(lr, 4) & "!" & ws.Cells(lr, 1), _
ScreenTip:="Dongusel Basvuru Hucresini Gormek icin Tiklayiniz"
Next j
Else
GoTo skipsheet
End If
Erase OldCir
Set crcell = sht.CircularReference
Loop While crcell.Cells.Count > 0
lr2 = ws.Cells(Rows.Count, 1).End(xlUp).Row
For m = 2 To lr2
If ActiveSheet.Name <> ws.Cells(lr2, "D") Then
wba.Sheets(ws.Cells(m, "D")).Activate
End If
Range(ws.Cells(m, 1)).Formula = "=" & Right(ws.Cells(m, 2), Len(ws.Cells(m, 2)) - 1)
Next m
End If
skipsheet:
Next sht
If ws.Range("A2") = "" Then
ws.Delete
wsa.Activate
m1 = MsgBox("Aktif Dosyada Dongusel Basvuru Bulunamadi", vbInformation, "Sayin " & Environ("UserName"))
Else
ws.Activate
ws.Range("A1:E1").EntireColumn.AutoFit
End If
End With
Erase OldCir
Set crcell = Nothing
With Application
.DisplayAlerts = True
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
I ran into a similar problem using VBA in MS Access. I understand you are using VBA Excel but I thought I'd post my personal experience in case it helps.
I have an Access form with a button that opens another form. The button is coded with VBA. If the VBA Editor was not open when I clicked the button then the new form would open but Form_Load() wouldn't trigger. If the VBA editor was open when I clicked the button then Form_Load() triggered as intended.
I did not have On Error Resume Next hiding any errors and all my variables were set with Option Explicit.
To troubleshoot the issue, I added a number of msgboxes throughout the code to narrow down where the problem was occurring. After adding a msgbox to the Click() event of the button I realized that the connection was somehow re-established and the code no longer needed the VBA editor open. After realizing this, I deleted the msgbox from the code, closed the application, re-opened the application without the VBA editor and from then on the VBA executed as intended.
Unfortunately, I came upon a solution while troubleshooting so I cannot provide an explanation as to why this worked but sometimes an explanation is not needed as long as you get it working again!
Hope this helps.
I had the same problem
However, it appeared have been caused by first using a message box with no return variable, then extending it to include a return, ie ret = msgbox(
Deleted the message box, code worked, closed and saved the project, reopened and message box with return variable added and now it run even without the editor open.
I am creating a few macros to do the following in Excel 2010:
1. Upon creating a new worksheet ask for what the user wants to name his/her worksheet and sets the new worksheet to the name provided; calls Sort_Active_Book and Rebuild_TOC in order
2. Sort_Active_Book: Asks the user if he/she wants to sort the workbook's worksheets in ascending/descending order and proceeds to do so.
3. Rebuild_TOC: Deletes the Table of Contents page and rebuilds it based on all the worksheets in the workbook minus the TOC itself.
My problem is Excel keeps asking me to input the name of the new worksheet to be created and does not progress any further in the code. I notice it manages to create the named worksheet and asks me if I would like to sort ascending or descending but then proceeds to ask me again the name of the new worksheet. Could anyone please point out how to fix this and provide a code fix (if possible) please?
What I have already
This code portion is from ThisWorkbook, this is what prompts the user for the name of the worksheet upon creation.
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Dim sName As String
Dim bValidName As Boolean
Dim i As Long
bValidName = False
Do While bValidName = False
sName = InputBox("Please name this new worksheet:", "New Sheet Name", Sh.Name)
If Len(sName) > 0 Then
For i = 1 To 7
sName = Replace(sName, Mid(":\/?*[]", i, 1), " ")
Next i
sName = Trim(Left(WorksheetFunction.Trim(sName), 31))
If Not Evaluate("ISREF('" & sName & "'!A1)") Then bValidName = True
End If
Loop
Sh.Name = sName
Call Sort_Active_Book
Call Rebuild_TOC
End Sub
These two macros are in "Module 1":
Sub Sort_Active_Book()
Dim TotalSheets As Integer
Dim p As Integer
Dim iAnswer As VbMsgBoxResult
' Move the TOC to the begining of the document.
Sheets("TOC").Move Before:=Sheets(1)
' Prompt the user as to which direction they wish to
' sort the worksheets.
iAnswer = MsgBox("Sort Sheets in Ascending Order?" & Chr(10) & "Clicking No will sort in Descending Order", vbYesNoCancel + vbQuestion + vbDefaultButton1, "Sort Worksheets")
For TotalSheets = 1 To Sheets.Count
For p = 2 To Sheets.Count - 1
' If the answer is Yes, then sort in ascending order.
If iAnswer = vbYes Then
If UCase$(Sheets(p).Name) = "TOC" Then
Sheets(p).Move Before:=Sheets(1)
ElseIf UCase$(Sheets(p).Name) > UCase$(Sheets(p + 1).Name) Then
Sheets(p).Move After:=Sheets(p + 1)
End If
' If the answer is No, then sort in descending order.
ElseIf iAnswer = vbNo Then
If UCase$(Sheets(p).Name) = "TOC" Then
Sheets(p).Move Before:=Sheets(1)
ElseIf UCase$(Sheets(p).Name) < UCase$(Sheets(p + 1).Name) Then
Sheets(p).Move After:=Sheets(p + 1)
End If
End If
Next p
Next TotalSheets
End Sub
and
Sub Rebuild_TOC()
Dim wbBook As Workbook
Dim wsActive As Worksheet
Dim wsSheet As Worksheet
Dim lnRow As Long
Dim lnPages As Long
Dim lnCount As Long
Set wbBook = ActiveWorkbook
With Application
.DisplayAlerts = False
.ScreenUpdating = False
End With
' If the TOC sheet already exist delete it and add a new worksheet.
On Error Resume Next
With wbBook
.Worksheets(“TOC”).Delete
.Worksheets.Add Before:=.Worksheets(1)
End With
On Error GoTo 0
Set wsActive = wbBook.ActiveSheet
With wsActive
.Name = “TOC”
With .Range(“A1:B1”)
.Value = VBA.Array(“Table of Contents”, “Sheet # – # of Pages”)
.Font.Bold = True
End With
End With
lnRow = 2
lnCount = 1
' Iterate through the worksheets in the workbook and create sheetnames, add hyperlink
' and count & write the running number of pages to be printed for each sheet on the TOC.
For Each wsSheet In wbBook.Worksheets
If wsSheet.Name <> wsActive.Name Then
wsSheet.Activate
With wsActive
.Hyperlinks.Add .Cells(lnRow, 1), “”, _
SubAddress:=”‘” & wsSheet.Name & “‘!A1”, _
TextToDisplay:=wsSheet.Name
lnPages = wsSheet.PageSetup.Pages().Count
.Cells(lnRow, 2).Value = “‘” & lnCount & “-” & lnPages
End With
lnRow = lnRow + 1
lnCount = lnCount + 1
End If
Next wsSheet
wsActive.Activate
wsActive.Columns(“A:B”).EntireColumn.AutoFit
With Application
.DisplayAlerts = True
.ScreenUpdating = True
End With
End Sub
You are creating a new sheet with sub Rebuild_TOC. Causing the newsheet macro to run again.
You will need to avoid running the newsheet macro by adding a enableevents = false and true surrounding your code when creating a new sheet for your TOC. The rest of your code appears to be working as you want it to.
Application.EnableEvents = False
With wbBook
.Worksheets("TOC").Delete
.Worksheets.Add Before:=.Worksheets(1)
End With
Application.EnableEvents = True
Why would you want to delete the TOC worksheet, why not just update it?
Is there an alternative to using ActiveWorkbook and ActiveSheet in VBA when working with multiple workbooks (copying from workbooks in a list to a master sheet) ? It is turning out to be more confusing than anything to know which workbook is open when working with multiple functions which need to use different workbooks. Is it a matter of code organization ?
For the moment I think I can manage by storing the activeworkbook's name at the beginning of every function and restoring it, but it seems like a lot of work and probably a lot of processing time for not much results.
Ideas ?
You might be interested in this page http://www.techrepublic.com/blog/10things/10-ways-to-reference-excel-workbooks-and-sheets-using-vba/967
Specifically look at 4: Explicitly reference a workbook
Or 10: Refer to a sheet’s code name property
Typically when you work through a list you will use a workbook variable to open, manipulate and then close each book
My code below is an example of work through and collate a directory of workbooks (similar to your list example). From Collating worksheets from one or more workbooks into a summary file
Public Sub ConsolidateSheets()
Dim Wb1 As Workbook
Dim Wb2 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim rng1 As Range
Dim rng2 As Range
Dim rng3 As Range
Dim rngArea As Range
Dim lrowSpace As Long
Dim lSht As Long
Dim lngCalc As Long
Dim lngRow As Long
Dim lngCol As Long
Dim X()
Dim bProcessFolder As Boolean
Dim bNewSheet As Boolean
Dim StrPrefix
Dim strFileName As String
Dim strFolderName As String
'variant declaration needed for the Shell object to use a default directory
Dim strDefaultFolder As Variant
bProcessFolder = (MsgBox("Process a single folder (Yes)," & vbNewLine & "or single file (No)", vbYesNo, "Application Scope: Folder or single File") = vbYes)
bNewSheet = (MsgBox("Extract all data to a single sheet (Yes)," & vbNewLine & "or a target file sheet for each source sheet (No)", vbYesNo, "Output Format: Single sheet or sheet by sheet collection") = vbYes)
If Not bProcessFolder Then
If Not bNewSheet Then
MsgBox "There isn't much point creating a exact replica of your source file :)"
Exit Sub
End If
End If
'set default directory here if needed
strDefaultFolder = "C:\temp"
'If the user is collating all the sheets to a single target sheet then the row spacing
'to distinguish between different sheets can be set here
lrowSpace = 1
If bProcessFolder Then
strFolderName = BrowseForFolder(strDefaultFolder)
'Look for xls, xlsx, xlsm files
strFileName = Dir(strFolderName & "\*.xls*")
Else
strFileName = Application _
.GetOpenFilename("Select file to process (*.xls*), *.xls*")
End If
Set Wb1 = Workbooks.Add(1)
Set ws1 = Wb1.Sheets(1)
If Not bNewSheet Then ws1.Range("A1:B1") = Array("workbook name", "worksheet count")
'Turn off screenupdating, events, alerts and set calculation to manual
With Application
.DisplayAlerts = False
.EnableEvents = False
.ScreenUpdating = False
lngCalc = .Calculation
.Calculation = xlCalculationManual
End With
'set path outside the loop
StrPrefix = strFolderName & IIf(bProcessFolder, "\", vbNullString)
Do While Len(strFileName) > 0
'Provide progress status to user
Application.StatusBar = Left("Processing " & strFolderName & "\" & strFileName, 255)
'Open each workbook in the folder of interest
Set Wb2 = Workbooks.Open(StrPrefix & strFileName)
If Not bNewSheet Then
'add summary details to first sheet
ws1.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0) = Wb2.Name
ws1.Cells(Rows.Count, "A").End(xlUp).Offset(0, 1) = Wb2.Sheets.Count
End If
For Each ws2 In Wb2.Sheets
If bNewSheet Then
'All data to a single sheet
'Skip importing target sheet data if the source sheet is blank
Set rng2 = ws2.Cells.Find("*", ws2.[a1], xlValues, , xlByRows, xlPrevious)
If Not rng2 Is Nothing Then
Set rng1 = ws1.Cells.Find("*", ws1.[a1], xlValues, , xlByRows, xlPrevious)
'Find the first blank row on the target sheet
If Not rng1 Is Nothing Then
Set rng3 = ws2.Range(ws2.UsedRange.Cells(1), ws2.Cells(rng2.Row, "A"))
'Ensure that the row area in the target sheet won't be exceeded
If rng3.Rows.Count + rng1.Row < Rows.Count Then
'Copy the data from the used range of each source sheet to the first blank row
'of the target sheet, using the starting column address from the source sheet being copied
ws2.UsedRange.Copy ws1.Cells(rng1.Row + 1 + lrowSpace, ws2.UsedRange.Cells(1).Column)
Else
MsgBox "Summary sheet size exceeded. Process stopped on " & vbNewLine & _
"sheet: " & ws2.Name & vbNewLine & "of" & vbNewLine & "workbook: " & Wb2.Name
Wb2.Close False
Exit Do
End If
'colour the first of any spacer rows
If lrowSpace <> 0 Then ws1.Rows(rng1.Row + 1).Interior.Color = vbGreen
Else
'target sheet is empty so copy to first row
ws2.UsedRange.Copy ws1.Cells(1, ws2.UsedRange.Cells(1).Column)
End If
End If
Else
'new target sheet for each source sheet
ws2.Copy after:=Wb1.Sheets(Wb1.Sheets.Count)
'Remove any links in our target sheet
With Wb1.Sheets(Wb1.Sheets.Count).Cells
.Copy
.PasteSpecial xlPasteValues
End With
On Error Resume Next
Wb1.Sheets(Wb1.Sheets.Count).Name = ws2.Name
'sheet name already exists in target workbook
If Err.Number <> 0 Then
'Add a number to the sheet name till a unique name is derived
Do
lSht = lSht + 1
Set ws3 = Wb1.Sheets(ws2.Name & " " & lSht)
Loop While Not ws3 Is Nothing
lSht = 0
End If
On Error GoTo 0
End If
Next ws2
'Close the opened workbook
Wb2.Close False
'Check whether to force a DO loop exit if processing a single file
If bProcessFolder = False Then Exit Do
strFileName = Dir
Loop
'Remove any links if the user has used a target sheet
If bNewSheet Then
With ws1.UsedRange
.Copy
.Cells(1).PasteSpecial xlPasteValues
.Cells(1).Activate
End With
Else
'Format the summary sheet if the user has created separate target sheets
ws1.Activate
ws1.Range("A1:B1").Font.Bold = True
ws1.Columns.AutoFit
End If
With Application
.CutCopyMode = False
.DisplayAlerts = True
.EnableEvents = True
.ScreenUpdating = True
.Calculation = lngCalc
.StatusBar = vbNullString
End With
End Sub
Function BrowseForFolder(Optional OpenAt As Variant) As Variant
'From Ken Puls as used in his vbaexpress.com article
'http://www.vbaexpress.com/kb/getarticle.php?kb_id=284
Dim ShellApp As Object
'Create a file browser window at the default folder
Set ShellApp = CreateObject("Shell.Application"). _
BrowseForFolder(0, "Please choose a folder", 0, OpenAt)
'Set the folder to that selected. (On error in case cancelled)
On Error Resume Next
BrowseForFolder = ShellApp.self.Path
On Error GoTo 0
'Destroy the Shell Application
Set ShellApp = Nothing
'Check for invalid or non-entries and send to the Invalid error
'handler if found
'Valid selections can begin L: (where L is a letter) or
'\\ (as in \\servername\sharename. All others are invalid
Select Case Mid(BrowseForFolder, 2, 1)
Case Is = ":"
If Left(BrowseForFolder, 1) = ":" Then GoTo Invalid
Case Is = "\"
If Not Left(BrowseForFolder, 1) = "\" Then GoTo Invalid
Case Else
GoTo Invalid
End Select
Exit Function
Invalid:
'If it was determined that the selection was invalid, set to False
BrowseForFolder = False
End Function