Hot to solve: VBA Copy Values only 1004 Error? - excel

I have an excel protected sheet that is being used by several users and I've found that they sometimes Copy&Paste info from a different application that Blocks the pasted cells (while changing other formats as well).
The solution that I've found is using a macro in ThisWorkbook that forces the Copy as Value.
As I don't have that much experience in VBA, I've decided to use some available code in the internet.
The problem is that the marco works just fine in my Excel, but not in an older version of Excel (where I need it to work...).
I'm getting the 1004 Error. From what I've read so far I believe this happens because the info in the Clipboard dissappears when I run the macro.
Does anyone know how to solve this?
Below is the code that I'm using:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim UndoString As String, srce As Range
On Error GoTo err_handler
UndoString = Application.CommandBars("Standard").Controls("&Undo").List(1)
If Left(UndoString, 5) <> "Paste" And UndoString <> "Auto Fill" Then
Exit Sub
End If
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Undo
If UndoString = "Auto Fill" Then
Set srce = Selection
srce.Copy
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.SendKeys "{ESC}"
Union(Target, srce).Select
Else
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
err_handler:
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub

Try this, two lines have been inserted
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim UndoString As String, srce As Range
On Error GoTo err_handler
UndoString = Application.CommandBars("Standard").Controls("&Undo").List(1)
If Left(UndoString, 5) <> "Paste" And UndoString <> "Auto Fill" Then
Exit Sub
End If
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Undo
If UndoString = "Auto Fill" Then
Set srce = Selection
srce.Copy
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.SendKeys "{ESC}"
Union(Target, srce).Select
Else
Selection.Copy 'This line has been inserted
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False 'This line has been inserted
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
err_handler:
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
It looks as though that section of the code (Else etc.) only applies if they used Paste but not AutoFill.
I don't see the merit of using the If block to distinguish between UndoString = "Auto Fill" and any other result, which based on an earlier If block can only include a situation where the last undoable action name started with (or was) Paste. Don't you want to do the same thing to both Auto Fill and Paste?

Related

Warning before overwriting existing data in VBA

I have the below code that creates a pop-up when new data is pasted into the specified range (A15 : E33). What I would like is when the user attempts to paste data into the range the pop up shows up and if the user selects no the data isn't pasted, preventing accidental overwrite.
Currently when the user selects no all it does is prevent cell B2 from being timestamped.
Thank you in advance for your help
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$15:$E$33" Then
Dim answer As Integer
answer = MsgBox("You are about to overwrite existing data, would you like to continue?", vbQuestion + vbYesNo)
If answer = vbYes Then
Range("B2") = "=NOW()"
Range("B2").Copy
Range("B2").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("a15:e33").Select
Else
MsgBox "Cancelled"
End If
End If
End Sub
Your code cannot know about your intention to paste in a specific range...
The above code is an event, being automatically triggered when the pasting has already been done. What you can do is using Application.UnDo:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.address = "$A$15:$E$33" Then
Dim answer As VbMsgBoxResult
answer = MsgBox("You are about to overwrite existing data, would you like to continue?", vbQuestion + vbYesNo)
If answer = vbYes Then
Application.EnableEvents = False 'to avoid the event being triggered again...
Range("B2") = "=NOW()"
Range("B2").Copy
Range("B2").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("a15:e33").Select
Application.EnableEvents = True
Else
Application.EnableEvents = False 'to avoid the event being triggered again...
Application.Undo
Application.EnableEvents = True
MsgBox "Cancelled"
End If
End If
End Sub

VBA - Paste Event and undo last action of Paste

