Excel 2013 VBA: Subscript out of Range (Error 9) - excel

So I have this code:
Sub CopyItems()
Dim Source As String
Dim Target As String
'Dim SourceSheet As String
'Dim TargetSheet As String
Source = "Source.xlsm"
Target = "needChange.xlsm"
'SourceSheet = "Sprint backlog"
'TargetSheet = "Sheet1"
Workbooks(Source).Sheets("Sprint backlog").Range("B6:B15").Copy
Workbooks(Target).Sheets("Sheet1").Range("A14:A23").Paste '<-ERROR here
End Sub
And it's giving me the Run-time error '9' as expressed in the title. The code is so simple that I am completely stumped.
I read around the net and it seems it's because of names that don't exist, however both the sheets and workbooks exist, with identical names. There is no space or weird char between any of the code.
Basically I want to Copy a column ranging from B6 to B15 from the sheet "Sprint backlog" in Source.xlsm to the range A14 to A23 in Sheet1 of needChange.xlsm
I tried, without any luck:
Workbooks(Source).Sheets("Sprint backlog").Range("B6:B15").Copy _
Workbooks(Target).Sheets("Sheet1").Range("A14:A23").PasteSpecial
And also modified code with what's now commented out.
I suspect the Macro can't access the target file (needChange.xlsm) because it can't find it or can't access it and therefore return the problem, but i cannot figure out how to fix it with code..
If it helps, while running the macro, both of the Workbooks in this code were open and accessible for me.
I am turning to you for help.
Big thanks.
Best Regards.

This was trickier than expected. I borrowed heavily from this web page http://ccm.net/faq/24666-excel-vba-copy-data-to-another-workbook.
I had to add references to the sheets for the copy and paste to get it to work.
The code as posted requires both workbooks to be open, but you can have wbTarget get opened if you give it a pathname. In that case you could comment out the two lines that appear after the -OR-.
The code can also save and close the target workbook as well.
Sub CopyOpenItems()
'
' CopyOpenItems Macro
' Copy open items to sheet.
'
' Keyboard Shortcut: Ctrl+Shift+O
'
Dim wbTarget As Workbook 'workbook where the data is to be pasted
Dim wbThis As Workbook 'workbook from where the data is to copied
Dim strName As String 'name of the source sheet/ target workbook
'set to the current active workbook (the source book)
Set wbThis = ActiveWorkbook
'get the active sheetname of the book
strName = ActiveSheet.Name
'open a workbook that has same name as the sheet name
'Set wbTarget = Workbooks.Open("C:\YourPath\needChange.xlsm")
' - OR -
Workbooks("needChange.xlsm").Activate
Set wbTarget = ActiveWorkbook
'select cell A1 on the target book
'wbTarget.Range("A1").Select
'clear existing values form target book
'wbTarget.Range("A1:M51").ClearContents
'activate the source book
wbThis.Activate
'clear any thing on clipboard to maximize available memory
Application.CutCopyMode = False
'copy the range from source book
wbThis.Sheets("Sprint backlog").Range("B6:B15").Copy
'paste the data on the target book
wbTarget.Sheets("Sheet1").Range("A14").PasteSpecial
'clear any thing on clipboard to maximize available memory
Application.CutCopyMode = False
'save the target book
'wbTarget.Save
'close the workbook
'wbTarget.Close
'activate the source book again
wbThis.Activate
'clear memory
Set wbTarget = Nothing
Set wbThis = Nothing
End Sub

if you copy only values (and no formula, picture, formating), a simple
Workbooks(Target).Sheets("Sheet1").Range("A14:A23").value = Workbooks(Source).Sheets("Sprint backlog").Range("B6:B15").value is good.
(in one same code line, only the size of the window here makes it look beeing on 2).
for more than values :
Workbooks(Source).Sheets("Sprint backlog").Range("B6:B15").Copy _
Workbooks(Target).Sheets("Sheet1").Range("A14:A23").
(in 2 lines)
note : the _ means that the folowing line is meant to be on the same line , and is only there for reading the code more easily purpose . (you made that error in your second code)
note 2 : range().paste does not exist , only sheets().paste , or range().pastespecial.
note 3 : of course, all worbooks, and sheets, must exist and have the same exact name than those used...
note 4 : copy/paste works ONLY if both workbooks are already opened. for closed files it's a different story.
To make it short, you made 2 mistakes : _, and range().paste.

Related

Workbook.close causes sub to exit

