What is the scope of Excel add-in's and VBA references? - vba

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.

Related

Variable declearation and option explicit in vba excel 2013 [duplicate]

So I'm having to run someone else's excel app on my PC, and I'm getting "Can't find Project or Library" on standard functions such as date, format, hex, mid, etc.
Some research indicates that if I prefix these functions with "VBA." as in "VBA.Date" then it'll work fine.
Webpages suggest it has to do with my project references on my system, whereas they must be ok on the developer's system. I'm going to be dealing with this for some time from others, and will be distributing these applications to many others, so I need to understand what's wrong with my excel setup that I need to fix, or what needs to be changed in the xls file so that it'll run on a variety of systems. I'd like to avoid making everyone use "VBA." as an explicit reference, but if there's no ideal solution I suppose that's what we'll have to do.
How do I make "VBA." implicit in my project properties/references/etc?
-Adam
I have seen errors on standard functions if there was a reference to a totally different library missing.
In the VBA editor launch the Compile command from the menu and then check the References dialog to see if there is anything missing and if so try to add these libraries.
In general it seems to be good practice to compile the complete VBA code and then saving the document before distribution.
I had the same problem. This worked for me:
In VB go to Tools ยป References
Uncheck the library "Crystal Analysis Common Controls 1.0". Or any library.
Just leave these 5 references:
Visual Basic For Applications (This is the library that defines the VBA language.)
Microsoft Excel Object Library (This defines all of the elements of Excel.)
OLE Automation (This specifies the types for linking and embedding documents and for automation of other applications and the "plumbing" of the COM system that Excel uses to communicate with the outside world.)
Microsoft Office (This defines things that are common to all Office programs such as Command Bars and Command Bar controls.)
Microsoft Forms 2.0 This is required if you are using a User Form. This library defines things like the user form and the controls that you can place on a form.
Then Save.
I have experienced this exact problem and found, on the users machine, one of the libraries I depended on was marked as "MISSING" in the references dialog. In that case it was some office font library that was available in my version of Office 2007, but not on the client desktop.
The error you get is a complete red herring (as pointed out by divo).
Fortunately I wasn't using anything from the library, so I was able to remove it from the XLA references entirely. I guess, an extension of divo' suggested best practice would be for testing to check the XLA on all the target Office versions (not a bad idea in any case).
In my case, it was that the function was AMBIGUOUS as it was defined in the VBA library (present in my references), and also in the Microsoft Office Object Library (also present). I removed the Microsoft Office Object Library, and voila! No need to use the VBA. prefix.
In my case, I could not even open "References" in the Visual Basic window. I even tried reinstalling Office 365 and that didn't work. Finally, I tried disabling macros in the "Trust Center" settings. When I restarted Excel, I got the warning message that macros were disabled, and when I clicked on "enable" I no longer got the error message.
Later I re-enabled all macros in the "Trust Center" settings, and the error message didn't show up!
Hey, if nothing else works for you, try the above; it worked for me! :)
Update:
The issue returned, and this is how I "fixed" it the second time:
I opened my workbook in Excel online (Office 365, in the browser, which doesn't support macros anyway), saved it with a new file name (still using .xlsm file extension), and reopened in the desktop software. It worked.
Even when all references are fine the prefix problem causes compile errors.
What about creating a find and replace sub for all 'built-in VBA functions' in all modules,
like this:
replace text in code module
e.g. "= Date" will be replaced with "= VBA.Date".
e.g. " Date(" will be replaced with " VBA.Date(" .
(excluding "dim t As Date" or "mydate")
All vba functions for find and replace are written here :
vba functions list
For those of you who haven't found any of the other answers work for you.
Try this:
Close out of the file, email it to yourself or if you're at work, paste it from the network drive to your desktop, anything to get it to open in "protected mode".
Now open the file
DON'T CLICK ANY ENABLE EDITING OR THE YELLOW RIBBON
Go to the VBA Editor
Go to Debug - - Compile VBA Project, if "Compile VBA Project" is greyed out, then you may need to click the yellow ribbon one time to enable the content, but DO NOT enable macros.
After you click Compile, save, close out of the file. Reopen it, enable everything and it should be OK. This has worked for me 100% of the time.
In my case I was checking work done on my office computer (with Visio installed) at home (no Visio). Even though VBA appeared to be getting hung up on simple default functions, the problem was that I had references to the Visio libraries still active.
I found references to an AVAYA/CMS programme file? Totally random, this was in MS Access, nothing to do with AVAYA. I do have AVAYA on my PC, and others don't, so this explains why it worked on my machine and not others - but not how Access got linked to AVAYA. Anyway - I just unchecked the reference and that seems to have fixed the problem
I've had this error on and off for around two years in a several XLSM files (which is most annoying as when it occurs there is nothing wrong with the file! - I suspect orphaned Excel processes are part of the problem)
The most efficient solution I had found has been to use Python with oletools
https://github.com/decalage2/oletools/wiki/Install and extract the VBA code all the modules and save in a text file.
Then I simply rename the file to zip file (backup just in case!), open up this zip file and delete the xl/vbaProject.bin file. Rename back to XLSX and should be good to go.
Copy in the saved VBA code (which will need cleaning of line breaks, comments and other stuff. Will also need to add in missing libraries.
This has saved me when other methods haven't.
YMMV.

I don't have Powerpoint object library on the list of available references, even though I have installed

I try to write an Excel VBA program that automatically creates a Powerpoint presentation. As far as I know, at first I should go to tools -> references and on the list of available references find and switch on the reference to the Powerpoint object library. However, on the list of available references I don't have the Powerpoint object library. What can I do to have it available? I have Powerpoint install and it works without problems.
Yes, I know I can use Powerpoint from Excel VBA macro without referencing to this object library (I can use late binding), but I would like to avoid that.
Edit:
Hm... just several minutes after posting this question I can see I have this reference on the list of available references. But I am quite sure that before I didn't have it. Is it possible that it became available now because just one minute ago I started PowerPoint?
The PowerPoint library file is msppt.olb.
If, for whatever reason it wasn't shown in this list, you could add it by running the regsvr32 command to register this particular file, or re-install PowerPoint - both should do the trick. Registering a COM file in this way puts a whole bunch of additions into the registry to let Windows know where the file is, how it can be accessed & what it's dependencies are.
In this case (i) I'm glad to hear you've already fixed the problem and (ii) sorry but it's unlikely - I'm guessing you just didn't spot it in the list the first time around (which is pretty easily done).

VBA external modules

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.

How do I add a "browse for file" dialog box to the transferText command?

I'm creating a macro in MS Access that imports a CSV file into a table. I'm using the TransferText action to import the CSV string, and I want to allow the user to browse for the file that contains the CSV string.
How do I show the "browse" dialog box to enable the user to choose the file?
See API: Call the standard Windows File Open/Save dialog box. However this requires VBA code.
An alternative (which I would say is second choice to the API call recommended by #Tony Toews and #draice) would be to use the Application.FileDialog object. This has been part of the Office automation library for as long as VBA has been in Access, but in recent versions of Access (starting with either A2002 or A2003, I don't know which), the top-level Access Application has provided a wrapper for this object. Beware, though, that without a reference to the Office automation library, the ENUM values that show up in Intellisense can't be used without a reference (a helpful error message informs you of this and offers to create the reference). In short, if you use it's best to use it as you would any automation object with late binding, with the exception that you don't have to initialize the top-level object with Application.CreateObject, as it's already there for you to use.
EDIT:
#draice asks:
I don't understand the following
statements that you wrote: "the
top-level Access Application has
provided a wrapper for this object"
"it's best to use it as you would any
automation object with late binding"
Tony's API code will work in every version of Windows, and because MS believes in backward compatibility, they will never break this API call in future versions of Windows.
the FileDialog object is not easy to use in VBA unless you add the reference to the Office Automation library. It is better to minimize the number of references in your Access database, because all sorts of things can mess them up and cause your app to break (any missing reference will prevent all VBA code from running). In order to avoid problems from missing references, we use late binding so that the code you write is not dependent on the outside libary.
Microsoft might remove this object from future versions of Access. The FileSearch object is an analogous situation, in that it was introduced in A95/97 as part of the Office Automation library, and then a wrapper around it was created in A2000, but Microsoft removed it in A2007 (and provided no alternative at all). MS could choose to remove the FileDialog object in future versions of Access and then your code would break. But the API call is never going to break.
Answer can be found at http://www.access-programmers.co.uk/forums/showthread.php?p=917371#post917371.

VBA Reference Libraries

I'm new to VBA and have been throwing together a small macro application for the Office. We've got about 80 users on essentially identical PC setups, and it will be accessed by all but a few users.
I've been playing around with some automation of accessing web pages using the Web Services references, and I've also loaded the Microsoft Scripting Runtime references into the project. I attempted to run it on a test PC and it complained that there were missing references.
I don't particularly want to go around 80 PCs and manually load the references.
My question, basically, is how should I manage the distribution of this macro-app to 80 odd users so as to ensure that the references will load every time for every user.
Thanks!
For the most part, late binding will solve problems with references in VBA, unless you have some unusual references. Most problems are caused by differences in library versions that can be overcome with late binding. With VBA, it is often recommended that you develop with early binding but release with late binding. The main disadvantage of late binding is changing built-in constants to values (speed is no longer the issue it used to be.)
So:
Dim fs As Object 'Instead of FileSystemObject '
Dim xl As Object 'Instead of Excel.Application '
Set fs=CreateObject("Scripting.FileSystemObject")
Set xl=CreateObject("Excel.Application")
'Value instead of built-in constant '
ForReading=2
Set f = fs.OpenTextFile("c:\testfile.txt", ForReading)
If you have references that your application depends on, that you know are not going to be on the target PCs, then I would strongly recommend you investigate some installer technology.
Using the installer you should be able to install your macro, and install and register all appropriate references / libraries.
There are generally two flavours on windows, Windows Installer based technology and Script based technology.
We use InstallShield for all of our deployment, although there are several options for you to use (there are several discussion on Stack Overflow).
Using windows installer technology, you can build MSI install files, which you are then able to deploy automatically using Group Policy.
Instead of having the documents expose the functionality, make it an add-in for Office (the suite, or the individual apps, your choice). This way, you don't have to deal with references.
Then, just distribute an install package with the add-in which registers the components and registers the add-ins with the appropriate Office apps.
VB6 might be a good idea here, given it's similarity to VBA.
In addition to this answer, which is the bullet-proof solution to solve this kind of issue, but which is quite complex to implement, you can also write some code to be executed when your VBA application starts, checking the 'references' collection of the 'application' object. You can then check (1) if requested files (dll, ocx, tlb) are available on the computer and (2) if reference can be created (application.references.addFromFile ...).
Be careful: object declarations that might be 'reference dependent', such as:
Dim cat as ADOX.catalog
will raise a compilation bug if the reference is not active when the corresponding module is 'compiled'. I then advise you to isolate your 'reference checking procedure' in a startup module (equivalent to an 'autoexec') which deals only with VBA and basic application objects. Check it with your Help Files (Example: in Access, default references that can be used without external references are VBA, Access and DAO).
EDIT:
in case external references depend on other software package and (1) cannot be distributed with a MSI file or (2) can have multiple versions, I think the 'references.addFromFile' is the only solution that can apply. Example:
You have an VBA/Access runtime client
app that needs to refer to Word
(msword.olb file).
For licensing issues, you cannot freely distribute this file with your msi pack
the olb file can be either the 'XP version or a newer one
Our solution is to have 2 tables on the client Access file. One lists all the references that have to be checked or added at startup time (Word will be one of them), and the other one lists all the possible locations of the file (depending if the user has the 'office11' version or a newer one), with a one to many relations between the 2 tables.
So, the best strategy could be a mix between msi packs and management through code:
msi is great for distributing independant dll's or other files that are totally 'embedded' in your app, such as activeX controls (like scanners controls, report or file viewers, etc)
code is the best solution where your app will have to communicate with other applications (word, excel, outlook, etc) that can exist in different versions on your user's machines.