vArray values not clearing out from previous loop in VBA - excel

I have some vArrays which are not clearing out. The purspose of the macro is to work on a raw data tab which has 30+ tabs, each tab holding information for a specific office, 001-New York, etc. The macro is supposed to select x number of tabs (based on a reference file), copy them and save them into a new workbook. The problem is that instead of copying and saving from the raw data file it save the reference file instead. A For...Next loop is used to determine which tabs/offices to select & copy from the raw data file. The varrays are inside the loop and contain the names of the offices. When the code encounters the vArray the varray values are not clearing out when the loop circles back around.
Example:
'For 1' reference a cell with value of "8" so it populates 8 different vArray values (offices in this case). 'For 2' has a reference number of 5 and is supposed to populate 5 vArray values. It does this correctly as I can see the 5 new values in the locals window under vArray (1) thru vArray (5), however, vArray 6 thru 8 are showing values of the previous loop instead of 'Empty'. The vArray values are not clearing out when the macro loops.
sMasterListWBName is the reference file which tells the macro which tabs to copy from the raw data file and where to move the newly created workbook. The sub is also copying, saving, and distributing the reference file instead of the raw data file for some iterations of the loop (secondary issue--I will try to refrain from splitting the thread topic).
Thanks in advance to anyone who tries to answer this question.
Option Explicit
Dim iYear As Integer, iMonth As Integer, iVer As Integer, icount As Integer, iCount2 As Integer
Dim iLetter As String, iReport As String
Dim sMonth As String, sDate As String, sVer As String, sAnswer As String
Dim sFolderName As String, sManagerInitials As String
Dim iManagerNumber As Integer, iManagerStart As Integer, iTabNumber As Integer, iTabStart As Integer
Dim sMasterListWBName As String, sConsolidatedWBName As String, sExists As String
Dim oSheet As Object, oDistList As Object
Dim vArray(300) As Variant
Dim wbDistList As Workbook
Dim wsAgentListSheet As Worksheet, wsMain As Worksheet
Dim rCell As Range, rCell2 As Range, rCellTotal As Range
Public sFINorAgent As String
Sub Agent_Distribute()
On Error Resume Next
iYear = frm_fin_rep_main_distribute.txt_year
iMonth = frm_fin_rep_main_distribute.txt_month
iVer = frm_fin_rep_main_distribute.txt_version
sMonth = Right("0" & iMonth, 2)
sDate = iYear & "." & sMonth
sVer = "V" & iVer
sAnswer = MsgBox("Is the following information correct?" & vbNewLine & vbNewLine & _
"Report - " & frm_fin_rep_main.sLetter & vbNewLine & _
"Year - " & iYear & vbNewLine & _
"Month - " & sMonth & vbNewLine & _
"Name - " & frm_fin_rep_main.sReport & vbNewLine & _
"Version - " & sVer, vbYesNo + vbInformation, "Please verify...")
If sAnswer <> vbYes Then
Exit Sub
End If
Unload frm_fin_rep_main_distribute
frm_agent.Hide
Form_Progress
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
sConsolidatedWBName = ActiveWorkbook.Name
sMasterListWBName = "Dist Master List Final.xls"
If Not IsFileOpen(sMasterListWBName) Then
Workbooks.Open FileName:= _
"W:\Addins\01 GL - Distribution\" & sMasterListWBName, Password:="password"
Workbooks(sConsolidatedWBName).Activate
End If
Set oDistList = Workbooks(sMasterListWBName).Worksheets("Agent")
With oDistList
iManagerNumber = .Range("ManNumber2") 'range value = 66
For iManagerStart = 2 To iManagerNumber '2 to 66
If .Range("A" & iManagerStart) = "x" Then
iTabNumber = .Range("E" & iManagerStart) 'E2 to E66
sFolderName = .Range("F" & iManagerStart) 'F2 to F66
sManagerInitials = .Range("G" & iManagerStart) 'G2 to G66
For iTabStart = 1 To iTabNumber
vArray(iTabStart) = .Range("G" & iManagerStart).Offset(0, iTabStart)
Next iTabStart
If iTabNumber = 1 Then
Sheets(vArray(1)).Select
Else
Sheets(vArray(1)).Select
For iTabStart = 2 To iTabNumber
Sheets(vArray(iTabStart)).Select False
Next iTabStart
End If
ActiveWindow.SelectedSheets.Copy
' *** the following code is optional, remove preceding apostrophes from the following four lines to enable password protection ***
'For Each oSheet In ActiveWorkbook.Sheets
'oSheet.Protect "password"
'oSheet.EnableSelection = xlNoSelection
'Next
ActiveWorkbook.SaveAs FileName:= _
"W:\Financials\" & iYear & "\" & sDate & "\Report to Distribute Electronically\Department Reports\" _
& sFolderName & "\Current Year Financials" & "\" & "Y" & ") " & iYear & "-" & sMonth & " Agent Report Card " & sVer & " - " & sManagerInitials & ".xls"
ActiveWorkbook.Close
End If
iPercent = iManagerStart / iManagerNumber * 95
Task_Progress (iPercent)
Next iManagerStart
End With
Workbooks(sMasterListWBName).Close False
Task_Progress (100)
Unload frm_progress
Set oDistList = Nothing
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
Message_Done
frm_agent.Show (vbModeless)
End Sub

