VBA - Opening a workbook and remembering it for other macros - excel

I'd like to create a macro that will:
Open a browser window to select a saved workbook (let's call it WB1)
In the same macro assign WB1 some form of reference that will allow it to be referenced by other macros
I can achieve step 1 via the following code:
Sub Add_New_Survey()
Dim pathString As String
Dim resultWorkbook As Workbook
Dim found As Boolean
pathString = Application.GetOpenFilename(fileFilter:="All Files (* . xl*) , *.xl* ")
' check if it's already opened
For Each wb In Workbooks
If InStr(pathString, wb.Name) > 0 Then
Set resultWorkbook = wb
found = True
Exit For
End If
Next wb
If Not found Then
Set resultWorkbook = Workbooks.Open(pathString)
End If
End Sub
This will open the workbook. I then need to perform a number of data preparation activities on WB1 which I would like to automate. Is there a way to reference WB1 as I open it from the browser so the following macros know to look on WB1 specifically?
Many thanks

Welcome to SO. Your object resultWorkbook is linked to Workbooks.Open(pathString), so as long as you dont unlink it with Set resultWorkbook = Nothing, you can reference that workbook always on any sub, (but declare the variable as Public first in the module, outside of all subs).
To declare a Variable as Public, please read:
How do I declare a global variable in VBA?

Related

Open/Close Workbook in Userform

In a Userform I want to open another workbook (than the active one)
Part of my code:
Private Sub cmbKontoPos1_Change()
Workbooks.Open Filename:=filename1
'Here should of course be some code, but it is not now
Workbooks(filename1).Close SaveChanges:=False
Open-command works.
But the Close-command gives error:
Error no '9'
Index out of bounds
(I get the error-message in Swedish, hope I translate correct)
What is it I do not understand?
Quick fix is to have a global Workbook Variable so you can assign it on Open and use it on other UserForm Events, the example below has two Buttons and one opens while the other one closes the Workbook. Tested and working.
You can see the Dim secondWorkbook outside the UserForm buttons this is to make it global. On the first button I assign the Opened workbook to that Variable and i can close it later.
Dim secondWorkbook As Workbook
Private Sub CommandButton1_Click()
'Open WB
Dim filename1 As String
filename1 = "F:\WorkbookPath\WBName.xlsx"
Set secondWorkbook = Workbooks.Open(filename1)
End Sub
Private Sub CommandButton2_Click()
'Close WB
secondWorkbook.Close False
End Sub
You can also use this variable to make changes to the workbook like: secondWorkbook.Worksheets(1).Range("A1").Value = "Test" as long as it is still open of course.

Getting the workbook object of an add-in's referring workbook

I can create a code add-in by setting a workbook's .IsAddin property to True, and saving it in *xlam format.
I can then add this as a reference to any other workbook as such:
Sub Test()
Dim wb As Workbook
Set wb = Workbooks.Add
wb.VBProject.References.AddFromFile "PathToAddIn.xlam"
End Sub
The add-in's code procedures will then be available to call from within the main wb workbook.
However, what if when running a procedure in the add-in, I want to get the workbook object of the workbook which references the add-in?
For example, something like this:
Sub ThisProcedureIsWithinTheAddIn()
Debug.Print ThisWorkbook.Path ' Returns the path of this add-in (xlam) file
Dim ReferringWorkbook As Workbook
Set ReferringWorkbook = ThisWorkbook... ' How does one reference the caller/referrer?
End Sub
For the purpose of this question, assume that the code execution is in a completely separate thread, and the wb object (as originally created) no longer exists as a variable. In fact, in my application the wb has been created in an entirely separate New Excel.Application.
I realise I could go through each workbook in the application with For Each wb In Application.Workbooks, and find some relevant matching criterion. But that's a messy solution. Is there something more elegant?

Calling an opened workbook in VBA

this is what i currently have,
Dim mastertemp As Workbook
Dim testproject As Workbook
Set testproject = Workbooks("C:\Users\zzz\Documents\Test Project.xlsm")
Set mastertemp = Workbooks("C:\Users\zzz\Documents\MasterTemp.xlsx")
mastersheet.sheets("Sheet1").activate
the third line of code is giving me subscript out of range, any ideas?
I want to be able to jump between workbooks without the system giving me "workbook is already open, reopening would discard all changes etc"
I would do something like this:
Dim wbk as Workbook
Set wbk = Workbooks("Test Project.xlsm")
do stuff
Workbooks.Open ("C:\Users\zzz\Documents\MasterTemp.xlsx")
do stuff
wbk.Sheets("Dashboard").Activate
If you will always know the name of your workbook you can do
workbooks("Test Project").sheets("Dashboard").Activate 'add the file extension to the name if you've turned on file extensions in windows explorer
If the workbook name might be changing (or evening if it isn't, and you'll be referring to the workbook multiple times) then findwindow's suggestion is the way to go.
dim TestWorkbook as workbook
set TestWorkbook=Workbooks.Open ("C:\Users\zzz\Documents\Test Project.xlsm")
TestWorkbook.sheets("Dashboard").activate
I hope this helps.
If you know the workbook is already open, then refer to it by name in the Workbooks collection:
Dim testProject as Workbook
Set testProject = Workbooks("C:\Users\zzz\Documents\Test Project.xlsm")
testProject.Sheets("Dashboard").Activate
If you don't know whether the workbook is open, then you can use some error-handling logic, like:
Dim testProject as Workbook
On Error Resume Next
' Attempt to index this workbook from the open Workbooks collection:
Set testProject = Workbooks("C:\Users\zzz\Documents\Test Project.xlsm")
If Err.Number <> 0 Then
' If the above fails, then the workbook isn't open, so we need to open it:
Set testProject = Workbooks.Open("C:\Users\zzz\Documents\Test Project.xlsm")
End If
On Error GoTo 0

How to reference an opened not active workbook?

I want to reference from code in an active workbook to another workbook,
I don't want to type path like that workbooks("path") , this reference should be flexible, is there something like array of already opened workbooks ?
You can assign an open workbook to a variable without providing the full path. You can then use the set object variable to perform any actions you wish.
Sub set_wb()
Dim wb As Workbook
Set wb = Workbooks("test_wb.xlsb")
wb.Activate
End Sub
You can also iterate through each open workbook using for each
Sub wb_names()
Dim wb As Workbook
For Each wb In Workbooks
Debug.Print wb.Name
Next wb
End Sub
Similarly, you can use for to iterate through each workbook using their index (the index is dependant on which order workbooks were opened).
Sub wb_index()
Dim i As Byte
For i = 1 To Workbooks.Count
Debug.Print Workbooks(i).Name
Next i
End Sub
Hope this helps.
See this answer.
To reference an already open workbook, you can use
Workbooks("book_name.xlsx")
You can also iterate through the collection
Dim i As Integer
For i = 1 To Workbooks.Count
MsgBox Workbooks(i).Name
Next i

Copy entire worksheet from one instance of Excel to another

According to this article, you cannot move or copy worksheet from one instance of Excel to another. Unfortunately, it's the only way I have to make my program function properly.
I have 2 instances of Excel: one is run by our ancient ERP system and another through OLE call. The macros running in the second should copy first worksheet from opened workbook (ThisWorkbook) into workbook opened in the first instance (Wb). I'm using ForEachLoop's solution to get Wb:
Public Function GetExcelObjectFromHwnd(ByVal hWnd As Long) As Boolean
...
If AccessibleObjectFromWindow(hWnd, OBJID_NATIVEOM, iid, obj) = 0 Then 'S_OK
Dim objApp As Excel.Application
Set objApp = obj.Application
Dim Wb As Workbook
For Each Wb In objApp.Workbooks
ProcessWorkbook Wb
Next Wb
fOk = True
End If
...
End Function
Sub ProcessWorkbook(Wb as Worksheet)
...
'This produces error because ThisWorkBook and Wb are opened in different instances of Excel:
ThisWorkbook.Sheets(1).Copy , Wb.Sheets(1)
'What I developed so far
Wb.Sheets.Add , Wb.Sheets(1)
'this doesn't work too:
ThisWorkbook.Sheets(1).UsedRange.Copy Wb.Sheets(2).Range("A1")
'and this works but doesn't copy formatting:
With ThisWorkbook.Sheets(1).UsedRange
Wb.Sheets(2).Range("A1").Resize(.Rows.Count, .Columns.Count) = .Value
End With
' later I perform some operations with cells
...
End Sub
As you can guess, I first tried to use Worksheet.Copy method then Range.Copy method and they both don't work. And the direct range assignment copies only values and I need also formatting to be copied.
So, apparently, solution which will copy formatting is appropriate, but I'd prefer direct copying if there is any way to do it. Also, please don't suggest to use clipboard, as it is always bad idea.
I suggest you SaveAs your workbook from Excel instance A to a temp file, and then open this temp file in Excel instance B in order to copy the sheet you need.

Resources