I've made an xlam addin to use many common functions I have to use regularly. Thing is whenever I send a workbook that uses these functions to another pc, the cell that calls it makes a reference to my xlam's path... which makes sense.
I'd like to know if there's any way to avoid this behaviour so I can make my xlsm files portable. Maybe a way to programmatically add all the addin modules to the workbook whenever a xlam function is used.
Related
I have several workbooks that have similar and reused VBA code sometimes I need to update the code and I would like to do this in one place instead of in 20 different workbooks is this possible?
If not is there a way to copy all the macros from one workbook to all the others after a change has been made?
Yes, you can reference other workbooks from VBA. Might be easiest to put it in an addin though.
If you are using class modules, then you can only set them as either private or public not createable (something like that). Obviously they'll need to be public, but you can get around the inability to create them by building simple helper functions in a normal module that do nothing other than create a new instance of the class and return it.
It is possible, yes.
This answer on SU mentions one possibility that is explored more in-depth in this support article.
If you find yourself recreating the same macros, you can copy those
macros to a special workbook called Personal.xlsb that is saved on
your computer.
By default, when you create a macro in Excel, the macro works only in
the workbook that contains it. This behavior is okay as long as you
don’t need to use that macro in other workbooks. Any macros that you
store in your personal workbook on a computer become available to you
in any workbook whenever you start Excel on that same computer.
In short: record a macro and choose to save it in Personal Macro Workbook. Save and exit, then re-open Excel. Go to the View-tab and click unhide.
The support article gives a more detailed step-by-step.
Sure is possible,
the two ways that I know are:
copy your macros on Personal.xlsb (like Vegard wrote) or (it's my usually case because I've also my custom Ribbon to play all my custom cmd) you can open a new excel file, write in this file all your macro/function/class.... and then save it as xlam file.
After you need to go on excel option, add components and choice the xlam file before created.
Tips, in the xlam file use a specific macro names and not macro1, macro2,.... because into your next files will be easy to create more macro and use the same name is usually..
I'll add my answer based on experience as it seems the ones given are all (unspoken) focused on being "free".
I started out using a workbook as my code library (as suggested above), but every time I made an adjustement or improvement to those code snippets, I had to go back to the other workbook and update it etc. This got old fast.
Once I started developing a bit more professionally, it made sense to invest in a tool to manage my code.
I use MZTools which also comes highly recommended by various Excel MVPs such as Ken Puls, Ro Bovey, etc. but there are other ones out there. Usually these tools also provide addtional functionalities that are useful to a developer. Invest a few bucks if you want to save your self from a headache.
I am looking for a way to create workbook-local functions in C++ (unmanaged). VBA is not appropriate for my use case. Unfortunately, that's the only way I know of to create a workbook-local function. (I'm not terribly familiar with VSTO, so there may be a way there, but I cannot used managed code for this.) I know how to create functions as XLLs, and I know how to create an automation addin that exposes functions through IDispatch. However, both of these seem to be for global functions only.
Does anyone know a way to do this?
Worksheet != Workbook
I don't know of any way to create worksheet-local functions.
In VBA to expose functions you need a standard module (.bas) without the Option Private Module option set, exposing a Public Function - that function is usable in every worksheet of the workbook that's containing it.
A worksheet is essentially a class module, and lives as an object instance: its Public Function members are therefore not usable as worksheet functions.
Functions are workbook-local, not worksheet-local.
Now, that's probably what you meant anyway, given that the add-in approach is being referred to as creating "global" functions, which are available to all workbooks.
As #RubberDuck hinted, creating code via the VBIDE library doesn't require elevation and security settings tweaking if you're extending the VBE itself. This might help (it's the entry point for the add-in #RubberDuck and I are working on). This add-in edits, deletes and adds code in the VBE for a living, and doesn't require tweaking macro security settings.
Is it possible to have modules be external to the actual Excel file and call the functions/subs within them externally?
My thinking is if there are multiple Excel files that use the same module, instead of updating each one of those files separately when I make a change, can I just update the one module stored on a server or something?
I have doing something like you describe for years. You can move your VBA code to a VB6 ActiveX dll, organize it into classes, and load that dll as a reference from Excel VBA.
This is a good way to reuse non-workbook specific code. For instance, I have code that queries a mainframe. I like to call it from Excel, but the details of the connection and how data is passed are contained in a dll that I can load from Excel, VB6, Word, .NET, wherever. I have a similar dll for reading data from AutoCAD drawings, one for interfacing with a product DB on a MySQL server, etc.
The code that remains in Excel tends to be simple formatting stuff. Say I return a variant array of strings (technically a COM SAFEARRAY) from some library that I wrote. I would then output it into Excel, maybe do a text-to-columns, and have a list of results returned to the user.
You can also pass and return more complex data structures. The beauty of VB6/COM Automation (and I didn't appreciate this until I learned to do it the harder way in VB.NET or C#) is that the data will flow in and out of your components seamlessly and all the necessary interfaces will be created for you.
The main change to your code will be replacing things like ThisWorkbook or ActiveSheet with explicit parameters like (Byval sht as Excel.Worksheet). These will be caught at compile time in VB6 (since it doesn't know what ThisWorkbook is), so you cannot overlook them; you are forced to pass an explicit reference.
I also notice that my code inside the dll becomes more paranoid if it receives a Worksheet or other Excel object as a parameter. In VBA you might have had more assurance that you were passing a good object since it was private to a given workbook. The dll does not know who is calling it, so I view the passed-in object with more suspicion (check if Nothing, sheet name, formatting clues to ensure I am using what I think I am using).
The only downside I see is that you will have to get a copy of Visual Basic 6.0. I bought mine in 1998. It is no longer available from Microsoft, but surely there is someone out there who will sell it to you. The latest service pack is SP6.
You will also have to become familiar with "regsvr32" and "regsvr32 /u" to deal with the "ActiveX can't create component" errors as you open your workbooks on various computers. I just publish my dlls to a mapped network drive and re-register them on the user's computers whenever there is a significant change. Obviously this is a intranet/single company solution. Publishing the updated versions is much more of a pain the farther you are distributed.
Not sure if this would satisfy your needs, but you could create your common module as an "add-in" and so install it so that all files that you open in the same instance of excel would have access to the add-in code.
It would not be my recommended way of doing it because I would be worried about suitable testing of all the excel files that use it, when you make a change, plus the added complexity of getting users to install your add-in (this may not be an issue for you). I have a "developersToolkit" module I use across 8 different Workbooks, but I import the module into each workbook so its stand alone and I can also test changes for compatibility with each of the 8 workbooks.
When I install an add-in (via the checkbox) what are the rules / mechanics governing how long that add-in stays installed? It seems that it is installed on the application level, meaning that it applies to any workbook in the excel application, until you uncheck it yourself. If this is correct, this means that as long as a user installs the add-in themselves, they should be fine; but they will have to install it that first time (which could be done programmatically).
Regarding VBA references, I imagine these do not need to be 'checked' every time- meaning it is in the scope of the document. But if this is true, why do people recommend using late binding methods when the software is ready to be distributed? Is late binding really just to make it compatible with different versions, but not necessarily to make it so the DLL is 'checked' as a reference? Under this assumption, as long as everyone uses the same version of Excel as the me, would it be safe to forego late binding all together, and just add the references manually?
Using late binding is better because you can't guarantee that every system will have the same references available. So you should only select references that you can guarantee will be on every machine and distribute the DLL files for the rest.
As far as scope, the public subs/functions/variables in your add-in will be available to anything in the application as long as it is installed and active. The references in the add-in will be available only to the routines in the add-in.
Add-ins are installed to the Application-level. You can fine-tune how an Add-in may be exposed (or not) to various Workbook(s) using Ribbon XML if needed.
as long as a user installs the add in themselves, they should be fine; but they will have to install it that first time
Yes, they'll have to install it.
Regarding VBA references, I imagine these do not need to be 'checked' every time- meaning it is in the scope of the document.
Yes, version control. It also saves you the hassle of having to try and programmatically add references. This can be done by path (which requires knowing the OS, version, etc. ) or the GUID (I've never actually been able to do this successfully). Both of these would then require error-trapping (what if the path doesn't exist or is otherwise inaccessible? etc.). So just use late binding.
While developing using early binding is helpful because of the intellisense, from a user perspective, there is generally no observable difference in how they might perform although EB is arguably faster, the difference is usually negligible for most applications. Related, if while using EB you rely on the New keyword to instantiate objects, I believe that the CreateObject function which you would use with LB is actually faster. This is probably not noticeable, though.
can I forego the late binding all together, and be safe by just adding the references manually?
I would simply do the development with EB, and then modify the code to late-bound objects before compiling the Add-in.
I've had a very difficult time implementing an Add-in in Excel.
I've got buttons on a worksheet which reference code in the Add-in, and I've also got code in the worksheet which references functions in the Add-in. What was really throwing me off, was that I could inactivate the Add-in (options, add-ins, Manage, uncheck) and the code continued to access the add-in. This was particularly frustrating during development and debug of the Add-In, because what I wanted to do, was to inactivate the Add-In (during development) and have my application worksheet reference the open Add-In .xlsm development file. What took me a while to figure out, was that due to the code "References" in the application worksheet, it was still calling to the code in the .xlam file, not the .xlsm.
Once I figured this out, things when smoother, but now, each time I make a change and want to test, I need to close my application, Inactivate the Add-in, Close Excel, Save my .xlsm as .xlam in the default Excel Add-Ins directory (which BTW requires administrator rights), Open excel, Activate the Add-in. [Close Excel], Open my workbook application. A throughly exhausting process. Perhaps I could skip the last [Close Excel] step if the add-in becomes active immediately when checked.
And then dealing with users on Win10 and Win7 really complicates things. Different path to default Add-in folder. Users have to change references path, etc. Very ugly. Very Microsoft.
What is the best way to avoid duplicating code when working in VBA?
I'm used to languages where I can just add an import statement and get access to all a class's public properties and functions, so I can just create a utility class with some common functions and have access to that in any project I choose to import it to. Any time I want to update one of those functions, one edit is all it takes to get it working across all projects.
Is there any good way to replicate this functionality in VBA?
What follows focuses on Excel but I am pretty sure the same would apply to any Office products.
The easy way is to save your reusable code as an addin (*.xla for Excel 2003, *.xlam for Excel 2007+). You then add the addin to Excel and all the spreadsheets you open will have access to the custom functions you have in your addin. If you add specific VBA code to a spreadsheet, you can add a reference to your addin and your VBA code will have access to all the public sub, function and classes of your addin.
In my organisation, we use 3 home made addins - they are stored in C:\Program Files\OrganisationName. And everybody has access to them. When an update is made, we only need to copy the new version to everybody's hard drive and restart Excel and they have the new version.
The addins contain utilities functions such as functions to:
read data from / write data to spreadsheets / files / databases.
usual data manipulation such as removing duplicates from a list
advanced statistical functions
etc.
A few drawbacks:
If you have several instances of Excel open, only one can update the addin, the other instances are in read-only mode
If Excel crashes, the auto recovery mode generally does not save the changes you made on your addin (TBC on newer versions) - there are a few tools to auto save regularly
An alternative is to develop xlls or COM libraries in VB or C# for example, but this is something I have not tried.
There are plenty of tutorials online if you need a more detailed procedure.