VBA and late binding: Where do I find the numeric equivalents to constants? - vba

I'm a complete VBA newbie, having decided to teach myself over a weekend, so forgive the stupid question(s). I'm trying to automate some routine tasks involving generating Word documents or emails from an Excel Spreadsheet. Because there will be multiple software versions involved, I am using late binding to open Word and Outlook. My question is: Where can I find a simple reference telling me what the index numbers are that correspond to the application constants? I have killed a lot of time googling to learn that, for example, the Outlook foldertype for "Contacts" is "10". Maybe someone knows of a web link that could save me countless hours of searching?
Update: http://msdn.microsoft.com/en-us/library/office/gg278936%28v=office.14%29.aspx seems to have some of the information I need, although it's not always intuitive where the information is. For example, if it contains the outlook folder type constants, I haven't found them yet.

See here
Enumeration http://msdn.microsoft.com/en-us/library/office/ff860961(v=office.15).aspx
OlDefaultFolders Enumeration http://msdn.microsoft.com/en-us/library/office/ff861868(v=office.15).aspx

I would recommend to add the relevant object libraries to your project as References during development time. You do this by using the Tools - References Menu in the VBA Editor. This makes developing a lot easier as you can use intellisense while writing the code.
If you need only a few Enums or single Constants in your code the easiest way to get their values is to hit [F2] in in VBA Editor while the object libraries are still referenced. Then search for the constants name and copy its value to your code.
Just using the numeric values of the constants in your code makes the code pretty hard to read. So I would recommend to re-declare all the Enums/Constants you actually use in a module in your own project. That massively improves the readability of your code.
So, instead of just copying the value from the VBA Object Browser, I suggest you copy the name and the value and put it your own code as a constant declaration. For your example of the Outlook contacts folder this will look like this:
Public Const olFolderContacts = 10
You can then use the constant in your procedures as you would do with Early Binding.
Should you work on a larger automation project using many of the constants from any one of the Office Object Libraries, you can download ready-made VBA modules containing all the Office constants from my website. You can then just import the relevant modules into your project and are ready to go.
After you finished the main development work, you remove the linked libraries from your project and declare the relevant object variables As Object instead of the actual type.
Always remember to compile your project not to miss any declaration that does not work late binding.

Related

How to change a global variable name in an Excel VBA project?

If someone have to carry on working on an Excel VBA project/module after the previous developer left the company, how do they safely change a global variable name?
These global variable names can be problematic if they are misleading, misspelled, look like another variable, don't follow the chosen convention, etc.
Changing them with a Search/Replace is a problem because sometimes it's a word that appears in comments.
Changing them by Copy/Pasting is a problem because it's long and you can miss some, especially if there are a lot of occurrences or if you change it to something similar.
Is there a way to do this safely via the Excel "IDE", or via another tool?
What you need to do here is called a refactoring - you need to make a possibly dangerous change to the code, without affecting its behavior. Do it wrong and the code breaks!
Renaming an identifier that's used in one or more places, is a rename refactoring.
Most modern IDE's have such a feature (and several other refactorings). However the VBE was at the height of its glory well before Visual Studio was the full-featured tool it has become since then - heck, the VBE was Visual Studio (6.0) in 1998!
So you really have two options:
Do the refactoring manually - the IDE's search & replace functionality (Ctrl+H) can be dangerous here, because it treats code as simple text, without semantic understanding: you need to review every single occurrence individually, or risk renaming an identifier that was not referring to the variable you're trying to rename.
Use a 3rd-party tool - I don't know any VBIDE add-ins that understand the code deeply enough to allow safely refactoring VBA code, other than the open-source Rubberduck project, which I've managed since October 2014). This add-in parses your entire project, builds a symbol table, and lets you navigate and, yes, refactor/rename any identifier, automatically updating all call sites.
Note that Rubberduck is a very active open-source project, constantly improving. Parsing VBA is hard, and getting the VBE functionally on par with modern-day IDEs isn't a small undertaking, nor is it easy... but it's fun, and yep, it works.

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.

Best way to internationalise VBA project

I develop quite complex Excel VBA application (several thousands lines of code spread across modules, class modules and form modules). There is a need to translate it to multiple languages, which means to replace (almost) all of the strings in application and use some kind of hash-table with records for each language.
My question is what is the most efficient and convenient way to gather all strings used in application and replace them with some kind of language variables. Could anybody recommend some kind of best practices for this type of task for VBA project environment? Thanks in advance.
One option is to use source tools addin to export all your code into source files under one folder. Example below:
Now you can write scripts to modify the files, and also now you can put them in source control. When done you can re-import them into the VBA project with changes.

How to import Microsoft Office constants (msoTrue, ppLayoutText...) into LotusScript?

I am trying to programmatically make a PowerPoint presentation from the contents of a Lotus Notes document. This is relatively straight-forward using CreateObject("Powerpoint.Application") but I fail to find a way to access the various constants that are used in VBA.
One solution is of course to hard-code the (ten or so) values into my script, but for obvious reasons I'm a bit uneasy about that solution.
Is there a way to lookup the value of for example msoTrue or ppLayoutText with LotusScript? For example a way to query the Powerpoint.Application object for the values?
(In more compentet languages adding various Interop libraries seems to do the trick, but I haven't found a way to do that in LotusScript.)
Edit
I prefer a solution that will work without any extra installation of software or dlls, apart from Office.
You can have your code lookup these MS constants by creating an OLE object of type "TLI.TLIApplication" object (defined in tlbinf32.dll), and then querying that object for all of the office VBA constants. There is an MSDN article describing this technique in general here:
http://msdn.microsoft.com/en-us/magazine/bb985086.aspx
There is also sample code for exactly this procedure in a LotusScript environment here:
http://noteslog.com/post/ole-constants/
Note that this is a runtime-only technique. This inspection method will make all of the constants available to your code, but will not make the constants available through Intellisense in the Domino script editor.
This is what I use for MS Office constants: Microsoft Constants Database. There is a script library that has recently been added for Word and Excel.