Excel Automation error when inserting a row - vba

I have a big problem and its driving me insane. I have a very simple piece of code that is supposed to copy a row and add it in below the active row plus a validation at the start of the code to check that you are allowed to add the row on that particular line.
The macro works perfectly when you first go in to the sheet. However, as soon as i enter anything in on any of the cells on the sheet the code bombs out with an automation error. Please say someone has found this before and has a fix for it?
The line it doesn't like is as shown here. Selection.Insert Shift:=xlDown
Sub Staffing_AddRow()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
ActiveCell.Select
Cells(ActiveCell.Row, 223).Select
If ActiveCell.Value = "Y" Then
ActiveSheet.Unprotect Password:="PasswordGoesHere"
'------------------------------------
ActiveCell.Rows("1:1").EntireRow.Select
Selection.Copy
Selection.Insert Shift:=xlDown
'------------------------------------
Cells(ActiveCell.Row, 13).Select
ActiveSheet.Protect Password:="PasswordGoesHere"
Else
If Response = MsgBox("You can't insert a row here!", _
vbCritical, "Warning") Then
Cells(ActiveCell.Row, 13).Select
End If
Cells(ActiveCell.Row, 13).Select
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
when it tries to paste that specific row in the worksheet I get Run-time error '-2147417848 (80010108)': Automation error the object invoked has disconnected from its clients.

Try this: Using With ActiveSheet
Sub Staffing_AddRow()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
ActiveCell.Select
'CHANGES BEGIN HERE
With ActiveSheet
If .Cells(ActiveCell.row, 223).Value = "Y" Then
ActiveSheet.Unprotect Password:="PasswordGoesHere"
'------------------------------------
ActiveCell.Rows("1:1").EntireRow.Select
Selection.Copy
Selection.Insert Shift:=xlDown
'------------------------------------
.Cells(ActiveCell.row, 13).Select
ActiveSheet.Protect Password:="PasswordGoesHere"
Else
If Response = MsgBox("You can't insert a row here!", _
vbCritical, "Warning") Then
.Cells(ActiveCell.row, 13).Select
End If
.Cells(ActiveCell.row, 13).Select
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End With
End Sub
See also: How to avoid using select statements in macros

Related

Paste Link Random Error

