VBA macro throwing Run-time error '1004':
PasteSpecial method of Range class failed
This error is only being thrown when the macro runs on PC. On a Mac, the macro runs seamlessly. Is there any reason the below macro would throw an error?
Option Explicit
Sub DCR()
Dim J As Integer
Dim K As Integer
Dim L As Range
Dim sDay As String
Dim sMonth As String
Dim sTemp As String
Dim iTarget As Integer
Dim dBasis As Date
Dim Wb As Workbook
Dim Wb2 As Workbook
Set Wb = ThisWorkbook
Set L = Sheets("Sheet1").Range("A1:G7")
L.Copy
For Each Wb2 In Application.Workbooks
Wb2.Activate
Next
iTarget = 13
While (iTarget < 1) Or (iTarget > 12)
iTarget = Val(InputBox("Numeric month?"))
If iTarget = 0 Then Exit Sub
Wend
Set Wb2 = Workbooks.Add
Application.ScreenUpdating = False
Application.DisplayAlerts = False
sTemp = Str(iTarget) & "/1/" & Year(Now())
dBasis = CDate(sTemp)
For J = 1 To 31
sDay = Format((dBasis + J - 1), "dddd mm-dd-yyyy")
sMonth = Format((dBasis), "yyyy-mm")
If Month(dBasis + J - 1) = iTarget Then
If J > Sheets.Count Then
Sheets.Add.Move after:=Sheets(Sheets.Count)
ActiveSheet.Name = sDay
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteValues
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteFormats
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteColumnWidths
Range("A1").Value = sDay
Else
If Left(Sheets(J).Name, 5) = "Sheet" Then
Sheets(J).Name = sDay
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteValues
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteFormats
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteColumnWidths
Range("A1").Value = sDay
Else
Sheets.Add.Move after:=Sheets(Sheets.Count)
ActiveSheet.Name = sDay
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteValues
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteFormats
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteColumnWidths
Range("A1").Value = sDay
End If
End If
End If
Next J
For J = 1 To (Sheets.Count - 1)
For K = J + 1 To Sheets.Count
If Right(Sheets(J).Name, 10) > _
Right(Sheets(K).Name, 10) Then
Sheets(K).Move Before:=Sheets(J)
End If
Next K
Next J
Sheets(1).Activate
Application.ScreenUpdating = True
Wb2.SaveAs Filename:="DCR_" + sMonth + ".xlsx"
'
End Sub
The reason for the error is that you are prematurely copying the source range to the clipboard, and somehow by the time when you try to paste the source range to the corresponding worksheet the clipboard is empty thus giving the error 1004. As to why the Mac does not give an error I have no idea, probably none of the actions performed between the L.Copy and the .PasteSpecial clears the clipboard or whatever the Mac uses. Nevertheless, it’s a bad practice to keep the items to be copied that long in the clipboard.
I have also done a review of your code and highlighted some points for improvement (see comments below)
Set Wb = ThisWorkbook 'Here you set the Wb variable but is not used at all in the entire procedure
Set L = Sheets("Sheet1").Range("A1:G7") 'Here was an opportunity to use the `Wb` variable instead this line points to whatever workbook is active
'This is the cause of the error: here you copy `A1:G7` to the clipboard (1\2)
L.Copy
'This Loop Through All Open Workbooks Seems To Have No Purpose!
For Each Wb2 In Application.Workbooks
Wb2.Activate
Next
'This is not efficient, if the user does not enter neither a valid number nor a zero it will go endlessly
'Also suggest to use Do...Loop for the reasons mentioned in the Tip of the page While...Wend Statement (see suggested pages)
iTarget = 13
While (iTarget < 1) Or (iTarget > 12)
iTarget = Val(InputBox("Numeric month?"))
If iTarget = 0 Then Exit Sub
Wend
'This way of setting the date is not efficient as it depends on knowing the date format used by the user machine
'Sugest to use instead the DateSerial Function (see suggested pages)
sTemp = Str(iTarget) & "/1/" & Year(Now())
dBasis = CDate(sTemp)
If J > Sheets.Count Then
Sheets.Add.Move after:=Sheets(Sheets.Count)
'These lines are repeated for each "situation" of the sheets (three times)
ActiveSheet.Name = sDay
'This is the cause of the error(2\2): here you try to paste from an empty clipboard
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteValues
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteFormats
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteColumnWidths
Range("A1").Value = sDay
Else
If Left(Sheets(J).Name, 5) = "Sheet" Then
Sheets(J).Name = sDay
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteValues
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteFormats
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteColumnWidths
Range("A1").Value = sDay
Else
Sheets.Add.Move after:=Sheets(Sheets.Count)
ActiveSheet.Name = sDay
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteValues
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteFormats
Wb2.Sheets(J).Range("A1").PasteSpecial Paste:=xlPasteColumnWidths
Range("A1").Value = sDay
End If
End If
End If
Next J
'This sort is redundant, instead have a more efficient process to add the required worksheets
For J = 1 To (Sheets.Count - 1)
For K = J + 1 To Sheets.Count
If Right(Sheets(J).Name, 10) > _
Right(Sheets(K).Name, 10) Then
Sheets(K).Move Before:=Sheets(J)
End If
Next K
Next J
Sheets(1).Activate
Application.ScreenUpdating = True
'Missed to restate the `Application.DisplayAlerts = True`
'This is very dangerous as the system will not advise when closing a workbook without saving it first.
'And it will result in losing all work done on that workbook!
'This will give an error if by any chance a workbook with same name is open
Wb2.SaveAs Filename:="DCR_" + sMonth + ".xlsx"
This is the revised code.
For a deeper understanding of the resources used suggest to visit these pages:
Application Members (Excel),
On Error Statement,
DateSerial Function
While...Wend Statement,
Do...Loop Statement,
With Statement
Option Explicit
Sub DCR()
Dim rSrc As Range 'Source Range to be copied
Dim WbkTrg As Workbook 'Target Workbook to act upon
Dim sWbkTrg As String 'Target Workbook name
Dim WshTrg As Worksheet 'Target Worksheet to act upon
Dim sWshTrg As String 'Target Worksheet name
Dim bMonth As Byte
Dim dDate As Date
Dim bDay As Byte
Dim b As Byte
Rem Application Settings OFF
Application.EnableEvents = False
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Rem Get User Input
Do
On Error Resume Next
bMonth = InputBox("Enter month number (1 to 12) or 0 to cancel.")
On Error GoTo 0
b = 1 + b
If bMonth = 0 Then GoTo ExitTkn
If b = 3 Then GoTo ExitTkn
Loop Until bMonth >= 1 And bMonth <= 12
Rem Set Target Range To Be Copied Into New Workbook
Set rSrc = ThisWorkbook.Sheets("Sheet1").Range("A1:G7")
Rem Add Target Workbook
Set WbkTrg = Workbooks.Add
sWbkTrg = "DCR_" & Format(DateSerial(Year(Now), bMonth, 1), "yyyy-mm") & ".xlsx"
Rem Delete All Worksheets Minus One In Target Workbook
Do
With WbkTrg
If .Sheets.Count = 1 Then Exit Do
.Sheets(1).Delete
End With
Loop
Rem Add Worksheet for each day of the month
For bDay = 1 To 31
Rem Set Date & Month
dDate = DateSerial(Year(Now), bMonth, bDay)
sWshTrg = Format(dDate, "dddd mm-dd-yyyy")
If Month(dDate) = bMonth Then
Rem Process Worksheets - Days
With WbkTrg
If bDay = 1 Then
Rem Process 1st Day
Set WshTrg = .Sheets(bDay)
Else
Rem Add Remaining Days
Set WshTrg = .Sheets.Add(after:=.Sheets(.Sheets.Count))
End If: End With
Rem Update Day Standard Data
WshTrg.Name = sWshTrg
With WshTrg.Range("A1")
rSrc.Copy
.PasteSpecial Paste:=xlPasteValues
.PasteSpecial Paste:=xlPasteFormats
.PasteSpecial Paste:=xlPasteColumnWidths
.Value = sWshTrg
Application.CutCopyMode = False
End With
End If: Next
Rem Save Target Workbook
Application.Goto WbkTrg.Sheets(1).Cells(1), 1
On Error Resume Next
Workbooks(sWbkTrg).Close 'Close Workbook If Open
On Error GoTo 0
WbkTrg.SaveAs Filename:=sWbkTrg
ExitTkn:
Rem Application Settings ON
Application.EnableEvents = True
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
Related
I'm working to identify rows in sheet 1 that are not blank in column A and don't have a Y or L in column V. Then I need to copy the contents of that row, then paste values to an open row on the next worksheet. Lastly, I need to clear contents on the original sheet for that row. I'm getting stuck when it comes time to paste. Error 1004 - Method 'Range' of object'_Worksheet' failed. I appreciate any help.
Option Explicit
Option Compare Text
Sub EndMove()
Dim rowCount As Long, i As Long
Dim ws As Worksheet: Set ws = ActiveSheet
ws.Range("A11").Select
rowCount = ws.Cells(ws.Rows.Count, 1).End(xlUp).row
Application.ScreenUpdating = False: Application.EnableEvents = False
Call ShowAllRecords
For i = 11 To rowCount
If ws.Range("V" & i) <> "y" And ws.Range("V" & i) <> "l" Then
If ws.Range("A" & i) <> "" Then
Dim rowCount2 As Long, j As Long
Dim sRng As Range
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets(ActiveSheet.Index + 1)
Dim wAct As Worksheet
Dim lRow As Long
Dim End_Row As Long
Set wAct = ws
Set sRng = ws.Range("V" & i)
If Not IsDate("01 " & wAct.Name & " 2017") Or wAct.Name = "Dec" Then MsgBox "Not applicable for this sheet.": Exit Sub
If ActiveSheet.Index = ThisWorkbook.Worksheets.Count Then MsgBox "This is the last worksheet cannot move forward.": Exit Sub
wAct.unprotect
With ws2
.unprotect
If rowCount2 = "1" Then
For j = 11 To Rows.Count
If .Range("A" & j) = "" Then
End_Row = j
Exit For
End If
Next j
Else
End If
wAct.Range("A" & sRng.row & ":AD" & sRng.row + sRng.Rows.Count - 1).Copy
.Range("A" & End_Row).PasteSpecial xlPasteValuesAndNumberFormats
wAct.Range("A" & sRng.row & ":AD" & sRng.row + sRng.Rows.Count - 1).ClearContents
.Range("A1000").Value = End_Row
.protect DrawingObjects:=True, Contents:=True, Scenarios:=True, AllowFiltering:=True
End With
wAct.protect DrawingObjects:=True, Contents:=True, Scenarios:=True, AllowFiltering:=True
Application.CutCopyMode = False
End If
End If
Next i
Application.EnableEvents = True: Application.ScreenUpdating = True
Call FilterBlanks
MsgBox "Move Complete"
End If
End Sub
It seems there is no line in your code that would assign value to rowCount2. So when you check it in code below it gives always false and therefore skips this part
If rowCount2 = "1" Then
For j = 11 To Rows.Count
If .Range("A" & j) = "" Then
End_Row = j
Exit For
End If
Next j
Else
but that part is essential as it is the only part where End_Row is assigned value. So then when you try to do this .Range("A" & End_Row) there is nothing in End_Row. Set up a breakpoint on that line and check Locals screen for End_Row to make sure it is this.
Here is my code, it s simple! but i have an error
at this line "wb.Sheets("Sheet1").Range(Cells(3, j), Cells(10, j)).Select"
Private Sub CommandButton1_Click()
Dim fd As Office.FileDialog
Dim wb As Workbook
Dim ms As Workbook
Dim Path As String
Dim i As Integer
Dim j As Integer
Set ms = ThisWorkbook
Path = "D:\SYSTEM DATA\\EVT.xlsx"
Set wb = Workbooks.Open(Path)
wb.Activate
For i = 2 To 12 Step 1
If wb.Sheets(1).Cells(1, i).Value = "EVT006" Then
j = i
Exit For
End If
Next i
wb.Sheets("Sheet1").Range(Cells(3, j), Cells(10, j)).Select 'the error line
Selection.Copy
ms.Activate
With ms
Sheets(1).Cells(1, 1).PasteSpecial Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
End With
wb.Close True
End Sub
i dont know why ?
Please help
Be sure to declare your wb on your cells within the range as well.
Private Sub CommandButton1_Click()
Dim fd As Office.FileDialog
Dim wb As Workbook
Dim ms As Workbook
Dim Path As String
Dim i As Integer
Dim j As Integer
Set ms = ThisWorkbook
Path = "D:\SYSTEM DATA\\EVT.xlsx"
Set wb = Workbooks.Open(Path)
wb.Activate
For i = 2 To 12 Step 1
If wb.Sheets(1).Cells(1, i).Value = "EVT006" Then
j = i
Exit For
End If
Next i
wb.Sheets("Sheet1").Range(wb.Sheets("Sheet1").Cells(3, j), wb.Sheets("Sheet1").Cells(10, j)).Select 'the error line
Selection.Copy
ms.Activate
With ms
Sheets(1).Cells(1, 1).PasteSpecial Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
End With
wb.Close True
End Sub
in
wb.Sheets("Sheet1").Range(Cells(3, j), Cells(10, j)).Select
you have wb.Sheets("Sheet1").Range( referencing worksheet "Sheet1" of workbook wb, while Cells(3, j) and Cells(10, j) are referencing active sheet of active workbook, where this latter is still wb (due to preceeding wb.Activate) while the former is the worksheet wb is opening with (i.e. the active sheet at the time it was last saved) which is not assured in any way to be "Sheet1"
furthemore you should avoid Activate/Select/ActiveXXX/Selection pattern and use fully qualified range references
finally you wouldn't need any wb.Activate statement after Set wb = Workbooks.Open(Path) one, since at any workbook opening it becomes the Active one
so substitute
wb.Sheets("Sheet1").Range(Cells(3, j), Cells(10, j)).Select 'the error line
Selection.Copy
ms.Activate
With ms
Sheets(1).Cells(1, 1).PasteSpecial Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
End With
with
With Wb.Sheets("Sheet1")
.Range(.Cells(3, j), .Cells(10, j)).Copy
ms.Sheets(1).Cells(1, 1).PasteSpecial Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
End With
Sorry that I am new to VBA, thanks to all the experts here I am able to copy some of the codes and modify them to suit my needs. Basically, they are just a couple of command buttons which carry out various functions. It work out fine in my excel 2010. However, when I try to save the file in my another computer with Excel 2007 (Confirmed that vba is running), a message popup saying
"The following Features cannot be saved in a macro-free workbooks:
VB Project
To save a file with these features, click no, and then choose a macro-enabled file type..."
Even I clicked no and then save it as xlsm. When I opened the file, all the vba codes are disabled. I just wonder whether it is due to any line of the following codes that could not be run in excel 2007. Many thanks for your help!
Apologies for the codes being a mess.
Private Sub CommandButton1_Click()
' Defines variables
Dim Wb1 As Workbook, Wb2 As Workbook
' Disables screen updating to reduce flicker
Application.ScreenUpdating = False
' Sets Wb1 as the current (destination) workbook
Set Wb1 = ThisWorkbook
' Sets Wb2 as the defined workbook and opens it - Update filepath / filename as required
Set Wb2 = Workbooks.Open("\\new_admin\MASTER_FILE.xlsx")
' Sets LastRow as the first blank row of Wb1 Sheet1 based on column A (requires at least header if document is otherwise blank)
lastrow = Sheets(1).Cells(Rows.count, "A").End(xlUp).Row + 1
' With workbook 2
With Wb2
' Activate it
.Activate
' Activate the desired sheet - Currently set to sheet 1, change the number accordingly
.Sheets(1).Activate
' Copy the used range of the active sheet
.ActiveSheet.UsedRange.Copy
End With
' Then with workbook 1
With Wb1.Sheets(1)
' Activate it
.Activate
' Select the first blank row based on column A
.Range("A1").Select
' Paste the copied data
.Paste
End With
' Close workbook 2
Wb2.Close
' Re-enables screen updating
Application.ScreenUpdating = False
End Sub
Private Sub CommandButton2_Click()
' Defines variables
Dim Wb1 As Workbook, Wb2 As Workbook
' Disables screen updating to reduce flicker
Application.ScreenUpdating = False
' Sets Wb1 as the current (destination) workbook
Set Wb1 = ThisWorkbook
' Sets Wb2 as the defined workbook and opens it - Update filepath / filename as required
Set Wb2 = Workbooks.Open("C:\Users\admin\Desktop\Accom_Master_File.xlsx")
' Sets LastRow as the first blank row of Wb1 Sheet1 based on column A (requires at least header if document is otherwise blank)
lastrow = Sheets(2).Cells(Rows.count, "A").End(xlUp).Row + 1
' With workbook 2
With Wb2
' Activate it
.Activate
' Activate the desired sheet - Currently set to sheet 1, change the number accordingly
.Sheets(1).Activate
' Copy the used range of the active sheet
.ActiveSheet.UsedRange.Copy
End With
' Then with workbook 1
With Wb1.Sheets(2)
' Activate it
.Activate
' Select the first blank row based on column A
.Range("A1").Select
' Paste the copied data
.Paste
End With
' Close workbook 2
Wb2.Close
' Re-enables screen updating
Application.ScreenUpdating = False
Dim wkb As Workbook
Set wkb = ThisWorkbook
wkb.Sheets("Sheet1").Activate
End Sub
Private Sub CommandButton3_Click()
Range("B2").CurrentRegion.Select
Selection.Sort Key1:=Range("B2"), Order1:=xlAscending, Header:=xlGuess, _
OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
DataOption1:=xlSortNormal
ThisWorkbook.Sheets("Sheet2").Range("B:C").Delete xlUp
ThisWorkbook.Sheets("Sheet2").Columns(2).Copy
ThisWorkbook.Sheets("Sheet2").Columns(1).Insert
ThisWorkbook.Sheets("Sheet2").Columns(3).Delete
End Sub
Private Sub CommandButton4_Click()
Dim dicKey As String
Dim dicValues As String
Dim dic
Dim data
Dim x(1 To 35000, 1 To 24)
Dim j As Long
Dim count As Long
Dim lastrow As Long
lastrow = Cells(Rows.count, 1).End(xlUp).Row
data = Range("A2:X" & lastrow) ' load data into variable
With CreateObject("scripting.dictionary")
For i = 1 To UBound(data)
If .Exists(data(i, 2)) = True Then 'test to see if the key exists
x(count, 3) = x(count, 3) & ";" & data(i, 3)
x(count, 8) = x(count, 8) & ";" & data(i, 8)
x(count, 9) = x(count, 9) & ";" & data(i, 9)
x(count, 10) = x(count, 10) & ";" & data(i, 10)
x(count, 21) = x(count, 21) & ";" & data(i, 21)
Else
count = count + 1
dicKey = data(i, 2) 'set the key
dicValues = data(i, 2) 'set the value for data to be stored
.Add dicKey, dicValues
For j = 1 To 24
x(count, j) = data(i, j)
Next j
End If
Next i
End With
Rows("2:300").EntireRow.Delete
Sheets("Sheet1").Cells(2, 1).Resize(count - 1, 24).Value = x
End Sub
Private Sub CommandButton5_Click()
If ActiveSheet.AutoFilterMode Then Selection.AutoFilter
ActiveCell.CurrentRegion.Select
With Selection
.AutoFilter
.AutoFilter Field:=1, Criteria1:="ACTIVE"
.AutoFilter Field:=5, Criteria1:="NUMBERS"
.Offset(1, 0).Select
End With
Dim ws As Worksheet
Dim rVis As Range
Application.ScreenUpdating = False
For Each ws In Worksheets
Do Until ws.Columns("A").SpecialCells(xlVisible).count = ws.Rows.count
Set rVis = ws.Columns("A").SpecialCells(xlVisible)
If rVis.Row = 1 Then
ws.Rows(rVis.Areas(1).Rows.count + 1 & ":" & rVis.Areas(2).Row - 1).Delete
Else
ws.Rows("1:" & rVis.Row - 1).Delete
End If
Loop
Next ws
Application.ScreenUpdating = True
Dim LR As Long
LR = Cells(Rows.count, 1).End(xlUp).Row
Rows(LR).Copy
Rows(LR + 2).Insert
End Sub
Private Sub CommandButton6_Click()
Columns("A").Delete
Dim lastrow As Long
lastrow = Range("A2").End(xlDown).Row
Range("X2:X" & lastrow).FormulaR1C1 = "=IF(RC[+1]=""PAYING"", VLOOKUP(RC[-23],'Sheet2'!R1C1:R20000C8,8,0),""PENDING"")"
Range("Y2:Y" & lastrow).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-24],'Sheet2'!R1C1:R20000C8,2,0), ""PENDING"")"
Range("Z2:Z" & lastrow).FormulaR1C1 = "=(LEN(RC[-24])-LEN(SUBSTITUTE(RC[-24], "";"", """"))+1)*1200"
Range("AA2:AA" & lastrow).FormulaR1C1 = "=VLOOKUP(RC[-26],'Sheet3'!R2C2:R220C4,2,0)"
Range("AB2:AB" & lastrow).FormulaR1C1 = "=VLOOKUP(RC[-27],'Sheet3'!R2C2:R220C4,3,0)"
Range("AC2:AC" & lastrow).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-28],'Sheet4'!R1C1:R30C3,2,0),"""")"
Range("AD2:AD" & lastrow).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-29],'Sheet4'!R1C4:R30C6,2,0),"""")"
Columns("X:AD").EntireColumn.AutoFit
Sheets(1).Columns(24).NumberFormat = "#"
Sheets(1).Columns(25).NumberFormat = "#"
Sheets(1).Columns(29).NumberFormat = "#"
Sheets(1).Columns(30).NumberFormat = "#"
End Sub
Private Sub CommandButton7_Click()
Sheet1.Cells.Clear
End Sub
When something like this happens to me I just start up a new workbook and save explicitly in .xls or .xlsm format and then copy and paste my module or class code into new modules and classes in the new workbook. -- cannot post comments yet so if this doesn't help i shall delete this answer.
Working in an Excel document that I didn't design.
I am trying to automate raw data into an report type spreadsheet.
In short. I have code that does everything I need it to as far as formatting, moving columns, calculations, lookups and etc. I even have it creating new sheets based off of data that is in a certain column. The goal is for there to be sheets for every executive that has their data on it and only their data. While maintaining a sheet that has all data on it. So I need to copy and past only their data to their Sheet. I am really close....I think.
Currently the code creates the correct sheets, it even names them correctly. However, it moves the data incorrectly. For example I expect there to 15 records on sheet 2, but there is 10 I expect and 17 random others. Also, you can run the macro twice and get different results on the sheets.
I have exhausted two other people, and several search's today. I have no idea how to fix it. There is a lot of formatting code above this code. I am a basic user of VBA. I can do a good bit of things with it, but this code came from a colleague who has more experience, but then he couldn't figure out why it did what its doing. I'm running out of time. So I really would appreciate any help.
The code is as below.
'create new sheets
On Error GoTo ErrHandle
Dim vl As String
wb = ActiveWorkbook.Name
cnt = Application.WorksheetFunction.CountA(ActiveWorkbook.Sheets("Sheet1").Range("S:S"))
For i = 2 To cnt
vl = Workbooks(wb).Sheets("Sheet1").Cells(i, 19).Value
WS_Count = Workbooks(wb).Worksheets.Count
a = 0
For j = 1 To WS_Count
If vl = Workbooks(wb).Worksheets(j).Name Then
a = 1
Exit For
End If
Next
If a = 0 Then
Sheets.Add After:=ActiveSheet
ActiveSheet.Name = vl
Sheets("Sheet1").Activate
Range("A1:V1").Select
Selection.SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Sheets(vl).Activate
Range("A1").Select
ActiveSheet.Paste
End If
Next
Sheets("Sheet1").Activate
j = 2
old_val = Cells(2, 19).Value
For i = 3 To cnt
new_val = Cells(i, 19).Value
If old_val <> new_val Then
Range("A" & j & ":V" & i).Select
Selection.SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Sheets(old_val).Activate
Range("A2").Select
ActiveSheet.Paste
Sheets("Sheet1").Activate
old_val = Cells(i + 1, 19).Value
j = i + 1
End If
Next
On Error GoTo ErrHandle
Worksheets("0").Activate
ActiveSheet.Name = "External Companies"
Worksheets("Sheet1").Activate
ActiveSheet.Name = "All Data"
Worksheets("All Data").Activate
Range("A1").Select
Workbooks("PERSONAL.xlsb").Close SaveChanges:=False
ActiveWorkbook.SaveAs ("Indirect_AVID_Approval")
Exit Sub
ErrHandle:
MsgBox "Row: " & i & " Value =:" & vl
End Sub
My apologies, I know I'm a messy code writer. If you couldn't tell, I'm mostly self taught.
Thanks in advance.
If you are not filtering the data you don't need to use SpecialCells(xlCellTypeVisible). I use a function getWorkSheet to return a reference to the new worksheet. If the SheetName already exists the function will return that worksheet otherwise it will create a new worksheet rename it SheetName and return the new worksheet.
Sub ProcessWorksheet()
Dim lFirstRow As Long
Dim SheetName As String
Dim ws As Worksheet
With Sheets("Sheet1")
cnt = WorksheetFunction.CountA(.Range("S:S"))
For i = 2 To cnt
If .Cells(i, 19).Value <> SheetName Or i = cnt Then
If lFirstRow > 0 Then
Set ws = getWorkSheet(SheetName)
.Range("A1:V1").Copy ws.Range("A1")
.Range("A" & lFirstRow & ":V" & i - 1).SpecialCells(xlCellTypeVisible).Copy Destination:=ws.Range("A2")
End If
SheetName = .Cells(i, 19).Value
lFirstRow = i
End If
Next
End With
Worksheets("0").Activate
ActiveSheet.Name = "External Companies"
Worksheets("Sheet1").Activate
ActiveSheet.Name = "All Data"
Worksheets("All Data").Activate
Range("A1").Select
Workbooks("PERSONAL.xlsb").Close SaveChanges:=False
ActiveWorkbook.SaveAs ("Indirect_AVID_Approval")
End Sub
Function getWorkSheet(SheetName As String) As Worksheet
Dim ws As Worksheet
On Error Resume Next
Set ws = Worksheets(SheetName)
If ws Is Nothing Then
Set ws = Worksheets.Add(after:=ActiveSheet)
ws.Name = SheetName
End If
On Error GoTo 0
Set getWorkSheet = ws
End Function
I have a macro that goes through a large directory of files and performs a task. However the macro stops when it gets to a certain file that has 'unreadable content'. (excel files)
What can I add to my code to skip these files? What area of my code do I place it?
Tried adding this to my code after i declare my variables, doesn't do anything though.
On Error Resume Next
Many thanks
EDIT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Posting part of my vba code, just a note: 'UserInput' is a function. If you need more posted to better understand let me know and i'll post.
'get user input for files to search
Set fileNames = CreateObject("Scripting.Dictionary")
errCheck = UserInput.FileDialogDictionary(fileNames)
If errCheck Then
Exit Sub
End If
'''
For Each Key In fileNames 'loop through the dictionary
Debug.Print fileNames(Key)
Set wb = Workbooks.Open(fileNames(Key), CorruptLoad:=xlRepairFile)
wb.Application.Visible = False 'make it not visible
EDIT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Going to upload full code. This is with the recommended changes.
Sub ladiesman()
'includes filling down
Dim wb As Workbook, fileNames As Object, errCheck As Boolean
Dim ws As Worksheet, wks As Worksheet, wksSummary As Worksheet
Dim y As Range, intRow As Long, i As Integer
Dim r As Range, lr As Long, myrg As Range, z As Range
Dim boolWritten As Boolean, lngNextRow As Long
Dim intColNode As Integer, intColScenario As Integer
Dim intColNext As Integer, lngStartRow As Long
Dim lngLastNode As Long, lngLastScen As Long
' Turn off screen updating and automatic calculation
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
' Create a new worksheet, if required
On Error Resume Next
Set wksSummary = ActiveWorkbook.Worksheets("Unique data")
On Error GoTo 0
If wksSummary Is Nothing Then
Set wksSummary = ActiveWorkbook.Worksheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
wksSummary.Name = "Unique data"
End If
' Set the initial output range, and assign column headers
With wksSummary
Set y = .Cells(.Rows.Count, 3).End(xlUp).Offset(1, 0)
Set r = y.Offset(0, 1)
Set z = y.Offset(0, -2)
lngStartRow = y.Row
.Range("A1:D1").Value = Array("File Name", "Sheet Name", "Node Name", "Scenario Name")
End With
'get user input for files to search
Set fileNames = CreateObject("Scripting.Dictionary")
errCheck = UserInput.FileDialogDictionary(fileNames)
If errCheck Then
Exit Sub
End If
'''
For Each Key In fileNames 'loop through the dictionary
On Error Resume Next
Set wb = Workbooks.Open(fileNames(Key))
If Err.Number <> 0 Then
Set wb = Nothing ' or set a boolean error flag
End If
On Error GoTo 0 ' or your custom error handler
If wb Is Nothing Then
Debug.Print "Error when loading " & fileNames(Key)
Else
Debug.Print "Successfully loaded " & fileNames(Key)
wb.Application.Visible = False 'make it not visible
' more working with wb
End If
' Check each sheet in turn
For Each ws In ActiveWorkbook.Worksheets
With ws
' Only action the sheet if it's not the 'Unique data' sheet
If .Name <> wksSummary.Name Then
boolWritten = False
' Find the Scenario column
intColScenario = 0
On Error Resume Next
intColScenario = WorksheetFunction.Match("scenarioName", .Rows(1), 0)
On Error GoTo 0
If intColScenario > 0 Then
' Only action if there is data in column E
If Application.WorksheetFunction.CountA(.Columns(intColScenario)) > 1 Then
' Find the next free column, in which the extract formula will be placed
intColNext = .Cells(1, .Columns.Count).End(xlToLeft).Column + 1
' Assign formulas to the next free column to identify the scenario name to the left of the first _ character
.Cells(1, intColNext).Value = "Test"
lr = .Cells(.Rows.Count, intColScenario).End(xlUp).Row
Set myrg = .Range(.Cells(2, intColNext), .Cells(lr, intColNext))
With myrg
.ClearContents
.FormulaR1C1 = "=IFERROR(LEFT(RC" & intColScenario & ",FIND(INDEX({""+"",""-"",""_"",""$"",""%""},1,MATCH(1,--(ISNUMBER(FIND({""+"",""-"",""_"",""$"",""%""},RC" & _
intColScenario & "))),0)), RC" & intColScenario & ")-1), RC" & intColScenario & ")"
.Value = .Value
End With
' Copy unique values from the formula column to the 'Unique data' sheet, and write sheet & file details
.Range(.Cells(1, intColNext), .Cells(lr, intColNext)).AdvancedFilter xlFilterCopy, , r, True
r.Offset(0, -2).Value = ws.Name
r.Offset(0, -3).Value = ws.Parent.Name
' Clear the interim results
.Range(.Cells(1, intColNext), .Cells(lr, intColNext)).ClearContents
' Delete the column header copied to the list
r.Delete Shift:=xlUp
boolWritten = True
End If
End If
' Find the Node column
intColNode = 0
On Error Resume Next
intColNode = WorksheetFunction.Match("node", .Rows(1), 0)
On Error GoTo 0
If intColNode > 0 Then
' Only action if there is data in column A
If Application.WorksheetFunction.CountA(.Columns(intColNode)) > 1 Then
lr = .Cells(.Rows.Count, intColNode).End(xlUp).Row
' Copy unique values from column A to the 'Unique data' sheet, and write sheet & file details (if not already written)
.Range(.Cells(1, intColNode), .Cells(lr, intColNode)).AdvancedFilter xlFilterCopy, , y, True
If Not boolWritten Then
y.Offset(0, -1).Value = ws.Name
y.Offset(0, -2).Value = ws.Parent.Name
End If
' Delete the column header copied to the list
y.Delete Shift:=xlUp
End If
End If
' Identify the next row, based on the most rows used in columns C & D
lngLastNode = wksSummary.Cells(wksSummary.Rows.Count, 3).End(xlUp).Row
lngLastScen = wksSummary.Cells(wksSummary.Rows.Count, 4).End(xlUp).Row
lngNextRow = WorksheetFunction.Max(lngLastNode, lngLastScen) + 1
If (lngNextRow - lngStartRow) > 1 Then
' Fill down the workbook and sheet names
z.Resize(lngNextRow - lngStartRow, 2).FillDown
If (lngNextRow - lngLastNode) > 1 Then
' Fill down the last Node value
wksSummary.Range(wksSummary.Cells(lngLastNode, 3), wksSummary.Cells(lngNextRow - 1, 3)).FillDown
End If
If (lngNextRow - lngLastScen) > 1 Then
' Fill down the last Scenario value
wksSummary.Range(wksSummary.Cells(lngLastScen, 4), wksSummary.Cells(lngNextRow - 1, 4)).FillDown
End If
End If
Set y = wksSummary.Cells(lngNextRow, 3)
Set r = y.Offset(0, 1)
Set z = y.Offset(0, -2)
lngStartRow = y.Row
End If
End With
Next ws
wb.Close savechanges:=False 'close the workbook do not save
Set wb = Nothing 'release the object
Next 'End of the fileNames loop
Set fileNames = Nothing
' Autofit column widths of the report
wksSummary.Range("A1:D1").EntireColumn.AutoFit
' Reset system settings
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
.Visible = True
End With
End Sub
If you want to skip the unreadable file, you should get rid of CorruptLoad:=xlRepairFile (apparently it doesn't work for your files anyways), and use On Error Resume Next directly before trying to open the file.
Like this:
On Error Resume Next
Set wb = Workbooks.Open(fileNames(Key))
If Err.Number <> 0 Then
Set wb = Nothing ' or set a boolean error flag
End If
On Error GoTo 0 ' or your custom error handler
If wb Is Nothing Then
Debug.Print "Error when loading " & fileNames(Key)
Else
Debug.Print "Successfully loaded " & fileNames(Key)
wb.Application.Visible = False 'make it not visible
' more working with wb
' all
' your
' code
' goes
' here :)
End If
Edit
All the code from
' Check each sheet in turn
For Each ws In ActiveWorkbook.Worksheets
(you should use wb here instead of ActiveWorkbook)
to
wb.Close savechanges:=False 'close the workbook do not save
Set wb = Nothing 'release the object
belongs in the Else part directly after (or rather instead of) my placeholder comment
' more working with wb
All of this should only be done, if the workbook has been successfully loaded.
Edit 2
About wb vs ActiveWorkbook:
It improves the robustness of your code to avoid using ActiveWorkbook, ActiveSheet etc. as much as possible, especially when working with multiple workbooks. Some later changes to your code may make a different workbook active at the time you use it, and suddenly your code will fail. (Probably not in this function here, but it's a general rule of thumb.)
wb was just assigned to the opened workbook
Set wb = Workbooks.Open(fileNames(Key))
so it's good practice to use the wb variable for everything you do with that workbook.
For the skipped files:
Instead of
Debug.Print "Error when loading " & fileNames(Key)
simply collect them in a string
strErrorFiles = strErrorFiles & vbCrLf & fileNames(Key)
and later MsgBox that string. But note that MsgBox has a limit to the number of text it will show, so if there may be lots of error files, better write them to a sheet.