I fixed it. I just added "Workbooks(sWbName).activate" at the end of the loop to make sure the focus is back on the raw data file. Now all files are saving in the correct format and location. Case closed unless someone has anything else to add. Maybe someone knows the reason the macro was losing sight of its active sheet (saving reference file instead of raw data file). Thank you.

Related

How to stop at an empty cell while merging PDFs using Excel VBA and Adobe Acrobat library

First of all I'd like to preface this by saying that I have less than a week's experience using VBA.
I have been trying to create a script that merges PDFs that are linked in an Excel sheet. The code that I have works fine, however, when I add multiple tables separated by empty rows, the script will continue to move down through the empty cells and collect the PDFs from the next table as well.
So if I select the bottom table to merge, it will work fine, but if I select the top one, it will merge all the linked PDFs for ALL the tables moving down.
Here is a screenshot of the Excel sheet I have at the moment:
Excel Sheet
What I would like is for the script to stop at the first empty cell it encounters while moving down column D, rather than continuing until the last populated cell. Meaning that the script will only merge one table of PDFs.
As I said, this is my first week using any VBA, so I have been struggling to get the range for the PDF merging to end when it encounters the empty cell.
Any help would be greatly appreciated!
Sub Button9_Click()
'References
'Adobe Acrobat 10.0 Type Library
Dim objCAcroPDDocDestination As Acrobat.CAcroPDDoc
Dim objCAcroPDDocSource As Acrobat.CAcroPDDoc
Dim PDFfiles As Range, PDFfile As Range
Dim n As Long
Dim em As String
'Set start point of cell range
'Takes ActiveCell from search results and offsets to filepaths
'CURRENTLY LOOKS FOR LAST POPULATED CELL IN COLUMN, DISREGARDING PREVIOUS EMPTY CELLS
With ActiveSheet
Set PDFfiles = .Range(ActiveCell.Offset(3, 1), .Cells(.Rows.Count, "D").End(xlUp))
End With
'Create Acrobat API objects
Set objCAcroPDDocDestination = CreateObject("AcroExch.PDDoc")
Set objCAcroPDDocSource = CreateObject("AcroExch.PDDoc")
'Open first PDF file and merge other PDF files into it
n = 0
For Each PDFfile In PDFfiles
n = n + 1
If n = 1 Then
objCAcroPDDocDestination.Open PDFfile.Value
Else
objCAcroPDDocSource.Open PDFfile.Value
If Not objCAcroPDDocDestination.InsertPages(objCAcroPDDocDestination.GetNumPages - 1, objCAcroPDDocSource, 0, objCAcroPDDocSource.GetNumPages, 0) Then
MsgBox "Error merging" & PDFfile.Value
End If
objCAcroPDDocSource.Close
End If
Next
'Save merged PDF files as a new file
objCAcroPDDocDestination.Save 1, "C:\Users\USER\OneDrive\TEST MERGE\Output\" & Sheets("SEARCH").Range("E6").Value & ".pdf"
objCAcroPDDocDestination.Close
Set objCAcroPDDocSource = Nothing
Set objCAcroPDDocDestination = Nothing
'Opens dialogue box for successful/failed merge
MsgBox "Created New PDF (" & Sheets("SEARCH").Range("E6").Value & ")" & vbCrLf & vbCrLf & "File Path: C:\Users\USER\OneDrive\TEST MERGE\Output\" & Sheets("SEARCH").Range("E6").Value & ".pdf"
'Opens merged PDF
ActiveWorkbook.FollowHyperlink "C:\Users\USER\OneDrive\TEST MERGE\Output\" & Sheets("SEARCH").Range("E6").Value & ".pdf"
End Sub
Try the next code, please:
Sub MergePDFDocuments()
'References to 'Adobe Acrobat 10.0 Type Library
Dim objCAcroPDDocDestination As Acrobat.CAcroPDDoc, objCAcroPDDocSource As Acrobat.CAcroPDDoc, i As Long
Dim PDFfiles As Range, PDFfile As Range, n As Long, em As String, processArr As String, prRng As Range
Dim sh As Worksheet, startRow As Long, endRow As Long
Set sh = ActiveSheet 'use here your sheet
processArr = "A" 'the group files to be processed.
'It can be "B", or other letter if the workbook will be filled with other groups
'CURRENTLY LOOKS FOR LAST POPULATED CELL IN COLUMN, DISREGARDING PREVIOUS EMPTY CELLS
'Set PDFfiles = sh.Range(sh.Offset(3, 1), sh.cells(rows.count, "D").End(xlUp))
endRow = sh.cells(rows.count, "D").End(xlUp).row
For i = 2 To endRow
If sh.Range("C" & i).value = "PRODUCT " & processArr Then
startRow = i + 2: Exit For
End If
Next i
If startRow >= i Then MsgBox "Strange..." & vbCrLf & _
"The area to be prcessed ""PRODUCT " & processArr & """ could not be found.": Exit Sub
'Create Acrobat API objects
Set objCAcroPDDocDestination = CreateObject("AcroExch.PDDoc")
Set objCAcroPDDocSource = CreateObject("AcroExch.PDDoc")
'Open first PDF file and merge other PDF files into it
For i = startRow To endRow
n = n + 1
If sh.Range("D" & i).value = "" Then Exit For 'iteration is interrupted in case of an empty cell in D:D:
If n = 1 Then
objCAcroPDDocDestination.Open sh.Range("D" & i).value
Else
objCAcroPDDocSource.Open sh.Range("D" & i).value
If Not objCAcroPDDocDestination.InsertPages(objCAcroPDDocDestination.GetNumPages - 1, _
objCAcroPDDocSource, 0, objCAcroPDDocSource.GetNumPages, 0) Then
MsgBox "Error merging: " & sh.Range("D" & i).value
End If
objCAcroPDDocSource.Close
End If
Next i
'Save merged PDF files as a new file. Here the pdf name can be assorted with the area to be processed (for instance PRODUCT A):
objCAcroPDDocDestination.Save 1, "C:\Users\USER\OneDrive\TEST MERGE\Output\" & Sheets("SEARCH").Range("E6").value & ".pdf"
objCAcroPDDocDestination.Close
Set objCAcroPDDocSource = Nothing
Set objCAcroPDDocDestination = Nothing
'Opens dialogue box for successful/failed merge
MsgBox "Created New PDF (" & Sheets("SEARCH").Range("E6").value & ")" & vbCrLf & vbCrLf & "File Path: C:\Users\USER\OneDrive\TEST MERGE\Output\" & Sheets("SEARCH").Range("E6").value & ".pdf"
'Opens merged PDF
ActiveWorkbook.FollowHyperlink "C:\Users\USER\OneDrive\TEST MERGE\Output\" & Sheets("SEARCH").Range("E6").value & ".pdf"
End Sub
You must set processArr to be processed (A or B from your picture).
Code is not tested, but it should work. Please test it and send some feedback.

Retrieve last value in a row of a specific column of multiple closed workbooks without opening

I have a list of files in a worksheet, that are files in a subfolder of the current directory.
I need to retrieve the value of a specific cell (can change), in a specific sheet (constant).
Of 10 files that are in the subfolder and which all have a sheet called "resumen", I want to get the value of the last row in column G.
So far I have this
Sub read_data_from_file_WO_openning()
Dim outputs_address As String
Dim FolderName As String, wbName As String, cValue As Variant
outputs_address = Sheets("lista_macro").Range("G2").Value
ruta_csv_output = ActiveWorkbook.Path & outputs_address
FolderName = ruta_csv_output
'select files to review
For Each file_analysis In Sheets("archivos_en_outputs").Range("I2", Range("I2").End(xlDown))
wbName = file_analysis.Value
cValue = GetInfoFromClosedFile2(FolderName, wbName, "resumen", "G1")
MsgBox (file_analysis & cValue) 'to see the values
Next file_analysis
End Sub
Private Function GetInfoFromClosedFile2(ByVal wbPath As String, _
wbName As String, wsName As String, cellRef As String) As Variant
Dim arg As String
If Right(wbPath, 1) <> "\" Then wbPath = wbPath & "\"
arg = "'" & wbPath & "[" & wbName & "]" & _
wsName & "'!" & Range(cellRef).Address(True, True, xlR1C1)
GetInfoFromClosedFile2 = ExecuteExcel4Macro(arg)
End Function
In range I2 to down I have my list of files.
The problem is that my "G1" only retrieves data of cell G1 of all files, and I need the last row of column G for each file.
Sometimes these files have 7 rows, others have 15. The number of rows can change but always is at least 2.
I know the problem is in cell reference, but I don't know how to change this to accomplish what I have said.
Assuming that there are no blank spaces in Column G, you can use ExecuteExcel4Macro with the WorksheetFunction CountA to find the last row.
Function getLastValueInColumnG(ByVal wbPath As String, wbName As String, wsName As String) As Variant
Dim count As Long
Dim Address As String
Address = getExternalR1C1Address(wbPath, wbName, wsName, "G:G")
count = ExecuteExcel4Macro("CountA(" & Address & ")")
Address = getExternalR1C1Address(wbPath, wbName, wsName, "G" & count)
getLastValueInColumnG = ExecuteExcel4Macro(Address)
End Function
Function getExternalR1C1Address(ByVal wbPath As String, wbName As String, wsName As String, cellRef As String) As String
If Right(wbPath, 1) <> "\" Then wbPath = wbPath & "\"
getExternalR1C1Address = "'" & wbPath & "[" & wbName & "]" & wsName & "'!" & Range(cellRef).Address(True, True, xlR1C1)
End Function
Another approach assuming you have limited number of rows in your output files (<1000 ?)
Option Explicit
Sub find_in_closed_files()
Application.ScreenUpdating = False
Dim Fch As Range
Dim Wb1 As Workbook: Set Wb1 = ActiveWorkbook
Dim Fld As String: Fld = Wb1.Path & Sheets("lista_macro").Range("G2").Value
If Not Right(Fld, 1) = "\" Then Fld = Fld & "\"
Dim Ws1 As Worksheet: Set Ws1 = Wb1.Sheets(1)
Dim Ws2 As Worksheet: Set Ws2 = Wb1.Sheets("tmp pull") 'This is a temp draft sheet to pull the data that you'll need to create
For Each Fch In Ws1.Range("I2", Ws1.Range("I2").End(xlDown))
Ws2.Cells.Clear
Ws2.Range("G1:G999").FormulaR1C1 = "=IF('" & Fld & "[" & Fch.Value & "]resumen'!RC<>"""",'" & Fld & "[" & Fch.Value & "]resumen'!RC,"""")"
Ws2.Range("G1:G999").Value2 = Ws2.Range("G1:G999").Value2
MsgBox Ws2.Range("G9999").End(xlUp).Value
Next Fch
Application.ScreenUpdating = True
End Sub
This leaves a formula in column G that will track the last text, number or date in column G of the resumen worksheet within the closed external workbooks.
Sub xlsxLastG()
Dim i As Long, f As String
With Worksheets("archivos_en_outputs")
For i = 2 To .Cells(.Rows.Count, "I").End(xlUp).Row
'conform C:\Users\public\AppData\Documents\test.xlsb
' to 'C:\Users\public\AppData\Documents\[test.xlsb]resumen'!G:G
f = .Cells(i, "I").Value
f = Left(f, InStrRev(f, Chr(92))) & Chr(91) & Right(f, Len(f) - InStrRev(f, Chr(92)))
f = Chr(39) & f & Chr(93) & "resumen'!G:G"
.Cells(i, "G").Formula = _
"=index(" & f & ", max(iferror(match(1e99, " & f & "), 0), iferror(match(""zzz"", " & f & "), 0)))"
Next i
End With
End Sub
#N/A errors would typically mean column G was blank; #REF! errors would indicate not existing workbook or no resumen worksheet within the referenced workbook.

Best methods to reference a user function in a macro

Afternoon,
I currently have this User Function saved:
Function AlphaNumericOnly(strSource As String) As String
Dim i As Integer
Dim strResult As String
For i = 1 To Len(strSource)
Select Case Asc(Mid(strSource, i, 1))
Case 48 To 57, 65 To 90, 97 To 122: 'include 32 if you want to include space
strResult = strResult & Mid(strSource, i, 1)
End Select
Next
AlphaNumericOnly = strResult
End Function
I call this User Function in some macros that I run (checking that it is open in the macro). The issue I'm having is when I need to share a macro that references this with another user.
I could of course copy the User Function and send that along with a copy of the macro, they could then save it locally and adjust the macro to check their local copy is open. But this seems quite long winded.
Could anybody offer any suggestions? I am wondering if I could somehow embed the User Function in the macro, or store it centrally some how. Some web searching and asking around has drawn a blank on this one.
Thank you.
Please see the complete macro along with the user function at the end:
Option Explicit
Public Const csFORMULA = "=concatenate(""AGSBIS"",IF(I2=0,"""",CONCATENATE(UPPER(AlphaNumericOnly(LEFT(I2,3))),UPPER(AlphaNumericOnly(RIGHT(I2,3))))),IF(O2=0,"""",UPPER(AlphaNumericOnly(SUBSTITUTE(O2,""0"","""")))),IF(R2=0,"""",UPPER(AlphaNumericOnly(SUBSTITUTE(R2,""0"","""")))),IF(W2=0,"""",UPPER(AlphaNumericOnly(SUBSTITUTE(W2,""0"","""")))),IF(AC2=0,"""",AlphaNumericOnly(SUBSTITUTE(AC2,""0"",""""))),IF(AD2=0,"""",SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(AD2,""-"",""X""),""."",""Y""),""0"",""Z"")),IF(AF2=0,"""",SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(AF2,""-"",""X""),""."",""Y""),""0"",""Z"")),IF(AH2=0,"""",SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(AH2,""-"",""X""),""."",""Y""),""0"",""Z"")))"
Sub AgeasBIS()
Dim lr As Long
Dim cl As Range
Dim Rng As Range
Dim mssg As String
Dim WS As Worksheet
Dim SaveToDirectory As String
Dim DateFormat As String
Dim StatementName As String
Dim Organisation As String
Dim ErrorMessage As String
Dim ErrorMessageTitle As String
Dim CompleteMessage As String
Dim CompleteMessageTitle As String
Dim UserFunctionsLocation As String
Dim SaveLocation As String
DateFormat = Format(CStr(Now), "yyyy_mm_dd_hhmmss_")
ErrorMessageTitle = "Invalid Date Format"
ErrorMessage = "There are invalid date value(s) in the following cell(s). Please check these cells."
CompleteMessageTitle = "Statement Preparation"
CompleteMessage = "Statement preparation is complete. Your file has been saved and will be processed as part of the next scheduled upload."
StatementName = "age_bts"
Organisation = "BTS"
' save locations
'*location of the old user function* UserFunctionsLocation = "C:\Users\user.name\AppData\Roaming\Microsoft\AddIns\UserFunctions.xla"
SaveLocation = "S:\MI\gre_cac\statement_feeds\waiting_to_upload\"
Set WS = ActiveSheet
Application.ScreenUpdating = False
Workbooks.Open Filename:=UserFunctionsLocation
'clears any formats from the sheet
With WS
.Cells.ClearFormats
End With
'standardises all fonts
With WS.Cells.Font
.Name = "Calibri"
.Size = 10
.Bold = False
End With
With WS
'cleans all non_printable characters from the data (excluding date columns) & removes "'" & ","
'trims the insurer comments field to ensure it is a maximum of 500 characters
lr = .Range("I" & Rows.Count).End(xlUp).Row
Set Rng = Union(.Range("C2:AA" & lr), .Range("AD2:AO" & lr), .Range("AM2:AM" & lr))
For Each cl In Rng
If cl.Column = 39 Then 'column AM gets Left() truncation as well
cl = Left(WorksheetFunction.Trim(WorksheetFunction.Clean(cl.Value)), 500)
cl = WorksheetFunction.Substitute(cl.Value, "'", "")
cl = WorksheetFunction.Substitute(cl.Value, ",", "")
Else
cl = WorksheetFunction.Trim(WorksheetFunction.Clean(cl.Value))
cl = WorksheetFunction.Substitute(cl.Value, "'", "")
cl = WorksheetFunction.Substitute(cl.Value, ",", "")
End If
Next cl
'format invoice_date, effective_date & spare_date to dd/mm/yyyy
Union(.Range("AB1:AB" & lr), .Range("AC1:AC" & lr), .Range("AP1:AP" & lr)).NumberFormat = "dd/mm/yyyy"
'formats all numerical fields to "0.00"
Union(.Range("AD2:AL" & lr), .Range("AO2:AO" & lr)).NumberFormat = "0.00"
'add the statement name
Range("A2:A" & lr).FormulaR1C1 = StatementName
'add the organisation name
Range("D2:D" & lr).FormulaR1C1 = Organisation
'adds the formula to generate the unique key (from the declared constant)
Range("B2:B" & lr).Formula = csFORMULA
Range("B2:B" & lr) = Range("B2:B" & lr).Value
'auto-fit all columns
With WS
.Columns.AutoFit
End With
'checks that only date values as present in the invoice_date, effective_date & spare_date
Set Rng = Union(.Range("AB2:AB" & lr), .Range("AC2:AC" & lr), .Range("AP2:AP" & lr))
For Each cl In Rng
If Not IsDate(cl.Value) And Not IsEmpty(cl) Then _
mssg = mssg & cl.Address(0, 0) & Space(4)
Next cl
End With
'If non-date values are found display a message box showing the cell locations
If CBool(Len(mssg)) Then
MsgBox (ErrorMessage & Chr(10) & Chr(10) & _
mssg & Chr(10) & Chr(10)), vbCritical, ErrorMessageTitle
'Otherwise display a message that the statement preparation is complete
Else
MsgBox CompleteMessage, , CompleteMessageTitle
End If
'save location for the .csv
SaveToDirectory = SaveLocation
'uses the set dateformat and save lovation
WS.SaveAs SaveToDirectory & DateFormat & StatementName, xlCSV
Set Rng = Nothing
Set WS = Nothing
Application.ScreenUpdating = True
ActiveWorkbook.Close SaveChanges:=False
End Sub
Function AlphaNumericOnly(strSource As String) As String
Dim i As Integer
Dim strResult As String
For i = 1 To Len(strSource)
Select Case Asc(Mid(strSource, i, 1))
Case 48 To 57, 65 To 90, 97 To 122: 'include 32 if you want to include space
strResult = strResult & Mid(strSource, i, 1)
End Select
Next
AlphaNumericOnly = strResult
End Function
Working through the comments:
Try adding a tempValue before the Select Case
Function AlphaNumericOnly(strSource As String) As String
Dim i As Integer
Dim strResult As String
Dim tempValue As Integer
For i = 1 To Len(strSource)
tempValue = Asc(Mid(strSource, i, 1))
Select Case tempValue
Case 48 To 57, 65 To 90, 97 To 122: 'include 32 if you want to include space
strResult = strResult & Mid(strSource, i, 1)
End Select
Next
AlphaNumericOnly = strResult
End Function
Using Regular Expressions offers a shorter more efficient solution then examining each character:
Function AlphaNumericOnly(strIn) As String
Dim objRegex As Object
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Global = True
.ignorecase = True
.Pattern = "[^\w]+"
AlphaNumericOnly = .Replace(strIn, vbNullString)
End With
End Function

New workbook created unintentionally

I'm trying to copy a worksheet ("ReceivingRecords") from the workbook ("InventoryControlSystemV1.1") and paste it in a new workbook ("RecordBook"). I have created a temporary workbook named "Temp.xls" which allows me to use the SaveCopyAs method to create my new workbook "RecordBook".
When I run the procedure, "RecordBook" is created as intended but with only one entry (The text 'InventoryControlSystemV1.1.xls') in cell A1.
The worksheet that I want to copy is then pasted into a new, unnamed, workbook.
I can't figure out where or why this new workbook is being created.
Here is the code for this procedure:
Sub WriteReceivingToRecords()
Dim UsedRng As Range
Dim LastCol As Long
Dim BeginDate, EndDate
Dim NameString
Dim FormatBeginDate, FormatEndDate
Dim BackupQuest As Integer
Dim BackupMsg As String
'Confirmation dialog box to avoid mistakes
BackupMsg = "This will create a new workbook for the period" & vbNewLine
BackupMsg = BackupMsg & " since the last backup was made, and will clear" & vbNewLine
BackupMsg = BackupMsg & " the receiving records in this workbook." & vbNewLine & vbNewLine
BackupMsg = BackupMsg & "Are you sure you want to back up the receiving records?"
BackupQuest = MsgBox(BackupMsg, vbYesNo, "Back-up Records")
If BackupQuest = vbNo Then
Exit Sub
Else
' Find start and end dates of receiving - To use for worksheet title
Workbooks("InventoryControlSystemV1.1.xls").Activate
Worksheets("ReceivingRecords").Activate
Set UsedRng = ActiveSheet.UsedRange
LastCol = UsedRng(UsedRng.Cells.Count).Column
Do While Cells(2, LastCol) = ""
LastCol = LastCol - 1
Loop
EndDate = Cells(2, LastCol).Text
BeginDate = Cells(2, 2).Text
FormatBeginDate = Format(BeginDate, "d mmmm yy")
FormatEndDate = Format(EndDate, "d mmmm yy")
NameString = "M-Props Receiving Records " & FormatBeginDate & " To " _
& FormatEndDate & ".xls"
Workbooks("InventoryControlSystemV1.1.xls").Sheets("ReceivingRecords").Copy
Workbooks.Open Filename:="Temp.xls"
Workbooks("Temp.xls").Activate
Workbooks("Temp.xls").Worksheets("Sheet1").Paste _
Destination:=Workbooks("Temp.xls").Worksheets("Sheet1").Range("A1")
Workbooks("Temp.xls").SaveCopyAs NameString & ".xls"
Workbooks("Temp.xls").Close False
End If
End Sub
Replace
Workbooks("InventoryControlSystemV1.1.xls").Sheets("ReceivingRecords").Copy
with
Workbooks("InventoryControlSystemV1.1.xls").Sheets("ReceivingRecords").Cells.Copy
That should do it.

VBA Subscript out of range - error 9

Can somebody help me with this code, I am getting a subscript out of range error:
The line after the 'creating the sheets is highlighted in yellow in debugger
'Validation of year
If TextBox_Year.Value = Format(TextBox_Year.Value, "0000") Then
'Creating Process
'Creation of new sheet
Workbooks.Add
ActiveWorkbook.SaveAs FileName:= _
"" & Workbooks("Temperature Charts Sheet Creator").Sheets("MENU").Cells(4, 12).Value & "Data Sheet - " & ComboBox_Month.Value & " " & TextBox_Year.Value & ".xls", FileFormat _
:=xlNormal, Password:="", WriteResPassword:="", ReadOnlyRecommended:= _
False, CreateBackup:=False
'Creating of the sheets
Windows("Data Sheet - " & ComboBox_Month.Value & " " & TextBox_Year.Value & ".xls").Activate
Sheets("Sheet3").Select
Sheets("Sheet3").Name = "31 " & ComboBox_Month.Value
Sheets("Sheet2").Select
Sheets("Sheet2").Name = "30 " & ComboBox_Month.Value
Sheets("Sheet1").Select
Sheets("Sheet1").Name = "29 " & ComboBox_Month.Value
For i = 28 To 1 Step -1
Sheets.Add
ActiveSheet.Name = i & " " & ComboBox_Month.Value
Next
Suggest the following simplification: capture return value from Workbooks.Add instead of subscripting Windows() afterward, as follows:
Set wkb = Workbooks.Add
wkb.SaveAs ...
wkb.Activate ' instead of Windows(expression).Activate
General Philosophy Advice:
Avoid use Excel's built-ins: ActiveWorkbook, ActiveSheet, and Selection: capture return values, and, favor qualified expressions instead.
Use the built-ins only once and only in outermost macros(subs) and capture at macro start, e.g.
Set wkb = ActiveWorkbook
Set wks = ActiveSheet
Set sel = Selection
During and within macros do not rely on these built-in names, instead capture return values, e.g.
Set wkb = Workbooks.Add 'instead of Workbooks.Add without return value capture
wkb.Activate 'instead of Activeworkbook.Activate
Also, try to use qualified expressions, e.g.
wkb.Sheets("Sheet3").Name = "foo" ' instead of Sheets("Sheet3").Name = "foo"
or
Set newWks = wkb.Sheets.Add
newWks.Name = "bar" 'instead of ActiveSheet.Name = "bar"
Use qualified expressions, e.g.
newWks.Name = "bar" 'instead of `xyz.Select` followed by Selection.Name = "bar"
These methods will work better in general, give less confusing results, will be more robust when refactoring (e.g. moving lines of code around within and between methods) and, will work better across versions of Excel. Selection, for example, changes differently during macro execution from one version of Excel to another.
Also please note that you'll likely find that you don't need to .Activate nearly as much when using more qualified expressions. (This can mean the for the user the screen will flicker less.) Thus the whole line Windows(expression).Activate could simply be eliminated instead of even being replaced by wkb.Activate.
(Also note: I think the .Select statements you show are not contributing and can be omitted.)
(I think that Excel's macro recorder is responsible for promoting this more fragile style of programming using ActiveSheet, ActiveWorkbook, Selection, and Select so much; this style leaves a lot of room for improvement.)
Subscript out of Range error occurs when you try to reference an Index for a collection that is invalid.
Most likely, the index in Windows does not actually include .xls. The index for the window should be the same as the name of the workbook displayed in the title bar of Excel.
As a guess, I would try using this:
Windows("Data Sheet - " & ComboBox_Month.Value & " " & TextBox_Year.Value).Activate
Option Explicit
Private Sub CommandButton1_Click()
Dim mode As String
Dim RecordId As Integer
Dim Resultid As Integer
Dim sourcewb As Workbook
Dim targetwb As Workbook
Dim SourceRowCount As Long
Dim TargetRowCount As Long
Dim SrceFile As String
Dim TrgtFile As String
Dim TitleId As Integer
Dim TestPassCount As Integer
Dim TestFailCount As Integer
Dim myWorkbook1 As Workbook
Dim myWorkbook2 As Workbook
TitleId = 4
Resultid = 0
Dim FileName1, FileName2 As String
Dim Difference As Long
'TestPassCount = 0
'TestFailCount = 0
'Retrieve number of records in the TestData SpreadSheet
Dim TestDataRowCount As Integer
TestDataRowCount = Worksheets("TestData").UsedRange.Rows.Count
If (TestDataRowCount <= 2) Then
MsgBox "No records to validate.Please provide test data in Test Data SpreadSheet"
Else
For RecordId = 3 To TestDataRowCount
RefreshResultSheet
'Source File row count
SrceFile = Worksheets("TestData").Range("D" & RecordId).Value
Set sourcewb = Workbooks.Open(SrceFile)
With sourcewb.Worksheets(1)
SourceRowCount = .Cells(.Rows.Count, "A").End(xlUp).row
sourcewb.Close
End With
'Target File row count
TrgtFile = Worksheets("TestData").Range("E" & RecordId).Value
Set targetwb = Workbooks.Open(TrgtFile)
With targetwb.Worksheets(1)
TargetRowCount = .Cells(.Rows.Count, "A").End(xlUp).row
targetwb.Close
End With
' Set Row Count Result Test data value
TitleId = TitleId + 3
Worksheets("Result").Range("A" & TitleId).Value = Worksheets("TestData").Range("A" & RecordId).Value
'Compare Source and Target Row count
Resultid = TitleId + 1
Worksheets("Result").Range("A" & Resultid).Value = "Source and Target record Count"
If (SourceRowCount = TargetRowCount) Then
Worksheets("Result").Range("B" & Resultid).Value = "Passed"
Worksheets("Result").Range("C" & Resultid).Value = "Source Row Count: " & SourceRowCount & " & " & " Target Row Count: " & TargetRowCount
TestPassCount = TestPassCount + 1
Else
Worksheets("Result").Range("B" & Resultid).Value = "Failed"
Worksheets("Result").Range("C" & Resultid).Value = "Source Row Count: " & SourceRowCount & " & " & " Target Row Count: " & TargetRowCount
TestFailCount = TestFailCount + 1
End If
'For comparison of two files
FileName1 = Worksheets("TestData").Range("D" & RecordId).Value
FileName2 = Worksheets("TestData").Range("E" & RecordId).Value
Set myWorkbook1 = Workbooks.Open(FileName1)
Set myWorkbook2 = Workbooks.Open(FileName2)
Difference = Compare2WorkSheets(myWorkbook1.Worksheets("Sheet1"), myWorkbook2.Worksheets("Sheet1"))
myWorkbook1.Close
myWorkbook2.Close
'MsgBox Difference
'Set Result of data validation in result sheet
Resultid = Resultid + 1
Worksheets("Result").Activate
Worksheets("Result").Range("A" & Resultid).Value = "Data validation of source and target File"
If Difference > 0 Then
Worksheets("Result").Range("B" & Resultid).Value = "Failed"
Worksheets("Result").Range("C" & Resultid).Value = Difference & " cells contains different data!"
TestFailCount = TestFailCount + 1
Else
Worksheets("Result").Range("B" & Resultid).Value = "Passed"
Worksheets("Result").Range("C" & Resultid).Value = Difference & " cells contains different data!"
TestPassCount = TestPassCount + 1
End If
Next RecordId
End If
UpdateTestExecData TestPassCount, TestFailCount
End Sub
Sub RefreshResultSheet()
Worksheets("Result").Activate
Worksheets("Result").Range("B1:B4").Select
Selection.ClearContents
Worksheets("Result").Range("D1:D4").Select
Selection.ClearContents
Worksheets("Result").Range("B1").Value = Worksheets("Instructions").Range("D3").Value
Worksheets("Result").Range("B2").Value = Worksheets("Instructions").Range("D4").Value
Worksheets("Result").Range("B3").Value = Worksheets("Instructions").Range("D6").Value
Worksheets("Result").Range("B4").Value = Worksheets("Instructions").Range("D5").Value
End Sub
Sub UpdateTestExecData(TestPassCount As Integer, TestFailCount As Integer)
Worksheets("Result").Range("D1").Value = TestPassCount + TestFailCount
Worksheets("Result").Range("D2").Value = TestPassCount
Worksheets("Result").Range("D3").Value = TestFailCount
Worksheets("Result").Range("D4").Value = ((TestPassCount / (TestPassCount + TestFailCount)))
End Sub

Resources