To provide a snapshot of how the code functions:
User Clicks button to Import Job Folder
File Path Selection Opens and User Selects File
VBA Imports Specified Cell Values from Job File and Pastes link to sheet.
Everything works fine except once in a while I get a error that says "No link to paste" and reference the ActiveSheet.Paste Link:=True Line but if I hit the runsub button on the VBA code editor it works. I don't know why I get this Error sometimes. Is there a way to make the code rerun on that error?
The Error occurs at any of the ActiveSheet.Paste Link:=True in the code shown below, again at random and at any of the Import Selections (Project Name or Client Name or Project Name etc)
'Imports Project#
sourcewb.Sheets("Estimate").Range("PROJECT_NUMBER").Copy 'project# info is located on "Reporting" tab
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Cells(NewRow, 1).Select
ActiveSheet.Paste Link:=True
'Imports Client Name
sourcewb.Sheets("Estimate").Range("PROJECT_CLIENT").Copy 'C3 is where client name info is located on "Reporting"
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Cells(NewRow, 2).Select
ActiveSheet.Paste Link:=True
'Imports Project Name
sourcewb.Sheets("Estimate").Range("PROJECT_NAME").Copy 'C2 is where project name info is located on "Reporting"
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Cells(NewRow, 3).Select
ActiveSheet.Paste Link:=True
'Imports Latest Revision Date
sourcewb.Sheets("Reporting").Range("O5").Copy 'P5 is where project name info is located on "Reporting"
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Cells(NewRow, 19).Select
ActiveSheet.Paste Link:=True
0
'Imports data from Project Total line
sourcewb.Sheets("Reporting").Range("C24:Q24").Copy 'Row 24 is where Project Total line is located on "Reporting"
PTRange = "D" & NewRow & ":" & "R" & NewRow
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Range(PTRange).Select
ActiveSheet.Paste Link:=True
Below is the full code:
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
'
'This code imports select data from specified project's cost tracking spread sheet.
'
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Sub ImportProjectStatus()
'Minimize runtime
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'Initialize Variables
Dim summarywb As Workbook
Dim sourcewb As Workbook
Dim currentVer As String
Dim FirstRow As Long
Dim LastRow As Long
Dim NewRow As Long
Dim NewJobNumber As String
Dim PTRange As String
'Set initial values
Set summarywb = ThisWorkbook
currentVer = "0.8.0"
'Open file selection dialog box
Application.FileDialog(msoFileDialogOpen).AllowMultiSelect = False
openFile = Application.FileDialog(msoFileDialogOpen).Show
If openFile <> 0 Then
sourcewbpath = Application.FileDialog(msoFileDialogOpen).SelectedItems(1) 'Select the corresponding master file
Else
sourcewbpath = ""
Exit Sub
End If
Set sourcewb = Workbooks.Open(sourcewbpath)
'Error Handling - If there is no reporting tab on a tracking sheet
On Error GoTo NoReportTabError
'Searches for first non-blank row with data
FirstRow = summarywb.ActiveSheet.Cells.Find(What:="Project #", After:=Range("A1"), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False).Row + 1
'Searches for last non-blank row
LastRow = summarywb.ActiveSheet.Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
'Sets Row to which new data will be imported
NewRow = LastRow + 1
'Checks if to-be imported job number is a duplicate
NewJobNumber = sourcewb.Sheets("Reporting").Range("P2")
If DuplicateCheck(summarywb, FirstRow, LastRow, NewRow, NewJobNumber) = 1 Then
If MsgBox(NewJobNumber & " already exists. Continue?", vbYesNo, "Confirm") = vbNo Then
'Close sourcewb
sourcewb.Close savechanges:=False
'Display back on
Application.ScreenUpdating = True
Application.DisplayAlerts = True
'Abort message
MsgBox "Job not added."
Exit Sub
End If
End If
'Imports Project#
sourcewb.Sheets("Estimate").Range("PROJECT_NUMBER").Copy 'project# info is located on "Reporting" tab
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Cells(NewRow, 1).Select
ActiveSheet.Paste Link:=True
'Imports Client Name
sourcewb.Sheets("Estimate").Range("PROJECT_CLIENT").Copy 'C3 is where client name info is located on "Reporting"
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Cells(NewRow, 2).Select
ActiveSheet.Paste Link:=True
'Imports Project Name
sourcewb.Sheets("Estimate").Range("PROJECT_NAME").Copy 'C2 is where project name info is located on "Reporting"
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Cells(NewRow, 3).Select
ActiveSheet.Paste Link:=True
'Imports Latest Revision Date
sourcewb.Sheets("Reporting").Range("O5").Copy 'P5 is where project name info is located on "Reporting"
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Cells(NewRow, 19).Select
ActiveSheet.Paste Link:=True
'Imports data from Project Total line
sourcewb.Sheets("Reporting").Range("C24:Q24").Copy 'Row 24 is where Project Total line is located on "Reporting"
PTRange = "D" & NewRow & ":" & "R" & NewRow
summarywb.ActiveSheet.Activate
summarywb.ActiveSheet.Range(PTRange).Select
ActiveSheet.Paste Link:=True
'Adds "N" to closed column
summarywb.ActiveSheet.Cells(NewRow, 20) = "N"
CleanExit:
'Line to display which line a new job was added to
MsgBox NewJobNumber & " added to line " & NewRow
'Close sourcewb
sourcewb.Close savechanges:=False
'Refresh Data (Note. Refreshes all links)
RefreshAllLinks
'Display back on
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Exit Sub
NoReportTabError:
MsgBox "No Reporting tab found on the specified Tracking workbook. Closing Macro."
'Close sourcewb
sourcewb.Close savechanges:=False
'Display back on
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Exit Sub
End Sub
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
'
'This code checks for job numbers that are duplicate of the one to be added.
'
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Private Function DuplicateCheck(summarywb, FirstRow, LastRow, NewRow, NewJobNumber)
Dim CheckCell As String
summarywb.ActiveSheet.Activate
For i = FirstRow To LastRow
Range("A" & i).Select
Selection.Copy
Range("A" & NewRow).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=Flase, Transpose:=False
CheckCell = Cells(NewRow, 1).Value
If CheckCell = NewJobNumber Then
DuplicateCheck = 1
Range("A" & NewRow).Clear
Exit Function
End If
Range("A" & NewRow).Clear
Next i
End Function
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
'
'This code refreshes all links in the active worksheet.
'
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Sub RefreshAllLinks()
'Minimize runtime
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'Initialize Variables
Dim summarywb As Workbook
'Set initial values
Set summarywb = ThisWorkbook
'Refresh all linked data
summarywb.ActiveSheet.Activate
summarywb.UpdateLink Name:=summarywb.LinkSources
'Display back on
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
'
'This code moves highlighted line(s) of data from current to archive tab.
'
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Sub ArchiveData()
'Minimize runtime
Application.ScreenUpdating = False
Application.DisplayAlerts = False
'Initialize Variables
Dim summarywb As Workbook
Dim LastRow As Long
Dim NewRow As Long
'Set initial values
Set summarywb = Workbooks("Project Status Summary.xlsm")
'Asks for confirmation
If MsgBox("Archive highlighted job(s)?", vbYesNo, "Confirm") = vbNo Then
'Display back on
Application.ScreenUpdating = True
Application.DisplayAlerts = True
'Abort message
MsgBox "Job(s) not archived."
Exit Sub
End If
'Finds last non-blank row on Archive sheet
Worksheets("Archive").Activate
LastRow = summarywb.Sheets("Archive").Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
'Assigns row number for a new line
NewRow = LastRow + 1
'Copies and pastes data from Current tab to Archive tab
Worksheets("Current").Activate
Selection.Copy
Worksheets("Archive").Activate
Range("A" & NewRow).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=Flase, Transpose:=False
''Displays confirmation message
MsgBox ("Job(s) archived.")
'Display back on
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
If the copy fails intermittently, it might be a race condition. Here's a little snippet that retries the paste a few times:
Sub PasteEx()
On Error Resume Next
Err.Clear
ActiveSheet.Paste Link:=True
If Err.Number = 0 Then
GoTo PasteEx_Exit
Else
For i = 1 To 3
Err.Clear
ActiveSheet.Paste Link:=True
If Err.Number = 0 Then
GoTo PasteEx_Exit
End If
Application.Wait Now + TimeValue("0:00:01") ' Adjust as needed
Next i
End If
On Error GoTo 0
Err.Raise 1004
PasteEx_Exit:
On Error GoTo 0
End Sub
Add this method and replace your ActiveSheet.Paste Link:=True with PasteEx.
There is a delay in there. Adjust it as needed.
Since I can't reproduce your conditions, I'm not sure if it will help you. Give it a try!

