Error when running a working macro from a Ribbon - vba

Below is a macro for Excel2010 in VBA. It's working only when I open VBA Code editor and run from the menu Debug. I tried to put it to Ribbon and run it from there but I've got this error:
Run-time error '1004':
Application-defined or object-defined error
Additionally, when I change all Range() into .Worksheet(i).Range(), the procedure does not run at all with the same error. It's like .Range does not seem to be part of Worksheet(i). I have no experience in Excel 2010 VBA.
Sub CopyAndRearrange()
Dim ns As Integer
Dim i As Integer
ns = ActiveWorkbook.Worksheets.Count
ActiveWorkbook.Sheets(ns).Cells.ClearContents
For i = 1 To ns - 1
With ActiveWorkbook
.Worksheets(i).Activate
Range("E1") = CInt(.Worksheets(i).Name)
Range(Range("G1"), Range("A1").End(xlDown).Offset(0, 7)) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5"
Range(Range("I1"), Range("A1").End(xlDown).Offset(0, 8)) = "=RC[-6]"
Range(Range("G1"), Range("I1").End(xlDown)).Copy
Sheets(ns).Activate
If i = 1 Then
'Range(Range("G1"), Range("I1").End(xlDown)).Copy Destination:=Sheets(ns).Range("A1")
Sheets(ns).Range("A1").Select
Else
'Range(Range("G1"), Range("I1").End(xlDown)).Copy Destination:=Sheets(ns).Range("A1").End(xlDown).Offset(1, 0)
Sheets(ns).Range("A1").End(xlDown).Offset(1, 0).Select
End If
ActiveSheet.Paste Link:=True
Application.CutCopyMode = False
Application.ScreenUpdating = True
End With
Next
Sheets(ns).Range("A1").Select
End Sub
EDIT:
OK. I have slightly changed the code in hope I was wrong about referring to the right sheet etc. The problem is still there. The line: ActiveSheet.Range(rg1, rg1) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5" causes the problem. Surprisingly, it is not the first that I refer to Range in the an active sheet and for some reasons, I really don't know why, I've got the error!!! To exhaust all possibilities, I have also tried these:
Explicitly re-create a Module in VBA Window
Re-open the file
Record a macro and insert a code in there
Nothing's worked so far. I have given up but maybe someone in future will see the problem and give a solution here.
Public Sub CopyAndRearrange()
Dim ns As Integer
Dim i As Integer
Dim ws As Worksheet
Dim wb As Workbook
Dim rg1 As Range
Dim rg2 As Range
Dim cell As Range
Set wb = ThisWorkbook
ns = wb.Worksheets.Count
wb.Sheets(ns).Cells.ClearContents
For i = 1 To ns - 1
With wb
Set ws = wb.Worksheets(i)
ws.Activate
ActiveSheet.Range("E1") = CInt(ActiveSheet.Name)
Set rg1 = ActiveSheet.Range("G1")
Set rg2 = ActiveSheet.Range("A1").End(xlDown).Offset(0, 7)
ActiveSheet.Range(rg1, rg1) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5"
Set rg1 = ActiveSheet.Range("I1")
Set rg2 = ActiveSheet.Range("A1").End(xlDown).Offset(0, 8)
ActiveSheet.Range(rg1, rg2) = "=RC[-6]"
Set rg1 = ActiveSheet.Range("G1")
Set rg2 = ActiveSheet.Range("I1").End(xlDown)
ActiveSheet.Range(rg1, rg2).Copy
Sheets(ns).Activate
If i = 1 Then
ActiveSheet.Range("A1").Select
Else
ActiveSheet.Range("A1").End(xlDown).Offset(1, 0).Select
End If
ActiveSheet.Paste Link:=True
Application.CutCopyMode = False
Application.ScreenUpdating = True
End With
Next
Sheets(ns).Range("A1").Select
Set ws = Nothing
Set wb = Nothing
Set rg1 = Nothing
Set rg2 = Nothing
Set cell = Nothing
End Sub

Try the following:
Sub CopyAndRearrange(Control as IRibbionControl)
Adding the control allows the code to be executed from the ribbion.