I have a set of versioned Excel documents that I am trying to get to auto-update when there is a new version available. What fails is that the .close method is not just closing one of the workbooks but also exiting the sub.
The process:
The sub gets called from Worksheet_Activate and immediately checks to see if an upgrade is needed. If needed, it collects all of the names of the sheets (except the "Count" sheet which is a copy from a template), creates a new workbook with the same sheets as the old one, copies the data over to the proper sheets, closes the old workbook, deletes the old workbook, saves the new workbook with the same name as the old workbook.
Pretty straight forward and it worked great until it didn't. I'm not sure why, but now when the wkbFrom.Close command is executed it also exits the procedure.
I've been digging around and the only answer I could find that seemed to address my issue was to give some delay before/after the close so that Excel will have time to finish and not collide with itself. So I tried putting in a 5 second delay before the close command but to no avail.
Excel doesn't crash, it's still up and running properly. I checked the Event Viewer and Excel is not throwing any errors. The sub simply closes the workbook and then exits the sub.
Here is the full code for the sub.
Sub UpgradeHWWorkbook(Optional HWSheetVersion As Double)
'--------------------------------
'This sub upgrades a hardware tracking
'workbook to the newest version based on
'version in the variable HWSheetVersion
'--------------------------------
'Before anything else, Check to see if upgrade is needed.
'If sheet version is equal or larger than the plugin version
'OR the name of the sheet is wrong, exit without upgrading
'---------------------------------------------------------------------
If HWSheetVersion >= HWPlugInVersion Or _
Not ActiveSheet.CodeName Like "BaseHWSheet_*" Then
Exit Sub
End If
'---------------------------------------------------------------------
'VAR declarations----------------
Dim wkbFrom As Workbook 'Holds the original workbook
Dim wkbTo As Workbook 'Holds the new workbook
Dim sWKB As Workbook 'Holds Workbook where Count sheet is kept
Dim sWKS As Worksheet 'Holds Count sheet
Dim wks As Worksheet 'Holds worksheets
Dim wksNames() As String 'Holds the names of all the worksheets
Dim wkbFromName As String 'Holds the name of the original workbook
Dim wkbFromPath As String 'Holds the path of the original workbook
Dim wkbToPath As String 'Holds the path where the new workbook will be saved
Dim rng As String 'Holds the range of cells that will be copied
Dim x As Byte 'Holds counter
Dim wksName As Variant 'Holds the name of the current worksheet
'--------------------------------
'Sub Settings--------------------
Set wkbFrom = ActiveWorkbook 'Set the active workbook as the one that the data comes from
wkbFromPath = wkbFrom.Path 'Grabs the path of the original workbook
wkbFromName = wkbFrom.Name 'Grab the original workbook name
wkbToPath = wkbFrom.FullName 'Grab the path path and name in another var so we don't have to do it by hand
ReDim wksNames(0) 'Starts off the array that will hold the worksheet names
x = 0 'Flush the counter
rng = "A2:D18" 'The range of cells that will be copied and pasted
Application.DisplayAlerts = False 'Turn off annoying pop-ups
Set sWKB = Workbooks("StockroomAddins.xlam") 'Workbook with Count sheet to copy to new workbook
Set sWKS = sWKB.Worksheets("Count") 'Count sheet to copy to new workbook
'--------------------------------
'Get all of the worksheet names (except Count) in the workbook
'-----------------------------------------------------------------------
For Each wks In wkbFrom.Worksheets 'itenerate through the book
If Not wks.Name = "Count" Then 'If the worksheet isn't the "Count" sheet...
wksNames(x) = wks.Name 'add the sheet name to the array wksName()
x = 1 + UBound(wksNames) 'Increase the array by 1
ReDim Preserve wksNames(x) 'Increase the size of the array by 1
End If
Next wks
'-----------------------------------------------------------------------
'Create new workbook & add Count sheet
'-----------------------------------------------------------------------
Set wkbTo = Workbooks.Add 'Create the new workbook
wkbTo.Activate 'Make sure new book is active book
sWKS.Copy Before:=Sheets("Sheet1") 'Add the Count sheet to workbook
'-----------------------------------------------------------------------
'Iterate through the sheets in the original workbook, add sheets with the same name to the new book, copy data from the old sheet to the new sheet
'-----------------------------------------------------------------------
For Each wksName In wksNames 'Loop through all of the worksheet names and...
If Not wksName = "" Then 'If it isn't blank...
Call NewHardwareTrackingSheet(wksName, wkbTo) 'Call the sub that creates a new tracking sheet
wkbFrom.Worksheets(wksName).Range(rng).Copy 'Copy the data from the old sheet
wkbTo.Worksheets(wksName).Range(rng).PasteSpecial _
Paste:=xlPasteValues 'Paste the data (Values only) into the new sheet
End If
Next wksName
wkbTo.Worksheets("Sheet1").Delete 'Delete the default "Sheet 1" that every new workbook has
wkbFrom.Close Savechanges:=False 'close the original workbook
'-----------------------------------------------------------------------
'Delete the old workbook and save the new one in the same place with the same name as the old one
'-----------------------------------------------------------------------
Kill wkbToPath 'Kill the original
wkbTo.SaveAs Filename:=wkbToPath, FileFormat:=52 'Save the new as the original
Application.DisplayAlerts = True 'Turn annoying pop-ups back on
'-----------------------------------------------------------------------
'Clean up-------------------------------------
Set wkbFrom = Nothing: Set wkbTo = Nothing: Set sWKB = Nothing
Set wks = Nothing: Set sWKS = Nothing
'---------------------------------------------
End Sub
Any ideas on what I've messed up? I figured that since it worked at one point and now doesn't, that I've probably messed up the code somewhere but I'm not seeing it.
OK, I found my answer and I feel a bit stupid about it. Thanks to the folks who asked me some questions because they caused the thought process that worked.
It seems that the spreadsheet I was using to test the code must have gotten corrupted. I tried it on a couple of other files and it worked correctly. No wonder I couldn't find a code issue: there isn't one.
Goes to show the old adage "Measure twice, cut once." I should have tested on multiple files and not assumed my single test file was right.
Much thanks to those who read, thought about, and commented on my post. It is appreciated.
EDIT: Or not......
Came in this morning and it's not working again. There's got to be something in my code that is causing the issue on some and not on others. TBH, I have no idea what it is.
This is really causing me to bang my head on the wall.
OK, so I think I've figured this out.
I am calling this Sub to check the version each time a sheet is activated with this:
Public Sub Worksheet_Activate()
Application.Run "StockroomBarcodeSheets.UpgradeHWWorkbook", HWSheetVersion
End Sub
To do some other testing, I set up another sub inside my plug-in that just called the UpgradeHWWorkbook sub with a fake HWSheetVersion so I could force a workbook to upgrade. Lo, and behold, this setup worked perfectly every time.
So, when I call from the Worksheet_Activate() it exits on the .close command. When I call it from a sub inside the add-in, it works perfectly.
Because the UpgradeHWWorkbook is in a plug-in I thought that the restriction upon closing the calling workbook wouldn't come into affect. I was wrong.