Excel vba MsgBox to display message when duplicate is found

I am trying to remove duplicates from a table in Excel, I have a piece of code that removes duplicates without any problem, I am wondering if I could make it prompt a message box when a duplicate is found saying something along the lines "This entry is a duplicate entry" Any suggestions? This Is what I got so far:
Sub AccessTransfer()
Range("A1:F1").Select
Selection.Copy
Sheets("Sheet2").Select
ActiveSheet.Paste
ActiveCell.Offset(0, 6).Value = "Oven"
Range("A65536").End(xlUp).Offset(1, 0).Select
Call GoDupe
Sheets("Sheet1").Select
Application.CutCopyMode = False
End Sub
Sub GoDupe()
Cells.RemoveDuplicates Columns:=Array(1), Header:=xlNo
Range("A65536").End(xlUp).Offset(1, 0).Select
End Sub
Rather than looping through, identifying and prompting for each duplicate, you could simply highlight all duplicates and prompt the user once.
Your GoDupe() sub could look something like this:
Sub GoDupe()
Cells.FormatConditions.AddUniqueValues
With Cells.FormatConditions(Cells.FormatConditions.Count)
.DupeUnique = xlDuplicate
.Interior.Color = RGB(255, 0, 0)
End With
If MsgBox("Red highlighted cells are duplicated. OK to remove duplicates?", vbOKCancel) = vbOK Then
Cells.RemoveDuplicates Columns:=Array(1), Header:=xlNo
Range("A65536").End(xlUp).Offset(1, 0).Select
End If
Cells.FormatConditions(Cells.FormatConditions.Count).Delete
End Sub

Code to search a list with a VBA Userform