I guess I found the answer to my own question.
The problem was missing bracket in this line:
ActiveSheet.Range(rg1, rg1) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5"
which should be:
ActiveSheet.Range(rg1, rg1) = "=IF(RC[-6]=0,"""",RC[-6] + R4C5)"
If the error was more intelligible, I would not lose 2 days to look for this problem :/

Related

Run-time Error: 1004 Application-defined or Object-defined error

I'm getting a run-time error when I run the following code:
Application.ScreenUpdating = False
Application.Calculation = xlCalculationAutomatic
Application.DisplayStatusBar = False
Application.EnableEvents = False
Dim c, OrgList, vtList, FndRng As Range
Dim Tbl As ListObject
Dim NewRow As ListRow
Dim Org, Track As Worksheet
Set Org = ActiveWorkbook.Worksheets("Org List")
Set Track = ActiveWorkbook.Worksheets("Visit Tracking Sheet")
Set Tbl = Track.ListObjects("TrackTbl")
Set OrgList = Org.Range(Cells(2, 1), Cells(Org.UsedRange.Rows.Count, 1))
Set vtList = Track.Range("TrackTbl[Org ID]")
Everything runs fine until I get to Set ChngList = Track.Range("TrackTbl[Org ID]") which throws the Run-time Error: 1004. I have tried also the following replacement lines, all of which throw the same error:
Set vtList = Tbl.Range(Cells(2, 1), Cells(ListRows.Count, 1))
Set vtList = Track.Range(Cells(2, 1), Cells(Track.UsedRange.Rows.Count, 1))
Set vtList = Track.Tbl.Range(Cells(2, 1), Cells(ListRows.Count, 1))
Set vtList = Tbl.Range
I'm at a loss on this one and have had trouble finding a solution for this. I assume it is an issue with setting the Range referencing cells in a Table but am not sure.
Thanks to Siddharth Rout for pointing my in the right direction for this one.
The answer involves two issues that I was not noticing. The first is that the error was actually occurring at the Set OrgList line instead of the Set vtList line. The error was being caused because even though I referenced the correct sheet, without a With line, I have to reference that sheet at every point in that line. The corrected code is below:
Application.ScreenUpdating = False
Application.Calculation = xlCalculationAutomatic
Application.DisplayStatusBar = False
Application.EnableEvents = False
Dim c, OrgList, vtList, FndRng As Range
Dim Tbl As ListObject
Dim NewRow As ListRow
Dim Org, Track As Worksheet
Set Org = ActiveWorkbook.Worksheets("Org List")
Set Track = ActiveWorkbook.Worksheets("Visit Tracking Sheet")
Set Tbl = Track.ListObjects("TrackTbl")
Set OrgList = Org.Range(Org.Cells(2, 1), Org.Cells(Org.UsedRange.Rows.Count, 1))
Set vtList = Track.Range("TrackTbl[Org ID]")
I could have used With to eliminate the need to reference the sheet for each Range.Cells in the line, but it would have been the same amount of code and the sheet name is short. Either way should work for anyone running into this problem.

PasteSpecial Method Odd Error

I have gone through the similar questions and have not found anything with this specific error.
I am trying to make a macro that goes through a large number of CSV files, pulls the necessary information I need, copies and pastes that data to a new Workbook, and then closes the CSV file and goes to the next one.
When I test my code and have it run Step by Step (using F8) it functions fine and there are no error. However, whenever I try and just have the code run (like pressing F5) I get the error "PasteSpecial Method of Class Range" failed. When I press debug this line of the code is highlighted:
copyRange.Offset(0, 1).PasteSpecial Paste:=xlPasteValues
I added a small time delay of 0.5s before this line and it actually was able to go further through the files before failing.
Is it something with the Range.Offset method? Should I explicitly define a different copy range?
Code I have follows below:
Public Sub OpenTXT_CopyNewWBK(inPath As String)
Application.ScreenUpdating = False
Dim fso, oFolder, oSubfolder, oFile, queue As Collection
Dim app As New Excel.Application
app.Visible = True
Dim dataRange As Range, dateRange As Range, copyRange As Range
Dim lastCell, lastRow As String
Dim newBook, wbk As Excel.Workbook
Dim csvStart As Long
Set newBook = Workbooks.Add
With newBook
.SaveAs Filename:="BETA RAY " & Format(Now, "ddmmyyhhmmss")
End With
Set fso = CreateObject("Scripting.FileSystemObject")
Set queue = New Collection
queue.Add fso.GetFolder(inPath) 'obviously replace
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
Do While queue.Count > 0
Set oFolder = queue(1)
queue.Remove 1 'dequeue
For Each oSubfolder In oFolder.SubFolders
queue.Add oSubfolder 'enqueue
Next oSubfolder
For Each oFile In oFolder.Files
Set wbk = app.Workbooks.Add(oFile.Path)
lastCell = wbk.Sheets(1).Range("A1").End(xlDown).Address
If Len(lastCell) = 6 Then
lastRow = Mid(lastCell, 4, 3)
ElseIf Len(lastCell) = 5 Then
lastRow = Mid(lastCell, 4, 2)
ElseIf Len(lastCell) = 4 Then
lastRow = Mid(lastCell, 4, 1)
End If
Set dateRange = wbk.Sheets(1).Range("A2", lastCell)
dateRange.Select
Set dataRange = wbk.Sheets(1).Range("AA2", "AM" & lastRow)
dataRange.Select
wbk.Application.CutCopyMode = True
Set copyRange = Workbooks(newBook.name).Sheets(1).Range("A1048576").End(xlUp)
If Not copyRange = "" Then
Set copyRange = copyRange.Offset(1, 0)
End If
dateRange.Copy
copyRange.PasteSpecial Paste:=xlPasteValues
wbk.Application.CutCopyMode = False
wbk.Application.CutCopyMode = True
Application.Wait (Now + 500 * 0.00000001)
dataRange.Copy
copyRange.Offset(0, 1).PasteSpecial Paste:=xlPasteValues
wbk.Application.CutCopyMode = False
wbk.Close SaveChanges:=False
Next oFile
Loop
app.Quit
Set app = Nothing
Range("B:B").Delete
Range("G:G").Delete
Range("L:L").Delete
Application.ScreenUpdating = True
End Sub
I am sure there are much better ways to do a lot of the things I have going on there. I really just use VBA to make my life easier at work so a lot of the code I use is copy, pasted, and modified to fit my needs. I couldn't figure out how to make this method work wbk2.sht2.Range("A1:A5") = wbk1.sht1.Range("B1:B5") everything I have read says this should be a much better method. Also, the portions of code that read dataRange.Select and dateRange.Select are just there for debugging purposes.
try this....
wbk2.sht2.Range("A1:A5").value = wbk1.sht1.Range("B1:B5").value

Unable to Set workbook

I have being doing research on why I am unable to set my workbook for the past couple of hours. What I am trying to do is go through each spreadsheet within a folder to refresh the data and import them using Vlookup at the Set Book2 = workbooks("InfoPedia Page Views (ASG Compete)") is when I am getting an error
Run-time error '9': Subscript out of range
Please, if anyone can tell why my code isn't working, I would really appreciated it.
enter code here
Sub Test()
Dim Book2 As Workbook
Set fso = CreateObject("Scripting.FileSystemObject")
Set xl = CreateObject("Excel.Application")
xl.Visible = True
For Each f In fso.getfolder("C:\Users\v-gazhan\Desktop\Infopedia Quality Project\Infopedia Quality Dashboard\Page Views").Files
If LCase(fso.GetextensionName(f.Name)) = "xlsx" Then
Set wb = xl.workbooks.Open(f.Path)
' Set the correct month
wb.SlicerCaches("Slicer_Month_Name").VisibleSlicerItemsList = Array _
( _
"[Time].[Month Name].&[10]")
With Application.WorksheetFunction
If fso.getbasename(f.Name) = "InfoPedia Page Views (ASG Compete)" Then
***Set Book2 = workbooks("InfoPedia Page Views (ASG Compete)")***
Set SearchRange = Book2.Sheets("Page Views Sorted Most to Least").Range("B:D")
ActiveWorkbook.Sheets("Reference").Cells(1, 4).Value = .VLookup(Sheets("reference").Range("B1"), SearchRange, 3, False)
End If
End With
wb.Close
End If
Next
xl.Qu
End Sub

vba Direct copy for buttons

I know that I could do something like..
range("C1:D1").copy destination:=range("C2:D2")
for ranges, I would like to know if I can do the same for form control buttons
Current code below copies the button if found and then adds the button to the cell where the "hash tag" was written. In this example "#Button Back To Summary#". This all works fine but I would like to change the code to not go via the clipboard, for example like the above code for a range but for a form button.
Calling Code:
On Error Resume Next
Cells.Find(What:="#Button Back To Summary#", After:=ActiveCell, LookIn:= _
xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext _
, MatchCase:=False, SearchFormat:=False).Activate
If Err.Number = 0 Then
addshapetocell ActiveCell, "BK_TO_SUMMARY"
End
DoEvents
On Error GoTo 0
addshapetocell()
Sub addshapetocell(p As Range, btn_Name As String)
Dim clLeft As Double
Dim clTop As Double
Dim cl As Range
Dim r As Integer, R1 As Integer
On Error GoTo 0
R1 = 0
r = 0
Set cl = Range(p.Address)
clLeft = cl.Left
clTop = cl.Top
cl.value = ""
retryer:
update_Working_Status
Application.CutCopyMode = False
DoEvents
If r > 5000 Or R1 > 700 Then
MsgBox "Code has attempted to copy a button 5000 times and has failed each time"
Stop
End If
Worksheets("Odds").Shapes(btn_Name).Copy
DoEvents
If Application.ClipboardFormats(1) = 0 Then
R1 = R1 + 1
Sleep (50)
GoTo retryer
End If
With ActiveSheet
On Error Resume Next
.Paste
If Err.Number = 1004 Then
On Error GoTo 0
r = r + 1
Sleep (50)
GoTo retryer
ElseIf Err.Number <> 0 Then
Stop 'unhandled error has happend
End If
On Error GoTo 0
.Shapes(btn_Name).Left = clLeft
.Shapes(btn_Name).Top = clTop
End With
End Sub
Edit: update_Working_Status updates the status bar with "Working." & "Working.." etc
I don't believe there is a way to directly copy the Shape from one Worksheet to another without using the Clipboard. There is a .Duplicate method but I'm not aware of a way to change the Shapes Parent ie. which Worksheet it belongs to.
Have you considered programmatically re-creating the Shape using your template Shape as a base? This would be, effectively, copying the Shape but with a bit more effort involved. I've written the following as an example of how you could do this which, hopefully, you can adapt to your exact needs.
Dim wb As Workbook
Set wb = Application.ActiveWorkbook
' Worksheet Receiving the Template Shape ie. the ActiveSheet.
Dim ws As Worksheet
Dim rng As Range
Dim newShape As Shape
Set ws = wb.ActiveSheet
Set rng = ws.Range("B10") ' Destination Cell.
' Worksheet containing the Template Shape.
Dim wsTemplate As Worksheet
Dim shapeToCopy As Shape
Set wsTemplate = wb.Sheets("Template") ' The Worksheet containing template button.
Set shapeToCopy = wsTemplate.shapes("#example") ' The name of template button.
' Different 'Shapes' are created via different Methods, so check the types that you want
' to support and implement the Method as appropriate.
Select Case shapeToCopy.Type
Case MsoShapeType.msoFormControl
' Create the 'new' Shape based on the type and size of the template, and the location of the receiving Cell.
Set newShape = ws.shapes.AddFormControl(shapeToCopy.FormControlType, rng.Left, rng.Top, shapeToCopy.Width, shapeToCopy.Height)
newShape.OLEFormat.Object.Text = shapeToCopy.OLEFormat.Object.Text ' Copy the template buttons caption.
Case Else
' Unsupported Shape Type
Exit Sub
End Select
' Now "Copy" the remaining shared Shape properties that we want to retain from the template.
newShape.Name = shapeToCopy.Name
newShape.AlternativeText = shapeToCopy.AlternativeText
newShape.OnAction = shapeToCopy.OnAction ' The name of the routine to run on button click
' etc...
' etc...
In sheet1 I have an invisible activeX control (Oleobject): commandbutton1
It can be placed alongside the 'hash tag' cell, using:
Sub M_snb()
With Cells.Find("hash tag").Offset(, 1)
Sheet1.CommandButton1.Top = .Top
Sheet1.CommandButton1.Left = .Left
Sheet1.CommandButton1.Visible = True
End With
End Sub

Copy worksheet macro stops doing anything when the workbook hits 50 worksheets

I have a workbook that has a number of cover sheets and then a bunch of sheets at the back that are contain a few graphs. The graph pages are created by copy-pasting one sheet ("MasterFormat") over and over again, changing a few key values each time.
The macro originally used to conk out fairly rapidly with a Copy Method of Worksheet Class failed error. I eventually found how to fix it, from http://support.microsoft.com/kb/210684 .
The problem is, I've had endless issues with my updated version; mostly that it continues running happily, but doesn't actually copy anything after a while. Part of why it's happy is that the updated logic includes a few Set x = y, if x is nothing thens, which (as far as I know) will only work with errors suppressed, so that's what I've done. But on the other hand, it stops copying sheets after there are 50 sheets, and gives no explanation (though this may be the mislocation of the on error goto 0).
Does anyone know what I should be fixing to make it actually copy all the sheets, not just get bored and stop?
The code is as follows:
Sub GenerateSheets()
Application.ScreenUpdating = False
Dim oBook As Workbook
On Error Resume Next
Set oBook = Workbooks("SSReport.xls")
If oBook Is Nothing Then
Set oBook = Application.Workbooks.Open("SSReport.xls")
End If
On Error GoTo 0
Dim i, j As Integer
Dim SheetName As String
Dim ws As Worksheet
Const PairingCount = 63
Dim Pairings(1 To PairingCount, 1 To 2) As String
For i = 1 To PairingCount
Pairings(i, 1) = oBook.Sheets("SSPairings").Rows(i + 1).Cells(1)
Pairings(i, 2) = oBook.Sheets("SSPairings").Rows(i + 1).Cells(2)
Next i
For i = 1 To PairingCount
If i Mod 5 = 0 Then
oBook.Close SaveChanges:=True
Set oBook = Nothing
Set oBook = Application.Workbooks.Open("SSReport.xls")
End If
Application.ScreenUpdating = False
j = oBook.Worksheets.Count
SheetName = "P" & Pairings(i, 1) & Pairings(i, 2)
On Error Resume Next
Set ws = oBook.Sheets(SheetName)
If ws Is Nothing Then
On Error GoTo 0
oBook.Sheets("MasterFormat").Copy After:=Sheets(j)
oBook.Sheets("MasterFormat (2)").Name = SheetName
End If
oBook.Sheets(SheetName).Cells(1, 2) = Pairings(i, 1)
oBook.Sheets(SheetName).Cells(1, 5) = Pairings(i, 2)
oBook.Sheets(SheetName).Cells(1, 8) = "P"
Next i
Application.ScreenUpdating = True
End Sub
It's run from a meta workbook, which was the suggestion of the KB article I linked to above. Interestingly, despite the Open workbook, it doesn't seem to actually work if the main workbook is not open.
The error is probably caused by this line:
oBook.Sheets("MasterFormat").Copy After:=Sheets(j)
The Sheets(j) will refer to whichever workbook the code module resides in, which may not be the intended workbook.
The following works for me:
Sub GenerateSheets()
Dim oBook As Workbook
Dim i As Long
Dim j As Long
Dim SheetName As String
Dim ws As Worksheet
Const PairingCount = 63
Dim Pairings(1 To PairingCount, 1 To 2) As String
On Error Resume Next
Set oBook = Workbooks("SSReport.xls")
On Error GoTo 0
If oBook Is Nothing Then
Set oBook = Application.Workbooks.Open("SSReport.xls")
End If
With oBook
For i = 1 To PairingCount
Pairings(i, 1) = .Sheets("SSPairings").Rows(i + 1).Cells(1)
Pairings(i, 2) = .Sheets("SSPairings").Rows(i + 1).Cells(2)
Next i
For i = 1 To PairingCount
If i Mod 5 = 0 Then
'//Save in case of corruption/error?'
.Save
End If
j = .Worksheets.Count
SheetName = "P" & Pairings(i, 1) & Pairings(i, 2)
On Error Resume Next
Set ws = .Sheets(SheetName)
On Error GoTo 0
If ws Is Nothing Then
.Sheets("MasterFormat").Copy After:=.Sheets(j)
.Sheets("MasterFormat (2)").Name = SheetName
End If
.Sheets(SheetName).Cells(1, 2) = Pairings(i, 1)
.Sheets(SheetName).Cells(1, 5) = Pairings(i, 2)
.Sheets(SheetName).Cells(1, 8) = "P"
Next i
End With
End Sub
I took the liberty of replacing the the close/reopen with a simple Save as this should achieve the same result?
Try changing
If ws Is Nothing Then
On Error GoTo 0
oBook.Sheets("MasterFormat").Copy After:=Sheets(j)
oBook.Sheets("MasterFormat (2)").Name = SheetName
End If
oBook.Sheets(SheetName).Cells(1, 2) = Pairings(i, 1)
oBook.Sheets(SheetName).Cells(1, 5) = Pairings(i, 2)
oBook.Sheets(SheetName).Cells(1, 8) = "P"
into
If ws Is Nothing Then
On Error GoTo 0
oBook.Sheets("MasterFormat").Copy After:=Sheets(j)
oBook.Sheets("MasterFormat (2)").Name = SheetName
else
oBook.Sheets(SheetName).Cells(1, 2) = Pairings(i, 1)
oBook.Sheets(SheetName).Cells(1, 5) = Pairings(i, 2)
oBook.Sheets(SheetName).Cells(1, 8) = "P"
End If
I guess if ws is nothing then it stuck in next 3 lines.
Based on Lunatik's answer, I changed oBook.Sheets("MasterFormat").Copy After:=Sheets(j) to oBook.Sheets("MasterFormat").Copy After:=oBook.Sheets(j), which seemed to fix the problem.