I'm trying to make my excel to Paste Values instead of PasteAll by using VBA. But I'm not able to achieve it due to failure of the line :
lastAction = Application.CommandBars("Standard").Controls("&Undo").List(1)
I'm using code as below. Could anyone kindly help me to solve this? please correct my code as well if I'm wrong.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim lastAction As String
Application.ScreenUpdating = False
Application.EnableEvents = False
lastAction = Application.CommandBars("Standard").Controls("&Undo").List(1)
If Left(lastAction, 5) = "Paste" Then
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Undo
Selection.PasteSpecial Paste:=xlPasteValues
End If
End Sub
After including above code, I understood that this doesn't helps if the content copied was not from Excel. Below code helps to handle the data from both Office Clipboard and Windows Clipboard.
Office Clipboard - Paste as Values
Windows Clipboard - Paste as text
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim UndoList As String
Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo Whoa
'~~> Get the undo List to capture the last action performed by user
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
'~~> Check if the last action was not a paste nor an autofill
If Left(UndoList, 5) = "Paste" Or UndoList = "Paste special" Then
Application.ScreenUpdating = True
On Error GoTo 0
'~~> Undo the paste that the user did but we are not clearing the
'~~> clipboard so the copied data is still in memory
Application.Undo
'~~> Do a pastespecial to preserve formats
'~~> Handle text data copied from a website
'Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
'Target.PasteSpecial Paste:="Text", Operation:=xlNone, SkipBlanks:=False
Call Paste_Event
On Error GoTo 0
'~~> Retain selection of the pasted data
Union(Target, Selection).Select
End If
Application.EnableEvents = True
LetsContinue:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
Private Sub Paste_Event()
On Error GoTo Paste
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Exit Sub
On Error GoTo 0
Paste:
Selection.PasteSpecial Paste:="Text", Operation:=xlNone, SkipBlanks:=False
Exit Sub
End Sub
Here is the perfect solution which i found
Private Sub Worksheet_Change(ByVal Target As Range)
Dim UndoList As String
Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo Whoa
'~~> Get the undo List to capture the last action performed by user
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
'~~> Check if the last action was not a paste nor an autofill
If Left(UndoList, 5) = "Paste" Or UndoList = "Paste special" Then
Application.ScreenUpdating = True
On Error GoTo 0
'~~> Undo the paste that the user did but we are not clearing the
'~~> clipboard so the copied data is still in memory
Application.Undo
'~~> Do a pastespecial to preserve formats
'~~> Handle text data copied from a website
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
On Error GoTo 0
'~~> Retain selection of the pasted data
Union(Target, Selection).Select
End If
Application.EnableEvents = True
LetsContinue:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub

Why am i getting this error with copy/paste?

I am getting an error
Runtime error 1004: Application defined or Object defined error
in my vba code. Could you please help me correct it?
Sub INPUT_DATA()
' INPUT_DATA Macro
' Application.ScreenUpdating = False
Application.EnableEvents = False
Sheets("Input").Select
If Range("D55").Value = 0 Then
Range("B2:AI52").Select
Selection.Copy
Sheets("Database").Select
ActiveSheet.Range("A2").End(xlDown).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
Sheets("Input").Select
MsgBox ("File has been updated. DO NOT PRESS UPDATE again, as it will enter the same data once again")
End Sub
You didn't say which line is causing the error, but it looks like it's likely this line...
ActiveSheet.Range("A2").End(xlDown).Offset(1, 0).Select
It starts at A2, and then it goes down until it finds the last used row. However, if there aren't any used rows below A2, it finds the very last row in Column A. Then it tries to offset to one row below it, which doesn't exist, and hence the error. Instead, you can find the next available row as follows...
ActiveSheet.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Select
Although, there's no need to do all of that selecting. It's very inefficient. So your macro can be re-written as follows...
Option Explicit
Sub INPUT_DATA()
' INPUT_DATA Macro
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Dim sourceWorksheet As Worksheet
Set sourceWorksheet = Worksheets("Input")
Dim destinationWorksheet As Worksheet
Set destinationWorksheet = Worksheets("Database")
With sourceWorksheet
If .Range("D55").Value = 0 Then
.Range("B2:AI52").Copy
With destinationWorksheet
.Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
End With
End If
End With
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
MsgBox ("File has been updated. DO NOT PRESS UPDATE again, as it will enter the same data once again")
End Sub

Method 'List' of object 'CommandBarComboBox' failed

