I want to reference to the first opened Workbook. 2 workbooks are open: one that is calling the macro to execute, and the workbook which contains the macro. Somehow, the code runs smoothly very often. But sometimes, there occurs a referencing error when accessing data in the first opened workbook: Subscript Out Of Range.
On this line, the error occurs:
Set mastersheet = Workbooks(1).Sheets("Setting")
So there should be two workbooks in the collection. What am I overseeing? Please keep in mind, that the first opened workbook doesn't have a fixed name, so the name of the open workbook changes. The second Workbook, the workbook which contains the macro to execute, doesn't change it's name.
Unfortunately, you don't provide more code or any information about what kind of code "container" the macro is in. The following solution assumes the macro is in a Worksheet or Workbook code container (Sheet1 or ThisWorkbook in the VBA Editor, for example).
It's possible to get the workbook from the code container. If the code is in a Worksheet code container, then use Me.Parent. If it's in ThisWorkbook use Me. These containers are actually classes that represent the Worksheet / the Workbook object. So Me refers to that object. The parent of a Worksheet is its workbook.
So a Workbook object is set to its container workbook. Then the open workbooks are looped in a For...Each and the workbook is tested whether it's the same as the code container workbook, or if it's another. If it's another, then the loop is exited. Debug.Print shows the result (two different names) and demonstrates how to continue to work with the separate workbook objects.
Sub GetOtherWorkbook()
Dim wbWithMacro As Workbook
Dim wbOther As Workbook, wb As Workbook
Set wbWithMacro = Me.Parent 'Assumes macro is in a "Sheet" code container
'Set wbWithMacro = Me 'Assumes macro is in "ThisWorkbook" code container
For Each wb In Workbooks
If Not wb Is Me Then
Set wbOther = wb
Exit For
End If
Next
Debug.Print wbWithMacro.Name, wbOther.Name
End Sub
I suggest the following to find the Setting worksheet:
Option Explicit
Public Sub FindSettingWorksheet()
Dim MasterSheet As Worksheet
Dim wb As Workbook
For Each wb In Workbooks 'loop through all open workbooks
On Error Resume Next 'stop error reporting
Set MasterSheet = wb.Worksheets("Setting") 'if this throws an error it's the wrong workbook
On Error GoTo 0 're-enable error reporting
If Not MasterSheet Is Nothing Then Exit For 'if we found the setting worksheet we can exit/stop
Next wb
If Not MasterSheet Is Nothing Then 'test if we found it
Debug.Print MasterSheet.Name
Else
Debug.Print "Settings not found"
End If
End Sub
Related
I'd like to ask if you could help me with copying some worksheet data from workbook A into my active workbook (workbook B)
I have the following code in the main workbook to copy the data from workbook A
Public Sub Worksheet_Activate()
test
End Sub
Sub test()
Dim Wb1 As Workbook
Dim MainBook As Workbook
'Open All workbooks first:
Set Wb1 = Workbooks.Open("Z:\Folder\WorkbookA.xlsm")
'Set MainBook = Workbooks.Open(Application.ActiveWorkbook.FullName)
Set MainBook = Application.ActiveWorkbook
'Now, copy what you want from wb1:
Wb1.Sheets("Projekte").Cells.Copy
'Now, paste to Main worksheet:
MainBook.Worksheets("Projekte").Range("A1").PasteSpecial xlPasteAll
Application.CutCopyMode = False
'Close Wb's:
Wb1.Close SaveChanges:=False
End Sub
I know, that it opens worksheet A and that it highlights and copys the data.
The script wont paste it into worksheet B (where the script is executed from)
Anybody know what i did wrong?
Kindest regards, and thanks for any help !
You should set the Mainbook (destination) first before the origin (if you're going to use ActiveWorkbook).
'Set MainBook First
Set MainBook = ThisWorkbook
'Open All workbook:
Set Wb1 = Workbooks.Open("Z:\Folder\WorkbookA.xlsm")
Just for clarity, it's just me being OC on this one.
you have to properly reference your workbook and worksheet objects
if you have to paste the whole content of range (including formatting, comments, ...), then you want to code like follows (explanations in comments):
Option Explicit
Sub test()
Dim targetSheet As Worksheet
Set targetSheet = ActiveSheet 'store currently active sheet
Workbooks.Open("Z:\Folder\WorkbookA.xlsm").Sheets("Projekte").UsedRange.Copy Destination:=targetSheet.Range("A1") ' open the wanted workbook and copy its "Projekte" sheet used range to 'targetSheet (i.e.: the sheet in the workbook where it all started) from its cell A1
ActiveWorkbook.Close SaveChanges:=False ' close the currently active workbook (i.e. the just opened one)
End Sub
if you only need to paste values, then this is the way to go (much faster!):
Option Explicit
Sub test()
Dim targetSheet As Worksheet
Set targetSheet = ActiveSheet 'store currently active sheet
With Workbooks.Open("Z:\Folder\WorkbookA.xlsm").Sheets("Projekte").UsedRange ' open the wanted workbook and reference its sheet "Projekte" used range
targetSheet.Range("A1").Resize(.Rows.Count, .Columns.Count).Value = .Value
.Parent.Parent.Close SaveChanges:=False 'close the parent workbook of referenced range (i.e., the newly opened workbook)
End With
End Sub
My recommendation is never to use ActiveWorkbook.
In most cases when people use ActiveWorkbook they actually meant to use ThisWorkbook. The difference is:
ActiveWorkbook is the currently selected one which is "on top of the screen" in exact that moment when your code runs. That can be any workbook the user just clicked on while your code runs. So you never can be 100% sure to get the right workbook.
ThisWorkbook is the actual workbook your code runs at the moment. And this doesn't change ever. So this is a well defined reference and no gamble about which workbook is on top at the moment.
About why your approach did not work
Set Wb1 = Workbooks.Open("Z:\Folder\WorkbookA.xlsm") 'this line makes WorkbookA the active one
Set MainBook = Application.ActiveWorkbook 'this makes MainBook = WorkbookA
Therefore a simple Set MainBook = Application.ThisWorkbook should work here.
Another recommendation
Sheets and Worksheets is not the same. Make sure you never use Sheets when you can use Worksheets.
Sheets contains worksheets and charts
Worksheets contain only worksheets
An example Sheets(1).Range("A1") fails if it is a chart.
While this seems very basic, I am continually getting an error message while trying to select a cell in a certain sheet on my workbook in my Macro. Does any one know why this will not work? I'm getting error message Run Time Error '1004'.
The sheets name is "Sheet1"and my code is below:
Application.ActiveWorkbook.Worksheets("Sheet1").Range("N2").Select
It's bad practice to use ActiveWorkbook when you don't need to. It's always better to set your workbooks and worksheets to actual variables that you can call on. I think your code is activating another workbook then trying to select a range in a worksheet it can't find.
Sub TryThis()
Dim wbk As Workbook
Dim ws As Worksheet
Set wbk = Workbooks("myWorkbook.xlsm")
Set ws = wbk.Worksheets("Sheet1")
'Now when we say "ws." it is actually "Workbooks("myWorkbook.xlsm").Worksheets("Sheet1")."
'This is okay to start with but it's better to work with the cells directly
ws.Select
Range("N2").Select
Selection = "myText"
'This is much faster and you won't have to worry about what is currently selected
ws.Range("N2") = "myText"
End Sub
Sub debug_tester()
Dim A As Workbook
Set A = Workbooks.Open("D:\a.xlsm")
Dim B As Workbook
Set B = Workbooks.Open("D:\b.xlsm")
A.Sheets("sheet1_in_test").range("A1").Value = "test" 'pop out "subscript out of range" on this line
End Sub
And "sheet1_in_test" does exist in A. If I change it to number (i.e. sheet(1)) B is the one changed.
Edit:
Correct the typos. Workbook A has one sheet named "sheet1_in_test". Workbook B has one sheet named "sheet1".
Edit:
Thanks sancho.s! It seems like Workbook.Open cannot refer the workbook when the sub located on it. Using Set A = ThisWorkbook seems work, too. I'm wondering why is that.
This sub, located in a separate workbook, performs as intended
Sub open_test()
Dim wb1 As Workbook
Dim wb2 As Workbook
Set wb1 = Workbooks.Open("C:\Users\user1\Documents\a.xlsx")
Set wb2 = Workbooks.Open("C:\Users\user1\Documents\b.xlsx")
wb1.Sheets("Hoja1").Range("A1").Value = "test"
wb2.Sheets(1).Range("A1").Value = "test2"
End Sub
Try reproducing this.
Using Workbooks.Open() makes the opened workbook the active workbook. That's why using sheet(1) goes into workbook B. It's the last workbook opened and therefore the active workbook. Use Workbook.Activate to make A the active workbook.
Sub debug_tester()
Dim A As Workbook
Set A = Workbooks.Open("D:\a.xlsm")
Dim B As Workbook
Set B = Workbooks.Open("D:\b.xlsm")
A.Activate
A.Sheets("sheet1_in_test").range("A1").Value = "test"
End Sub
If you still get the "subscript out of range" message, the "sheet1_in_test" worksheet is not in the A workbook. Check the spelling between the code and the worksheet name. This assumes that you are running the code from a 3rd workbook.
If you are running this code from workbook A, Excel will close the open instance of A and reopen it but the code won't be running. In that case you can use
Set A = ThisWorkbook
Or if the code is in workbook B use
Set B = ThisWorkbook
I'm not the greatest with VBA and haven't touched it in years therefore I resort to tutorials so I hope somebody can help!
In the long run I'm trying to, in the following order:
Open an explorer window in one excel document via a button (Done!)
select an excel doc (Hopefully selected multiple docs in the long run)
pull info from a certain row/column of a sheet though to the original excel book
So far I've scoured/chopped and changed and found the following (Thanks JMax on this site)
Sub test()
Dim wb As Workbook, wb2 As Workbook
Dim ws As Worksheet
Dim vFile As Variant
'Set source workbook
Set wb = ActiveWorkbook
'Open the target workbook
vFile = Application.GetOpenFilename("Excel-files,*.xls", _
1, "Select One File To Open", , False)
'if the user didn't select a file, exit sub
If TypeName(vFile) = "Boolean" Then Exit Sub
Workbooks.Open vFile
'Set targetworkbook
Set wb2 = ActiveWorkbook
'For instance, copy data from a range in the first workbook to another range in the other workbook
wb2.Worksheets("Sheet1").Range("C3:D4").Value = wb.Worksheets("Sheet3").Range("A1:B2").Value
End Sub
To me this looks in order however when It opens the excel doc it comes back with the 'subscript out of range' message.
What Im I missing? The cells and naming seem correct to me :(.
Thanks,
Dave
The error is being thrown because a Worksheet name doesn't exist in on of the Worksheet Collections.
wb2.Worksheets("Sheet1")
Worksheets("Sheet3")
I am trying to create a copy of a large macro enabled (xlsm) file in xlsx format.
Sub Button1_Click()
Dim wb As Workbook
Set wb = Workbooks.Open("C:\original.xlsm")
Dim mySheetList() As String
ReDim mySheetList(0 To (ThisWorkbook.Sheets.Count) - 1)
Dim a As Integer
a = 0
For Each ws In ActiveWorkbook.Worksheets
mySheetList(a) = ws.Name
a = a + 1
Next ws
'actually save
Worksheets(mySheetList).Copy
ActiveWorkbook.SaveAs Filename:="ORIGINAL_COPY.xlsx" 'default ext
wb.Close
End Sub
I am getting subscript out of range error at following line:
mySheetList(a) = ws.Name
You are sizing the array with ThisWorkbook.Sheets but the loop use ActiveWorkbook.Worksheets. You need the same reference to avoid issues when multiple workbooks are opened.
You're using 4 different references to workbooks:
wb, ThisWorkbook and ActiveWorkbook are not necessarily the same thing. Furthermore, when you use Worksheets without prefixing it with a workbook reference, you're implicitly referencing the Activeworkbook. And, when you use Worksheets.Copy without any arguments, you're implictly creating a new workbook.
Currently, if ThisWorkbook has fewer sheets than original.xlsm, then your array will not be large enough to accommodate indexes larger than the count of sheets in ThisWorkbook. That is what is causing your out of bounds error.
I've adjusted the code. This will open the XLSM, copy the sheets, save the new XLSX workbook, and close the original XLSM, leaving the new XLSX workbook open.
Sub Button1_Click()
Dim wbOriginal As Workbook
Dim wbOutput As Workbook
Set wbOriginal = Workbooks.Open("C:\original.xlsm")
Dim mySheetList() As String
ReDim mySheetList(0 To (wbOriginal.Sheets.Count) - 1)
Dim a As Integer
a = 0
For Each ws In wbOriginal.Worksheets
mySheetList(a) = ws.Name
a = a + 1
Next ws
'Unfortunately, Worksheets.Copy isn't a function, so it doesn't
'return the workbook that it creates, so we have to execute the
'copy, then find the activeworkbook
Worksheets(mySheetList).Copy
Set wbOutput = ActiveWorkbook
'actually save
wbOutput.SaveAs Filename:="ORIGINAL_COPY.xlsx" 'default ext
wbOriginal.Close
End Sub
Why bother with all that looping?
Sub MM()
Dim sourceWB As Excel.Workbook
Set sourceWB = Workbooks.Open("C:\Original.xlsm")
sourceWB.SaveAs "C:\ORIGINAL_COPY.xlsx", FileFormat:=xlOpenXMLWorkook
sourceWB.Close False '// Optional
End Sub
The .SaveAs() method would be far more effective.
As mentioned in other answers, your issue seems to be with wb, ActiveWorkbook and ThisWorkbook being used interchangeably when they are actually different things.
wb is a workbook object that has been set to "C:\original.xlsm". It will always refer to that workbook unless you close the workbook, empty the object, or assign a new object to it.
ActiveWorkbook refers to the workbook that is currently active in Excel's forefront window. (i.e. The workbook you can see on your screen)
ThisWorkbook refers to the workbook in which the currently executing code belongs to. To quickly explain the difference:
Workbook A is the only workbook open, and has some code in to open another workbook (let's call it Workbook B).
At the moment, Workbook A is the ActiveWorkbook.
The code in workbook A starts running, workbook A is now the ActiveWorkbook and ThisWorkbook (because the running codes resides in this workbook)
The code opens Workbook B, which naturally opens in the forefront of Excel. Now Workbook B is the ActiveWorkbook and Workbook A is still the ThisWorkbook
Hopefully that clears it up a bit for you...