How to copy data from closed worksheets in folder when sheet name changes?

I have set up a macro that runs when a button is clicked. The macro checks a specified folder and pulls in the data from all of the workbooks contained in the folder into the active workbook.
The code worked perfectly however, there are new worksheets being added where the tabs have slightly different numbers at the beginning meaning the code no longer works.
Is there a way to make the macro collect all data regardless of the sheet name? (There will only ever be one sheet per workbook)
I have written the code which worked when the sheet name was always the same, however, when this changes the code no longer runs.
Do While Len(fl) > 0
' Open file
Set dWb = Workbooks.Open(fDir & fl)
' Copy data from
dWb.Sheets("DailyReport").Range("A2:AU100").Copy mSh.Cells(1, nxtCol)
' Close workbook
dWb.Close SaveChanges:=True
' Increment column counter
nxtCol = nxtCol + 7
' Go to next file
fl = Dir
Loop
Run-time error '9':
Subscript out of range
If there is only one sheet:
Set dWb = Workbooks.Open(fDir & fl)
dWb.Worksheets(1) 'this selects the first sheet in the workbook
I hope this helps
Try use activeSheet; hard or str variable:
dWb.Worksheets(ActiveSheet.Name)
Dim ash as String
ash = ActiveSheet.Name
dWb.Worksheets(ash)

VBA: Paste ceases to work (suddenly) in specific macro