Method 'List' of object 'CommandBarComboBox' failed ---Earlier using 2011 mac excel, when updated to 2015 getting this error. desperatly required solution...
code is
Option Explicit
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim UndoList As String
Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo Whoa
'~~> Get the undo List to capture the last action performed by user
UndoList = Application.CommandBars("Standard").Controls("&Undo").List(1)
'~~> Check if the last action was not a paste nor an autofill
If Left(UndoList, 5) <> "Paste" And UndoList <> "Auto Fill" _
Then GoTo LetsContinue
'~~> Undo the paste that the user did but we are not clearing
'~~> the clipboard so the copied data is still in memory
Application.Undo
If UndoList = "Auto Fill" Then Selection.Copy
'~~> Do a pastespecial to preserve formats
On Error Resume Next
'~~> Handle text data copied from a website
Target.Select
ActiveSheet.PasteSpecial Format:="Text", _
Link:=False, DisplayAsIcon:=False
Target.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
On Error GoTo 0
'~~> Retain selection of the pasted data
Union(Target, Selection).Select
LetsContinue:
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub

Paste value based on index match

I'm attempting to get a macro(button click) to paste a value into another sheet if the value is not a formula. I'm not getting any errors with the below but the function won't fire. Thank you in advance for your help!
Sub Update_Numbers(ByVal Target As Range)
' Update_Numbers Macro
'
' Keyboard Shortcut: Ctrl+j
On Error GoTo Safe_Exit
Application.EnableEvents = False
Select Case Target.Address(0, 0)
Case Sheets("Wage Run").Range("B7")
If Target.HasFormula = False Then _
Sheets("wage run").Range("B7").Copy
Sheets("With Changes").Select
Range(Application.WorksheetFunction.Index(Sheets("With Changes").Range("E2:AB138"), Application.WorksheetFunction.Match(Sheets("Wage Run").Range("D1"), Sheets("With Changes").Range("A2:A138"), 0), 1)).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Select
Safe_Exit:
Application.EnableEvents = True
End Sub
EDIT: Changed with the below suggestions, but it still won't fire.
Sub Update_Numbers(ByVal Target As Range)
With Sheets("wage run")
' Update_Numbers Macro
'
' Keyboard Shortcut: Ctrl+j
On Error GoTo Safe_Exit
Application.EnableEvents = False
Select Case Target.Address(0, 0)
Case "B7"
If Target.HasFormula = False Then
Sheets("wage run").Range("B7").Copy
Sheets("With Changes").Select
Range(Application.WorksheetFunction.Index(Sheets("With Changes").Range("E2:AB138"), Application.WorksheetFunction.Match(Sheets("Wage Run").Range("D1"), Sheets("With Changes").Range("A2:A138"), 0), 1)).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
End Select
Safe_Exit:
Application.EnableEvents = True
End Sub
In addition to #Scott Craner's comment above: Note that the "If-Then" construct doesn't need any corresponding "End If" when you have only one statement on one line following "Then". But when the If construct contains more than one statement, as in your case, the code block must end with "End If". You have a line continuation symbol ( _) immediately after "Then". Try removing this and include an End If statement instead, like this:
Select Case Target.Address(0, 0)
Case Sheets("Wage Run").Range("B7")
If Target.HasFormula = False Then
Sheets("wage run").Range("B7").Copy
Sheets("With Changes").Select
Range(Application.WorksheetFunction.Index(Sheets("With Changes").Range("E2:AB138"), Application.WorksheetFunction.Match(Sheets("Wage Run").Range("D1"), Sheets("With Changes").Range("A2:A138"), 0), 1)).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
End Select
In addition to my comments above, here is a very minimal example that seems to do what you are asking for, but without any other context. It works on a workbook with (at least) two sheets. Maybe useful as a starting point.
Sub Macro1()
'
' Macro1 Macro
'
' Paste a value into another sheet if the value is not a formula.
Dim sourcecell As Range
Dim targetcell As Range
Set sourcecell = Sheets(1).Range("D8")
Set targetcell = Sheets(2).Range("D8")
If Not sourcecell.HasFormula Then targetcell = sourcecell
End Sub

Resources