I'm trying to create a userform in VBA that will search a list in another sheet and display all matching results, is it also possible to have that data displayed by default to then be narrowed down by the search box value?
There are three columns in the list it will search, but if it finds a match, ideally it would display the data from the first and third, the middle column is irrelevant, but needs to stay for other code.
Then you might need to select one of the results to display it in a specific folder in the workbook (column one result in one cell, column two in the cell next to it).
I'm completely new to userforms so a task like this is quite daunting, I'm not even certain how to activate the form from the sheet.
Any feedback is appreciated, I'll comment any useful code I find online.
Accomplished most of what I was after with the following:
Private Sub SearchButton_Click()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
On Error GoTo ErrorHandler
Workbooks("Form1.xlsm").Worksheets("Employees").Visible = True
ActiveWorkbook.Sheets("Employees").Activate
Employee = EmployeeName.Value
lastrow = Range("A" & Rows.Count).End(xlUp).Row
ActiveSheet.Range("$A$2:$C$" & lastrow).AutoFilter Field:=1, Criteria1:= _
"=*" & Employee & "*", Operator:=xlAnd
Workbooks("Form1.xlsm").Worksheets("Temp").Visible = xlSheetVisible
Workbooks("Form1.xlsm").Worksheets("Temp").Range("A1:AFD1000000").ClearContents
'validation to stop the form breaking if a nane is searched that doesnt exist
Range("A1000000").Select
Selection.End(xlUp).Select
If ActiveCell.Value = "KeyID" Then GoTo validationend
'Take the data that has been filtered by employee name and store it in a temp worksheet
Range("A2").Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
Workbooks("Form1.xlsm").Worksheets("Temp").Activate
Range("A1").Select
ActiveSheet.Paste
'Delete any data that is irrelevant at this stage
Range("D:D").Delete Shift:=xlToLeft
Range("E:E").Delete Shift:=xlToLeft
Range("G:AZ").Delete Shift:=xlToLeft
lastrow = Range("A" & Rows.Count).End(xlUp).Row
Dim rngName As Range
Dim ws As Worksheet
Dim i As Integer
Set ws = Worksheets("Temp")
For i = 1 To ws.Cells(ws.Rows.Count, 1).End(xlUp).Row Step 1
If ws.Cells(i, 1).Value <> vbNullString Then Me.ListBox.AddItem ws.Cells(i, 1).Value
Next i
validationend:
Workbooks("Form1.xlsm").Worksheets("Form").Activate
'Workbooks("Form1.xlsm").Worksheets("Temp").Visible = xlSheetVeryHidden
'Workbooks("Form1.xlsm").Worksheets("Employees").Visible = xlSheetVeryHidden
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
Exit Sub
ErrorHandler:
MsgBox ("Error: Name not found. Please check your spelling and try again.")
Workbooks("Form1.xlsm").Worksheets("Form").Activate
'Workbooks("Form1.xlsm").Worksheets("Temp").Visible = xlSheetVeryHidden
'Workbooks("Form1.xlsm").Worksheets("Employees").Visible = xlSheetVeryHidden
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
End Sub
Doesn't work perfectly, so if you want more answers, I'll be asking relevant questions soon.

Logging actions in VBA

What´s the best way to log each action executed in VBA? Is there some built-in Windows object that already does this that I can use?
(I'm not referring to user actions)
Thanks
This will log actions typed into cells. Right-click your sheet and paste the code into the window that opens..
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Range("$A$1:$b$400")) Is Nothing Then
Application.EnableEvents = False
Application.ScreenUpdating = False
With Worksheets("Sheet2")
.Select
.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0).Select
ActiveCell.Value = Target.Address
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = Target.Value
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = Now()
ActiveCell.NumberFormat = "mm/dd/yy"
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = InputBox("You've made a change to the Rates tab. Please enter your name here for historical purposes.")
Application.EnableEvents = True
Application.ScreenUpdating = True
End With
End If
End Sub

Conditionally move rows into another worksheet

I'm hoping someone can help me with this. I have a spreadsheet with 2 sheets one called Details and another called Reconciled. I have 1000+ rows in Details and I want to cut all rows that have 0 or a - in column E (I want to cut the entire row) and paste it into sheet Details. If possible I would like to copy and paste the headers from Reconciled into Details as well.
I've tried using this code (modified slightly) used in another post
Sub Test()
For Each Cell In Sheets("Details").Range("E:E")
If Cell.Value = "0" Then
matchRow = Cell.Row
Rows(matchRow & ":" & matchRow).Select
Selection.Copy
Sheets("Reconcile").Select
ActiveSheet.Rows(matchRow).Select
ActiveSheet.Paste
Sheets("Details").Select
End If
Next
End Sub
But there are 2 problems. Because some values - (numbers are truly) those get moved, but the ones that are 0.00 do not get moved because they are rounded (I think that's why they are not being moved). Also, the screen updates oddly, and I'm sorry I can't explain it more than.
Any help would be appreciated
Sub Test()
Application.ScreenUpdating = False
On Error Goto Finish
For Each Cell In Sheets("Details").Range("E:E")
If Cell.Value = 0 Or Cell.Value = "-" Then cell.EntireRow.copy Sheets("Reconcile").Rows(cell.Row)
Next
Finish:
Application.ScreenUpdating = True
End Sub
Notice: dont put quotes around the 0, this will make numeric comparison
Using Autofilter:
Public Sub Test()
Application.ScreenUpdating = False
With Worksheets("Details").UsedRange
.Parent.AutoFilterMode = False
.AutoFilter
.AutoFilter Field:=5, Criteria1:="0"
.Copy
With Worksheets("Reconciled").Cells(1, 1)
.PasteSpecial xlPasteColumnWidths
.PasteSpecial xlPasteAll
.Parent.Activate: .Select
End With
.Rows(1).Hidden = True
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
.Rows(1).Hidden = False
.AutoFilter
.Parent.Activate
.Cells(1, 1).Activate
End With
Application.ScreenUpdating = True
End Sub