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.
Related
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.
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.
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.
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.
I am looking for a way I can automate an Excel VSTO Document level solution, to be called from an external application, similar to the VBA approach like "xlApp.Run("WorkBook", "MacroName") which we use to auto mate VBA solutions. As this will be a document level solution, Remoting or Webservices are not options. I am using VSTO 2010 and Framework 4 targeting Excel 2007 and 2010 versions.
Say, I have a Document Level Solution with a workbook named "TestBook" which contains a VSTO based class "MyClass" with a static function "GetData(string connection)" I am looking for a way to make a call to GetData function, from an external application. The solution itself will be loaded into excel by the external application too using Application.Workbooks.Open method.
To summarize: I am trying to find a way to get a reference to an object (ideally) and make a call to a function from a Document level solution after loading it. I am trying both ways like (External App)->(Addin)->(Document level object) but the route (External App)->(Document level Object) would be ideal.
Any pointers would be greatly appreciated.
I suspect you need to go about this a bit differently...
The call a method the way you want you might a to resort to something called a "COM Automation AddIn" and implement a UDF this way.
You can then just place the call to your method as a formula inside any sell of that workBook - Excel eveluates that formula by calling your implementation. You can even tell Excel to reevaluate it.
Another option might be to build the functionality as a so-called RTD-server which is referenced in your workbook...
For some information see these links:
http://msdn.microsoft.com/en-us/library/aa662931%28office.11%29.aspx
http://msdn.microsoft.com/en-us/library/aa140060%28office.10%29.aspx
http://weblogs.asp.net/kennykerr/archive/2008/11/13/Rtd3.aspx
http://msdn.microsoft.com/en-us/library/aa140059%28v=office.10%29.aspx
http://msdn.microsoft.com/de-de/library/microsoft.office.interop.excel.rtd%28v=office.11%29.aspx
http://exceldna.codeplex.com/workitem/5902 (free library to ease the development)
http://www.add-in-express.com/docs/net-excel-automation-addins.php and http://www.add-in-express.com/docs/net-excel-rtd-servers.php (commercial library to ease the development)