Where to place reference content for an xlam file - vba

So I have an excel add-in that, amongst other things, contains a huge list of aliases. For example, Country names with their ISO codes, Countries with their continents, etc etc (so that I can easily know that Canada is in America or that Côte D'Ivoire's national language is French, etc). Currently, I have the xlam with all the relevant functions that check named ranges in another workbook.
So summarizing, I have 2 files:
macros.xls (has all the named ranges with things like Angola =
AGO, etc), and
my_functions.xlam (has the functions that I can call from
excel to get the Alias name). An example function is:
Function nti(v)
nti = WorksheetFunction.VLookup(Trim(v), Range("macros.xls!nti"), 2, 0)
End Function
Where nti is the function that I use and macros.xls!nti is the named range that I am referencing.
This all works great, but that means that this functionality requires two files, since an .xlam file can not be opened and edited in excel, only in VBA explorer.
Question: How can I have an easily modifiable lists and functions referring to these lists in one file? The functions should be available to other files I'm working on.
Disqualified solutions:
Save the my_functions.xlam as an .xls temporarily, copy all the named
ranges in, and then save it back as an .xlam. This would be annoying
to do every time I want to make a change to the named ranges (which
is fairly frequent).
Hardcode a bunch of 2 column arrays with all the
aliases into each function (thousands of lines long sometimes). PLEASE tell me there's a sexier way...
Thanks in advance!

I usually just toggle the IsAddin property of the XLAM from true to false, edit the worksheet and then toggle the property back again before saving.

Related

VBA loop through non-patterned files in folder (seek for opinions) [EDIT]

