Excel Collection Variable - excel

Let's say we have two workbooks identical with respect to the VBA functionality; however, the data-sets will be different. The VBA code stores some data on a collection variable to facilitate calculations. This variable is called via different modules inside the same workbook. As this variable also exists on the other workbook and these two workbooks should not share the same collection values, how can we make sure the call for collection will only pull the variable from its own workbook?
Will the declaration "Option Private Module" be adequate when declaring the collection variable? Such as:
Option Private Module
Public DataCol As New Collection
Thanks.

Yes.
Declaring the module as Option Private Module will restrict the scope of "Public" variables declared in that module to that specific project. This is similar to Friend scope in classes, and analogous to internal static in .NET.

Unlikely to be an issue...
Let's say you have two identical workbooks:
Book1.xlsm, and,
Book2.xlsm
...and both have a Public Variable setup identically, named X.
Unless you have explicitly set a Reference from Book1 to Book2, then Book1 cannot "see" X or other variables/constants/etc that exist within Book2.
For example, one way of setting a the reference would be if in Book1 you went Tools > References > Browse and selected workbook Book2.xlsm.
Even if you did set a reference between the workbooks, and both have a variable named X, Book1 will always look for an X in within itself before looking elsewhere. You would have to qualify the variable like:
Applications.Workbooks("Books2.xlsm").X
This applies to all references; If you have something in your workbook named the same as a "connected" reference, code running in your workbook "looks" first within the procedure, then within the module, then within the workbook, before looking externally to connected references.
Its very unlikely that VBA will refer to a variable in the wrong workbook.
If you often have two identical workbooks open, it's much more likely that you will accidentally write or execute code in the wrong workbook, (I've done it, it's annoying - especially when you close & delete the "garbage workbook", that you actually accidentally just wrote a bunch of code in!)
There should not be very many situations where you have two identical workbooks open; if this is regular practice there is probably a better way to organize your data storage process.
Ranges
Note that the same does not apply when referring to worksheet ranges, etc., with unqualified references.
For example, Range("A1") refers to whatever worksheet is "on top" (ie., the last workbook that was clicked, selected, or otherwise activated.
This is why it's important to qualify range references. One example of a fully qualified range reference is:
ThisWorkbook.Sheets("Sheet1").Range("A1")
Scope
This discussion falls into the category of Scope.
Read more about what scope is and how to use it to your benefit (and prevent problems) in these links:
Chip Pearson : Understanding Scope of Variables and Procedures in VBA
MS Office Support : Scope of variables in Visual Basic for Applications
analysistabs.com : Scope of Variables in Excel VBA
Truly Global Variables
Incidentally, there's also a way to create truly Global Variables, that can be referenced by other (non-Office) applications, and even after your application has closed and/or re-opened.
It takes some fairly advanced coding since it involves Windows API's, but Chip Pearson has the steps and sample code available here.

Related

ActiveWorkbook.Saved versus ThisWorkbook.Saved versus Me.Saved

I write Excel VBA reports that tap into SQL databases. I'm also in a company that uses dozens of such reports, and any user could have multiple such reports open at once from multiple different sources. Because of this, it is paramount that code does not affect or interfere with any other open workbooks.
My current report unavoidably uses volatile functions, so users that open and then immediately close the file will get prompted with a Save? dialog. Searching online has always pointed to using
Private Sub Workbook_Open()
ActiveWorkbook.Saved = True
End Sub
While effective, I've never been a big fan because of the non-specific nature of "ActiveWorkbook".
Question:
What are the pros/cons/pitfalls of using any of the following options-
ActiveWorkbook.Saved
ThisWorkbook.Saved
Me.Saved
Something_I_haven't_thought_of.Saved
ActiveWorkbook
I would argue that there are no pros to using ActiveWorkbook, as a direct reference to what you're working with should always be preferable, especially in the case stated above where multiple workbooks are involved. Even in the event of opening and working with arbitrary workbooks whose names you don't specifically know (via a FSO or Dir() loop), you can always set a workbook variable equal to the return value of a Workbook.Open function.
ThisWorkbook
Any time you have code working with more than one workbook or even code working with one workbook while multiple workbooks are open, I would recommend ThisWorkbook. It is versatile in that it can be used in object code modules and generic modules to return a consistent reference to the workbook it is placed within. There really aren't any cons to explicitly specifying ThisWorkbook when that's what you mean to reference.
Me
Me and ThisWorkbook are interchangeable when using them inside the ThisWorkbook object code module, but outside of that, Me refers to the object which it is placed within. For instance Me.Name inside a worksheet object code module will get you the name of the worksheet. Doing the same inside the workbook code module will get you the name of the workbook.
For the sake of clarity and re-usability, I would personally recommend ThisWorkbook out of all 3.
Active workbook is the workbook that is in use/activated (hence can change during code execution) and thus less reliable.
This workbook is the workbook on which the code is run. Hence, a good option if that is the workbook you want to refer to.
"Me" refers to where the code is. E.g. if in sheetmodule, it refers to that sheet, if in a userform module it refers to that module, if in thisworkbook module it is the same as 'thisworkbook', etc.
Defining a variable as workbook can refer to any open workbook. Can be redefined as desired in the code and hence very flexible as long as you know the name of the book
Application.DisplayAlerts = False can be used to suppress save/overwrite requests. Which can be very handy if you do not want users to receive a prompt.
Do re-enable as this is a powerful yet 'dangerous' piece of code.

Working with Changing Named Ranges Excel VBA

I am writing a fairly lengthy macro in Excel VBA. I want to use named ranges instead of specifying it in the macro. This macro is intended for long-term use. What happens if the range shifts by another user? How can I adjust my code so my named ranges can accommodate for changing positions?
I (personally) hate named ranges. Especially, when you are copying or pasting sheets / ranges from one file to another you always end up with dead-references or copied over named ranges which do not work anymore or got renamed (because they existed already in that file).
My solution to this is one of the following two:
(1) I dedicate a certain part (or even module) in the VBA to declaring my ranges in global variables. This is very similar to the Dim of all variables at the beginning of each sub.
'*********************************************************
'** Declaring all ranges and where to find which data
'*********************************************************
Dim rngNamedRangeName As Range
Sub SetupAllGlobalVariables()
Set rngNamedRangeName = ThisWorkbook.Worksheets(1).Range("A1:C10")
End Sub
'*********************************************************
'** After that all your normal subs follow and whenever
'** necessary you can call the above to get your ranges
'*********************************************************
Sub ExampleCodeToFormatYourRanges()
Call SetupAllGlobalVariables
With rngNamedRangeName
.Interior.ColorIndex = 36
End With
End Sub
(2) Yet, my preferred second solution is to have a separate very hidden sheet where I reference / link all the ranges (which are important to me) again. So, basically, I have in this separate sheet all the "important" data again. This would be your named ranges. But nobody is allowed to touch this sheet (that's why its very hidden). If any of your ranges get shifted or changed then it is easy to re-link the ranges on this hidden sheet with the other sheets again. Yet, on the hidden sheet all data is still in the same spot and allows you to hard-code all ranges in your VBA (taken from the hidden sheet only).
Even non-VBA programmers can normally fix such things with the second method. With the first method you'll probably always need someone with VBA skills to fix it.
Note, the above is not the one and only solution nor might it be the best solution. But I can certainly say that this has proven to be a usable solution even for larger corporations.

Excel/VBA workbook.activesheet returns wrong sheet

I have a workbook (we'll call it "AAA") that is based on a template and refers to code modules in a second workbook. The second workbook (we'll call it "CodeStorage") is a repository for code modules so that any saved versions of the template will be able to access modified/updates code without a change to the saved workbook.
My problem arises when I have multiple windows open in "AAA" and try to get the activesheet when a module is running in "CodeStorage". In code, I create an object ("oWorkbook") that is a reference to the workbook "AAA" When "AAA" has focus, oWorkbook.Activesheet returns the sheet for the active window. When "CodeStorage" is running a module and thus has focus, oWorkbook.Activesheet returns the sheet that is selected in window #1 regardless of what window (#2, 3, etc) was active when the code module in "CodeStorage" was called.
Has anyone run into this and have you found a work around?
ActiveSheet is confusing the way you are using it.
You need to explicitly activate a sheet for it to be considered the ActiveSheet. Running code in another workbook does not activate it.
Selecting cells in a worksheet will activate it. Or specifically calling Activate.
You could do something like:
oWorkbook.Activate
oWorkbook.Activesheet
Alternatively, and preferably, you could do something like the following:
oWorkbook.Worksheets("Sheet1")
oWorkbook.Worksheets(1)
Both these are better. If your user selects a different workbook during runtime execution or you select something in a different sheet, ActiveSheet will return something different.
It's better to fully qualify you workbook paths when using multiple workbooks. This will save you a ton of headache in the future for dealing with "what is activated?" or "what is selected?" This answer is worth reading, too.
To rephrase my question, I was looking for a way to reference the last active worksheet in a workbook that had multiple windows open. If window 1 was selected, I wanted the sheet from window 1, same for window 2, 3, or ???. I also needed the reference when a code module in a different workbook was running and the code module had a variable that was an object reference to the calling workbook.
The solution is Workbook.Windows.Item(1).ActiveSheetView.Sheet. When called from the running code module, even in a different workbook, it returns the same as workbook.activesheet when that is called from the workbook itself. My tests show that Workbook.Windows.Item(1) is the last active window when a workbook loses focus.
Thank you enderland. You got me pointed in the right direction.

declaration of global variable in excel VBA

here's my goal: I need to declare a table that I would like to use first in a workbook and then in a different module. The table would always contain the same values and would be filled at the opening of the excel document, and I need to use it in a different module afterwards.
Now I have searched the proper way to implement this, and what I have found tells me to put a "public" in front of the variable in order to be able to use it in a different module. However I have to declare the table in the workbook of my project (not in a module), fill it with the values, and only then can I launch the module that will use that table.
Is it because I declare the table in the workbook that the "public" does not do the trick? Or is it simply impossible to do such things with vba?
Thank you for your time and your answers
-Declaration of the Table :
you can declare in any module using the keyword GLOBAL
GLOBAL table() as variant
-filling the table :
write your code inside the event Workbook_open() in thisWorkbook

Excel VBA - Use Module in Workbook B to Update Data in Workbook A

I have 10 XLS's, each of which contain a a few hundred lines of VBA that do the same thing. I want to move this common code into an 11th XLS, and have the other 10 call the code in the 11th XLS. The common code must have access to all of the data and worksheets in the calling XLS. This last requirement does not seem to be addressed by other answers to this question on SO. Can I pass the calling XLS's worksheets in as a parameter, or something similar?
Instead of putting this into a secondary XLS file, I'd recommend creating an XLA file (an Excel Add In).
This is the exact scenario for which XLA was intended. XLA will work the way you intend in this case.
For details on creating an XLA, see this page.
Yes, you can pass references to workbooks, worksheets, ranges, etc. as parameters to any function:
Public Sub CallMe(ByVal oWorkbook as Workbook)
Dim oWorksheet as Worksheet
Set oWorksheet = oWorkbook.Worksheets(1)
' Do stuff...
End Sub
Note that you'll probably have to re-write a lot of the code you copy from the 10 workbooks since they'll be full of implicit references to "this" workbook, such as Worksheets(1) etc. As in the example above, you now need to say oWorkbook.Workbooks(1) instead.

Resources