I'm a very new, self-taught programmer, so please keep this in mind in your responses. I have extensively searched this and other forums and can't seem to find a similar question.
The following code has been working for weeks and has not been changed. (My macro includes more variables and code, but I know from taking it apart that those pieces work, so I've left them out for clarity). From what I can tell the PasteSpecial function is specifically not working.
Dim StimSheet As String
ActiveCell.Rows("1:290").EntireRow.Select
Selection.Copy
'Copies the data for the current stimulus
StimSheet = Application.InputBox("Enter the name of the stimulus")
'asks name of the stimulus
Sheets.Add After:=Worksheets(Worksheets.Count)
ActiveSheet.Name = StimSheet
'adds new sheet at the end and names whatever you input as stimulus name
Sheets(StimSheet).Select
Selection.PasteSpecial Paste:=xlPasteValues
'pastes data into new sheet
At this point there is no error, the macro simply stops after copying and creating the new sheet.
Here's what I know / have tried:
The macro is successfully making and naming the new sheet and copying the selection to the clipboard, because I can manually paste it after running the macro. It seems to be getting stuck at the paste piece.
Other macros that use the exact same format of copy / paste special are still working correctly.
Another forum with a similar program suggested typing "Application.EnableEvents=True" into the immediate window. This did not change anything.
This macro has worked for several weeks with no errors. I have made new macros using previously saved code in case something inadvertently was changed in the current one, but this did not work either.
The paste option will work one time on a new file and then ceases to work again.
Thank you in advance for your suggestions.
You might find the problem is that you don't have much control over which workbook and worksheet this code applies to. It's better to avoid ActiveSheet, Select, and Sheet with no parent as much as you can.
If you only need to copy the values of cells without any formatting, then Paste isn't needed either.
Try changing your code to the following and see if you have any better luck:
Const BOOK_NAME As String = "Book1.xlsm" 'change this to your workbook name
Const SOURCE_SHEET_NAME As String = "Sheet1" 'change this to your sheet name
Dim wb As Workbook
Dim sourceSheet As Worksheet
Dim newSheet As Worksheet
Dim newSheetName As String
Dim validName As Boolean
Dim rng As Range
' Set the book, sheet and range objects
Set wb = Workbooks(BOOK_NAME)
Set sourceSheet = wb.Worksheets(SOURCE_SHEET_NAME)
Set newSheet = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
' Acquire the new sheet name and check it's valid.
Do
newSheetName = InputBox("Enter the name of the stimulus")
On Error Resume Next
newSheet.Name = newSheetName
validName = (Err.Number = 0)
On Error GoTo 0
If Not validName Then MsgBox "Sheet name isn't valid. Try again."
Loop Until validName
' Write the values into the new sheet
Set rng = sourceSheet.Cells(1, 1).Resize(290, sourceSheet.UsedRange.Columns.Count)
newSheet.Range(rng.Address).value = rng.Value2
I moved this line:
StimSheet = Application.InputBox("Enter the name of the stimulus")
to the top of the method and it seems to work reliably. I wish I could tell you exactly why, but at least you can proceed. Perhaps it has something to do with the focus changing.
Also, when it failed for me (Office 2013) I got the following error:
Run-time error 1004:
Application-defined or object-defined error.
When the Sub was in a Sheet code behind, and this:
Run-time error '1004'
PasteSpecial method of Range class failed.
When pasted in a Module.

Copy one worksheet to multiple identical workbooks using VBA

I have a workbook containing one worksheet ("DB Output" or Sheet 34) which I would like to copy to several (around 45) files in within the same folder.
None of the target files have an existing sheet named "DB Output" - the objective is to find a way to insert a copy of this sheet, forumlas and all, into each one.
The range of cells on that sheet that needs to be copied to a sheet of the same name in each book is A1:PE5
The sheet contains references to cells in the book it is currently in, however as the files which I am seeking to copy the worksheet to all share the same template, I want the references to be to the local file, not the original one.
I've tried looking at RDBMerge, however it seems that is for merging sheets, and while I do want to do that, it will not help me do it multiple times quickly.
Likewise I have looked on SO for similar situations, this is the closest, however my attempts to adapt that code have failed as I only have a single workskeet. Never the less, as it is always useful to inlcude what you have already tried, here is my existing attempt:
Option Explicit
Public Sub splitsheets()
Dim srcwb As Workbook, trgwb As Workbook
Dim ws As Worksheet, t1ws As Worksheet
Dim rng1 As Range
Dim trgnm As String
Dim fpath As String
Application.ScreenUpdating = False
'--> Set this to the location of the target workbooks
fpath = "C:/file/path/"
Set srcwb = ThisWorkbook
For Each ws In srcwb.Worksheets
trgnm = ws.Name
'--> Change A1:B3 to the range to be copied to inside page
Set rng1 = srcwb.Sheets(trgnm).Range("A1:PE5")
Set trgwb = Workbooks.Open(fpath & trgnm & ".xlsm")
With trgwb
Set t1ws = .Sheets("DB Output")
End With
'--> Change A1:B3 to the range where you want to paste
rng1.Copy t1ws.Range("A1:PE5")
trgwb.Close True
Next
Application.ScreenUpdating = True
End Sub
However this starts with the first sheet in the workbook that contains DB Output (the sheet to be copied) and gives an error that "NameOfSheet1.xlsm" does not exist in that directory (which it does not).
Any help is much appreciated.
This should copy from the active workbook to all files in a directory. If you need help modifying it to fit your specific use let me know!
Edit: fixed code to only copy A1:PE5 and save each workbook.
Sub Example()
Dim path As String
Dim file As String
Dim wkbk As Workbook
path = "C:\Test\"
file = Dir(path)
Application.DisplayAlerts = False
Do While Not file = ""
Workbooks.Open (path & file)
Set wkbk = ActiveWorkbook
Sheets.Add After:=Sheets(Sheets.Count)
ActiveSheet.Name = "DB Output"
ThisWorkbook.Sheets("DB Output").Range("A1:PE5").Copy Destination:=wkbk.Sheets("DB Output").Range("A1")
wkbk.Save
wkbk.Close
file = Dir
Loop
Application.DisplayAlerts = True
End Sub
Please note that I did not add error handling so this could break if the active workbook is included in the directory you are trying to copy or if a sheet with the same name already exists in the workbook. If this is an issue let me know and I will add error handling.

Excel vba code for updating workbook from external worksheet

Yet another worksheet copying problem! This is a simple problem that has got me stumped. I want the click of a command button (in action.xlsm) to repopulate the values in a range ("stock" - 2 cols & maybe 100 rows - this is the master inventory records) in a separate excel file (inventory.xlsx), from a named range ("newInventory" - same size as other named range) in the active worksheet (in action.xlsm) that has had the original "stock" values reduced by the values of items taken out of stock. The calculations are OK I just can't get the master inventory file to update. I have checked heaps of forums and tried two approaches to no avail. I have tried:
Private Sub CommandButton1_Click()
Dim InventoryFileName As String
InventoryFileName = "C:\Users\david\Documents\inventory.xlsx"
Workbooks(InventoryFileName).Worksheets("Sheet1").Range("stock") = ThisWorkbook.Worksheets("inventory").Range("newInventory").Value
Workbooks(InventoryFileName).Save
End Sub
Throws a "Run-time error '9': Subscript out of range" on line 4. I have also tried:
Private Sub CommandButton1_Click()
Dim wbTarget As Workbook 'workbook where the data is to be pasted
Dim wsTarget As Worksheet
Dim wbThis As Workbook 'workbook from where the data is to copied
Dim wsThis As Worksheet
Dim strName As String 'name of the source sheet/ target workbook
'set to the current active workbook (the source book)
Set wbThis = ActiveWorkbook
Set wsThis = ActiveSheet
'get the active sheetname of the book
strName = wsThis.Name
'open a workbook that has same name as the sheet name
Set wbTarget = Workbooks.Open("C:\Users\david\Documents\" & strName & ".xlsx")
Set wsTarget = wbTarget.Worksheets("Sheet1")
'select cell A1 on the target book
wbTarget.wsTarget.Range("A1").Select
'clear existing values form target book
wbTarget.wsTarget.Range("A1:B10").ClearContents
'activate the source book
wbThis.Activate
'clear any thing on clipboard to maximize available memory
Application.CutCopyMode = False
'copy the range from source book
wbThis.wsThis.Range("A1:B10").Copy
'paste the data on the target book
wbTarget.wsTarget.Range("A1").PasteSpecial Paste:=xlPasteValues
'clear any thing on clipboard to maximize available memory
Application.CutCopyMode = False
'save the target book
wbTarget.Save
'close the workbook
wbTarget.Close
'activate the source book again
wbThis.Activate
'clear memory
Set wbTarget = Nothing
Set wbThis = Nothing
End Sub
This throws a "Run-time error '438': Object doesn't support this property or method" on line wbTarget.wsTarget.Range("A1").Select
What have I got wrong? Any suggestions?
Replace
wbTarget.wsTarget.Range("A1").Select
with just
wsTarget.Range("A1").Select
The workbook is already implied from the way you defined wsTarget. I suspect that will do it. If you run the code in the debugger, then when you do a "watch" on the variable you can see exactly what does and doesn't work..
Firstly you have 2 commandbutton1. Secondly you must have a reference for a Range like:
Workbooks(InventoryFileName).Worksheets("Sheet1").Range("A3:B21") = ThisWorkbook.Worksheets("inventory").Range("A10:B12").Value
or
stock="A3:B21"
newInventory="A10:B12"

Resources