I am here for seeking any advice or opinion as I want to loop through every excel files in folder. As you can see from my attached picture, my excel files are different both in file types (.xls <> .xlsx) and filename (especially on 2018). I also need to loop through "Revised" or "revised" files as well since it is possibly that any file will be revised next time.
And yes, I also did some research on this. My understanding is I need to modify all of the file names into the pattern one before build up a VBA to loop. At first, I thought about decomposing all filenames and put it back in pattern form, but it sound too idealistic. Another way is using the date in each file to label the workbook name, but again I found that those date had different styles. Some files label the date by using string such as "January 2012" or "March 2014", while the others using the date form such as "19/08/2013".
Therefore, I would be appreciated if anyone could suggest me on;
How can I handle with the different file name (.xls and .xlsx) within the same VBA?
How should I deal with these different file names (some files have "revised" at the back; some do not have "-" between "Cons" and date; and some use month name instead of number)? Are they any pattern that I overlook?
Please noted that I am just a newbie VBA coder, so it would be great if you left your answers with an explanation or any kind of examples.
Many thanks.
--------------------------------------------------------[EDIT]-------------------------------------------------------------------
First of all sorry for my poor explanation before. I provided too few information to understand overall picture. Let's start this over again.
My data are about steel consumption which release from the authority
every month. My task is to gather all of these data (such as
production, import, export and consumption of every data in each
row) and generate into time series pattern (please see attached
excel screen)
As it is possibly that these data will be revised anytime, I thus
decide to download all of these file every time in every month (one
file per one month). In addition to those revised file, the
authority will unexpectedly rename those file for example, from
"Cons 201601.xlsx" into "Cons 201601 - revised.xlsx)". This make me
more difficult to work on this (please see attached folder for
reference).
Moreover, this authority seems to have a problem with file naming as
they had different pattern of filename in the past compare to the
present ones. Example is per below table; Cons 201701-Revised.xlsx
Cons 201710-Revised1.xlsx
Cons 201711.xlsx
Cons-200902.xls
Cons-201212_revise.xls
Cons-201401-revised.xls
I mention above file name in order to create a VBA to loop through
these file, select some content and paste into another workbook in
chronological order. This means that I cannot use "Loop while or Do
while function" in my VBA. At first I decided to use two integer
variables, both of which were set for years and months
(e.g. For i = 2009 to 2018 and For j = 1 to 12) in order to created the system of filename (such as filename = "Cons" & "-" & i & j). But,
as I stated before, non-patterned name by the authority had
prevented me from creating this kind of loop.
I also tried to use the date in cell B2 in figure 1 to label the
date in order to create the loop which I already explained before.
However, again, the authority did not use the same pattern to date
month and year. After I checked with many file, these are example of
the date style in cell B2 January 2012 (string)
February 2009 (string)
Jan-16 (1/1/2016 date in custom format)
Given above limitations, could you guys again suggest me any possible
way to create chronological loop so as to copy and paste data to another
workbook to form a set of time series data for each product?
Thank you for your kind help :)
Firstly, use FileSystemObject (include a reference to Microsoft Scripting Runtime in your VBA project) which has some helpful functions within it. You could always code your own, but why reinvent the wheel in this case?
Don't have time to codes something this morning, so here is the pseudocode:
Open a Folder using your known filepath
Loop through all the files in the Folder (For each f in Folder.Files
extract the date code from your filename (e.g. using RegEx)
Add to a collection (e.g. array or Dictionary item) of the filename and the extracted date code (your key).
(end loop)
Sort your collection based on the extracted date code
This now gives you an ordered list of files, which you can open in turn and extract the data. An added bonus is that the key in the collection gives you a consistent date representation which you can use as an index in your collated information.
If you just want to loop through all files in folder use this:
dim file as variant
file = Dir("<PathToFolder>")
While (file <> "")
'Your logic here
file = Dir
wend

Finding a VBAS defnied Named Range definition

a valueI've inherited a large VBA project and whilst I have lots of dev expereince I have a small amount of VBA. The code reads data off a sheet in the form:
Intersect(Range("colName"), .Rows(intCurrentRow)).Value
Where colName is a named range, or so I thought. I have searched all of the project code and the excel sheets and cannot find where colName is defined ?
So far I have searched the code, looked in Name Manager on the sheet and have googled furiously but hit a total blank. As I now need to read in another value from the Sheet I would really prefer to use the code that is currently used with another value instead of colName to reference my new data field.
Is there anything obvious I'm missing ?
Edits:
activesheet.range("colName").address gives a value of "$L:$l"
Its probably a hidden name.As Doug Glancy said, you can unhide it using VBA
Activeworkbook.Names("colName").Visible=True
If you are working with defined names you may find it useful to get My & Jan Karel Pieterse's Name Manager addin which (amongst many other things) handles hidden names. download from
http://www.decisionmodels.com/downloads.htm
It could be a hidden Name. Try:
ActiveWorkbook.Names("colName").Visible=True

Excel VBA: Resetting spreadsheet count

I have a excel VBA macro that dynamically generates and deletes spreadsheets based on user input. However, when I open the VBA IDE, it seems that although I am naming my spreadsheets in the subs that create/delete them, the overall count is still increasing.
For example, depending on how far into execution my program is, under the "Microsoft Excel Objects" folder in my current project, the spreadsheets in the current workbook could look something like
Sheet101(Sheet3)
Sheet103(Sheet2)
Sheet104(Sheet1)
Or
Sheet81(Inputs)
Sheet83(Date Adjustment Interpolation)
Sheet84(Pricing)
Sheet85(Comparison)
No matter if I delete the rest of them and add one, it still picks up where the last highest one left off.
I don't know how many times this macro will be run and I'd feel a lot better about putting it out there if I could reset this annoying tally on the number of spreadsheets that have ever been generated, since I don't know for sure where excel will cut me off. Plus it's just annoying.
My Question:
I would like to know how to alter that spreadsheet number, or at least what the relevant object is for doing so.
Thanks!
Thanks to #dijkay s suggestion on code names, I've found some code to accomplish this.
ThisWorkbook.VBProject.VBComponents("Sheet1").name = "test"
Will change the code name of Sheet1 to test, so in the Excel Objects folder, it will appear as test(Sheet1) for example.
This option, however, requires messing around with some trust/security settings in each individual excel client running the macro, which is unsuitable for my purposes, unfortunately. You can also change the value manually by changing the (Name) property directly in the IDE through the properties window.
here are some ideas you can try...
Sheets(x).Name = "Sheet" & x
or (assuming in this example, 'Sheet3' doesn't already exist:
Set Sheet3 = sheets.Add
Sheet3.name = "Sheet3"
This is more cleanup than re-setting
cheers,
Micéal

Proper procedure for declaring global variables in VBA?

I have a macro workbook with a number of worksheets that exist permanently, which are constantly cleared, updated, etc. Since they are referred to in various subroutines, I have made each corresponding worksheet object a pseudo-global variable in the following manner, for example for the "Main" sheet:
Function MAIN() As Worksheet
Set MAIN = ThisWorkbook.Sheets("Main")
End Function
By doing so, I can then refer to each sheet in the other subroutines, for example:
MAIN.Cells.ClearContents
I have also defined some pseudo-global constants which are located in a fixed place on the "Main" sheet in a similar way, for example:
Function NumLines() As Integer
NumLines = MAIN.Range("C3").Value
End Function
In this way, I use "NumLines" just like any variable throughout the code.
I expect that there is a more efficient way to manage globally accessed variables like these and was wondering, what would be a better way to accomplish this?
For reliable sheet reference I would suggest to use Sheet.CodeName Property. Each sheet has its unique CodeName which you could find in the place marked yellow on the picture below.
For quick reference to cell value I would suggest to use Range name. After you select you C3 cell you need to put unique name in the box marked yellow below. All Range names are unique in the workbook.
As a result you can use sheet and cell reference as presented below in each of your subroutines in your project.
Sub Test_Macro()
Debug.Print MAIN.Name '>> result: Sheet1
Debug.Print Range("CellC3").Value '>> result: 100
End Sub
I expect that there is a more efficient way to manage globally accessed variables like these and was wondering, what would be a better way to accomplish this?
When I use global variables in VBA, I do three things.
I always preface global variables with a g_ prefix. It seems often that a global variable in VBA is useful. But I've also spent far too long trying to track down "what variables are global or not?" in other people's code. Keeping a very clear naming convention will save you and whoever looks at your code a TON of hassle in the future.
This is even more important if you are less experienced as a developer. Avoiding globals is hard in VBA, and the less experience you have, the more likely it is you will use globals. For others to help or maintain the code this becomes so important.
If you are going to be using even a small number of global variables, you must use Option Explicit unless you want to cause nightmares in maintaining code. It's hard enough to track down these errors when you wrote code let alone months or years later.
I always create a module which is called "GlobalVariables" or something similar. That module contains all of the global declarations in one location. For larger code bases this can become longer but it has always paid off for me because I know exactly where all my globals are defined. None of the "which file is this variable actually being defined in?" game.
Just an unrelated note, too, in your first example - I would use the code name rather than that function. Each VBA worksheet has a sheet name ("Main" in your case) as well as a codename, which you can set in VBA and remains the same. This prevents users from changing the name of "Main" and breaking code.
You can also refer directly to them similar to how you are using MAIN.Cells. KazJaw has a good example of this.

How to create string in Excel INDIRECT function to dynamically reference cells in an external spreadsheet

I can use an external reference easily in Excel 2010 like this
Cell A1 : ='BLAH.XLSX'!Fees[[#Totals],[Billable Hours]]
but lets say B1 contains FOO.XLSX
I now want A1 to be
='FOO.XLS'!Fees[[#Totals],[Billable Hours]]
I tried the indirect function
=INDIRECT(CONCATENATE("'", B1, "'!Fees[[#Totals],[Billable Hours]]"))
But this just gives a #REF error, but it resolves (I used the show steps function in excel)
to:
=INDIRECT("'FOO.XLSX'!Fees[[#Totals],[Billable Hours]]")
I've tried (played with) a number of things but nothing gives me the reference correctly
suchas =INDIRECT(CONCATENATE("='", B1, "'!Fees[[#Totals],[Billable Hours]]")) which resolves to
=INDIRECT("='FOO.XLSX'!Fees[[#Totals],[Billable Hours]]")
Also I want to avoid VBA to avoid security warnings/dialogs etc., but will accept this if that's the the only way
I feel I'm really close
As Jesse says, you can't use INDIRECT to refer to closed workbooks. There is no other formula solution unless you use add-in functions. INDIRECT.EXT works with closed workbooks but you need to download MOREFUNC addin to get that function, google Morefunc
See INDIRECT and closed workbooks at Dick's Blog
Harlan Grove's Pull function and opening the workbook directly via VBA for large scale manipulation are the two most commonly used methods