Question!
I have an add-in we created at work, say foo.xla, and it has a function foo_sub(arg1).
Now, I want to improve the way that foo_sub(arg1) behaves but withour editting the original add-in code, since as soon as they update it, I must migrate my code from the old add-in to the newer.
Is there a way I could write foo_sub(arg1) in a different add-in, say fee.xla, so that every time I call foo_sub from a worksheet the one that get's called is the one I wrote?
Thanks in advance
I had a lot of similar issues when trying to overload a constructor in VBA in Excel.
However, I think your problem is a little different. You're not necessarily trying to overload the function by providing a separate method with the same name and different parameters; you're trying to add a method with the exact same name, return type, and parameters and figure out a way to have Excel call your function rather than that of the add-in.
I'm not positive, but I don't think this is possible in Excel VBA. If you try to call a function that's defined in multiple places, it will get confused and tell you that it doesn't know which one to call.
You might create a wrapper function called my_foo_sub(arg1) which has custom code in it. Then, if you need to switch to the new foo_sub(arg1) when the .xla file is updated, you could just comment out your custom code and add a call to foo_sub(arg1). This is far from ideal, but it might help.
This may help: Function Overloading and UDF in Excel VBA
Related
I am using LEFT, UCASE, MID and a few other text functions.
eg If UCase(Mid(VBAFormField, 4, 3)) = "ABC" Then
For most users the code works fine. On one PC it gives an error and seems to need modification.
eg If UCase(Application.Worksheetfunction.Mid(VBAFormField, 4, 3)) = "ABC" Then
Things I tried:
Excel versions are identical
VBA Reference libraries are the same on both computers
Any ideas?
I have frequently experienced that VBA (2010) will highlight a missing library for an item for which the library is not missing because another library in fact is missing. It's usually just the first reference to any library in the code. So you should look for a missing library further down in the code, more likely, a not so standard object.
I have also frequently experienced (with any version of VBA up to 365) that errors aren't shown right away but are "remembered". I have explained this to myself by acknowledging that given a large project VBA will assemble the parts it needs as it needs them but once an error was discovered it won't be overlooked a second time and is flagged right away. This behavior could explain why only one of your PCs objects to the code. The others just didn't get around to it yet.
I would guess there must be an add-on or a language setting that is causing a conflict. However as Tim Williams pointed out, you're using the worksheet function in VBA when a VBA function exists that does this exact task you need to complete it.
While probably not necessary, you could go even further and scope the formulas to be vba specific just to ensure the proper library is being utilized.
MsgBox VBA.UCase(VBA.Mid("SomeText!", 4, 3))
Summary:
So I have a workbook that has been distributed and will need to be updated on occasion. After some research and investigation, I have opted for the workbook to import a networked .bas file (Visual Basic code module), execute the module's code to update said workbook and finally remove the module once completed.
Problem:
I was wondering if there might be any issues with this method, as it seems to work and be implemented too easily, when compared to an add-in for example.
My code is simple, in the workbook_open event I import and run the "update" module:
1) VBproject.vbcomponents.Import MyModule
2) Execute MyModules code
3) VBproject.vbcomponents.remove MyModule
(2) and (3) are completed in another subroutine, otherwise the module's methods aren't recognised after importing and can't be used.
Thanks in advance for any issues that might come of this.
If the question is too vague or open ended let me know and I'll remove it or alternatively I can provide further specifics.
Thanks in advance guys
The main issue I can think of is that for this to work, you need your users to accept to Trust access to the VBA project object model.
They might not want that, reasonably, or be forbidden to do that, because it involves some security risks.
Imagine someone succeeds to drop a malicious .bas file with the same name/place of yours. You need to take measures against that, and convince the users and especially the security admins...
(Questions with an answer of NO are still useful; they're just not the solution to the problem. Answers say, no, there is no built-in, you have to implement the dialog for yourself...)
In VBA, (ms-word, or ms-excel, but seems like a generic operation) is there any way to simply a provide a collection to a built in dialog in order to prompt the user to select a value from a list of values?
I can't believe there's not a built in method to do this, it seems like a such a generic operation that could be coded once and everybody would re-use it. I can certainly hand code it, but why bother if it's already in the vba libraries someplace.
I've searched for a solution, but it does appear that the standard answer is to hand code it.
My aproach would be to create a Form, add a ListBox, Ok, Cancel and the ShowModal property.
To use it first set the ListBox RowSource according to what you need:
https://msdn.microsoft.com/en-us/library/office/ff196460.aspx
Then make it visible, manage Ok/Cancel and then use the ItemsSelect property (multiselect is possible):
https://msdn.microsoft.com/en-us/library/office/ff823015.aspx
Yup, no such thing.
Hand-code it, and keep it as part of your VBA "toolbox" - make yourself an add-in that other VBA projects can reference, so you can reuse the code without having to rewrite it every time.
Then export the code modules from your host document, upload them to a GitHub repository, and share your solution with the world so the next person looking for it doesn't need to implement it from scratch again.
The VBA standard library is rather limited, and beyond MsgBox there isn't much available in terms of built-in UI. That's just how it is.
The description
I am writing a couple of Excel UDFs in COM Servers. I'd like to get the standard help (Insert Function dialog) that you get when you press fx. Yes, I can see my COM Server listed in among the Category drop down, but
I also see Equals, GetHashCode, GetType, and ToString (which are fairly undesirable to expose to the Excel user),
selecting my COM Server brings up the *Function Arguments*[1] dialog with no argument information and no description of the function.
Here is the lameness that I get:
Insert Function dialog http://www.iwebthereforeiam.com/files/Insert%20function%20dialog.gif
Excel Function Arguments dialog http://www.iwebthereforeiam.com/files/Function%20Arguments%20dialog.gif
The question
Are there .NET attributes I could put on the methods to pass this through to Excel?
Can I provide a description of the function?
Can I provide a description of the parameters?
Can I provide a category name for my functions, so that I get something better than just the ProgID?
(I see that it looks sadly easy to do in ExcelDNA, but I am not going that route. Emulating govert's code [custom attributes, a loader of some sort, etc.] looks like it would be pretty hard.)
Additional background
If you have not done work with Excel + COM Servers before, here are some useful resources to get up to speed:
Previous StackOverflow questions:
How to get COM Server for Excel written in VB.NET installed and registered in Automation Servers list?
How Add a COM-Exposed .NET Project to the VB6 (or VBA) References Dialog?
Other resources:
Writing user defined functions for Excel in .NET
Build and Deploy a .NET COM Assembly
Writing Custom Excel Worksheet Functions in C#
Edit 2009-10-20 14:10
I tried out calling Application.MacroOptions in a Sub New().
No Sub New()
Semi-acceptable: Function is listed under category ProgID.
Shared Sub New()
Not acceptable: build-time error.Cannot register assembly "...\Foo.dll".
Exception has been thrown by the target of an invocation.
Sub New()
Not acceptable: category is not listed in Insert Function dialog.
I suspect this is a problem both for MacroOptions and for the more involved route recommended by Charles.
Edit 2009-10-20 14:55
On the plus side, Mike's recommendation to create an interface to implement did kill off the annoying extra methods that were exposed.
Edit 2009-10-20 15:00
This Microsoft article from early 2007 (via Mike's link) seems a rather complete answer on the topic:
Automation Add-ins and the Function
Wizard
Each Automation Add-in has its own
category in the Excel Function Wizard.
The category name is the ProgID for
the Add-in; you cannot specify a
different category name for Automation
Add-in functions. Additionally, there
is no way to specify function
descriptions, argument descriptions,
or help for Automation Add-in
functions in the Function Wizard.
1 Huh, a StackOverFlow bug. It looks like you cannot italicize a string inside an explicit HTML ul-list?
Some of this is easy to correct, other parts of it is rather hard. All of it is do-able, though, if you are willing to put the time in.
You wrote:
I also see Equals, GetHashCode,
GetType, and ToString (which are
fairly undesirable to expose to the
Excel user)
Yes, agreed, this definitely undesirable, but it can be prevented. This is occurring because your class is inheriting from 'System.Object', as all .NET classes do, and your default interface that is exposed to COM is including these members. This occurs, for example, if you use the 'ClassInterfaceAttribute', using the setting 'ClassInterfaceType.AutoDual'.
E.g. in C#:
[ClassInterface(ClassInterfaceType.AutoDual)]
In VB.NET:
<ClassInterface(ClassInterfaceType.AutoDual)>
The use of 'ClassInterfaceType.AutoDual' should be avoided, however, in order to prevent the members inherited from 'System.Object' from being exposed (as well as to prevent potential versioning issues in the future). Instead, define your own interface, implement the interface in your class, and then mark your class with the 'ClassInterface' attribute with a value of 'ClassInterfaceType.None'.
E.g., using C#:
[ComVisible(true)]
[Guid("5B88B8D0-8AF1-4741-A645-3D362A31BD37")]
public interface IClassName
{
double AddTwo(double x, double y);
}
[ComVisible(true)]
[Guid("010B0245-55BB-4485-ABAF-46DF4356DB7B")]
[ProgId("ProjectName.ClassName")]
[ComDefaultInterface(typeof(IClassName))]
[ClassInterface(ClassInterfaceType.None)]
public class ClassName : IClassName
{
public double AddTwo(double x, double y)
{
return x + y;
}
}
Using VB.NET:
<ComVisible(True)> _
<Guid("5B88B8D0-8AF1-4741-A645-3D362A31BD37")> _
Public Interface IClassName
Function AddTwo(ByVal x As Double, ByVal y As Double) As Double
End Interface
<ComVisible(True)> _
<Guid("010B0245-55BB-4485-ABAF-46DF4356DB7B")> _
<ProgId("ProjectName.ClassName")> _
<ComDefaultInterface(GetType(IClassName))> _
<ClassInterface(ClassInterfaceType.None)> _
Public Class ClassName
Implements IClassName
Public Function AddTwo(ByVal x As Double, ByVal y As Double) As Double _
Implements IClassName.AddTwo
Return x + y
End Function
End Class
By making use of the 'ClassInterfaceAtribute' with a value of 'ClassInterfaceType.None', the inherited 'System.Object' memebers are excluded, because the class's interface is not made COM-visible. Instead, only the implemented interface ('IClassName' in this example) is exported to COM.
The above is also making use of the 'ComDefaultInterfaceAttribute'. This is not very important, and does nothing if you implement only one interface -- as in this example -- but it is a good idea in case you add an interface later, such as IDTExtensibility2.
For more detail on this, see:
(1) Managed Automation Add-ins by Andrew Whitechapel.
(2) Writing Custom Excel Worksheet Functions in C# by Gabhan Berry.
Ok, now to the hard part. You wrote:
Selecting my COM Server brings up the
Function Arguments[1] dialog with no argument information and no
description of the function.
Can I provide a description of the
function?
Can I provide a description of the
parameters?
Can I provide a category name for my
functions, so that I get something
better than just the ProgID?
The easiest approach here is to make use of the Application.MacroOptions method. This method enables you to provide a description of the function and specify which category under which you want it to be displayed. This approach does not allow you to specify any information for the functions parameters, unfortunately, but techniques that allow you to do so are very complicated, which I'll get to later. [Correction: The 'Application.MacroOptions' method only works for UDFs created via VBA and cannot be used for automation add-ins. Read on for more complex approaches to handle registration of UDFs containe in an automation add-ins -- Mike Rosenblum 2009.10.20]
Note that the help files for Excel 2003 and help files for Excel 2007 state that a string can be provided to the category argument in order to provide a custom category name of your choice. Beware, however, that the help files for Excel 2002 do not. I do not know if this is an omission in the Excel 2002 help files, or if this is a new capability as of Excel 2003. I'm guessing the latter, but you would have to test to be sure.
The only way to get your parameter information into the Function Wizard is to use a rather complex technique involving the 'Excel.Application.ExecuteExcel4Macro' method. Be warned though: many Excel MVPs have struggled with this approach and failed to produce a result that is reliable. More recently, though, it appears that Jan Karel Pieterse (JKP) has gotten it worked out and has published the details here: Registering a User Defined Function with Excel.
Skimming that article you'll see that it is not for the faint of heart. Part of the problem is that he wrote it for VBA / VB 6.0 and so all that code would have to be translated to VB.NET or C#. The key command, however, is the 'Excel.Application.ExecuteExcel4Macro' method, which is exposed to .NET, so everything should work fine.
As a practical matter, however, I vastly prefer using the 'Excel.Application.MacroOptions' approach because it is simple and reliable. It does not provide parameter information, but I have not yet had a strong need to motivate me to take on the 'ExecuteExcel4Macro' approach.
So, good luck with this, but my advice would be to utilize the 'MacroOptions', unless you are being paid by the hour. ;-)
-- Mike
Follow-up to Hugh's Replies
I tried out calling
Application.MacroOptions in a Sub
New().
No Sub New() Semi-acceptable: Function
is listed under category ProgID.
Shared Sub New() Not acceptable:
build-time error. Cannot register
assembly "...\Foo.dll". Exception has
been thrown by the target of an
invocation.
Sub New() Not acceptable: category is
not listed in Insert Function dialog.
I suspect this is a problem both for
MacroOptions and for the more involved
route recommended by Charles.
You can't use shared (aka "static") classes or constructors when exposing your classes to COM because COM has no knowledge of this concept and so it cannot compile -- as you found out! You might be able to apply a 'COMVisibleAttribute' with a value of 'False' to the shared constructor, to at least allow it to compile. But this wouldn't help you in this case anyway...
Trying to register your automation add-in via the automation add-in itself might prove tricky. I realize that this is desirable in order to keep it as a single, stand-alone component, but it might not be possible. Or at least this won't be easy.
The issue is that automation add-ins are demand loaded. That is, they are not really there until Excel attempts to access the first worksheet function from your automation add-in. There are two issues related to this:
(1) If you put your registration code within the constructor for your class, then, by definition, your function wizard information cannot exist until the function has been called for the first time.
(2) Your constructor might be executing when Excel is not ready to accept automation commands. For example, an automation add-in is typically demand-loaded when the user begins to type in the name of one of the user-defined functions (UDFs) defined in the automation add-in. The result is that the cell is in edit-mode when your automation add-in first loads. If you have automation code within your constructor during edit mode, many commands will fail. I do not know if the 'Excel.Application.MacroOptions' or 'Excel.Application.Excel4Macro' methods have a problem with this, but many commands will choke when trying to execute while the cell is in edit mode. And if the automation add-in is being loaded for the first time because it is being called while the Function Wizard is open, I have no idea if these methods can work right.
There is no easy solution to this if you wish to have your automation add-in to be completely stand-alone with no other support. You can, however, create a managed COM add-in that will register your automation add-in for you via 'Excel.Application.MacroOptions' or the 'Excel.Application.Excel4Macro' approach when Excel starts up. The managed COM add-in class can be in the same assembly as that of your automation add-in, so you still only need one assembly.
By the way, you could even use a VBA workbook or .XLA add-in to do the same -- use the Workbook.Open event in VBA to call the registration code. You just need something to call your registration code when Excel starts up. The advantage to using VBA in this case is that you could utilize the code from the Jan Karel Pieterse's Registering a User Defined Function with Excel article as-is, without having to translate it to .NET.
On the plus side, Mike's
recommendation to create an interface
to implement did kill off the annoying
extra methods that were exposed.
lol, I'm glad something worked!
This Microsoft article from early 2007
(via Mike's link) seems a rather
complete answer on the topic:
Automation Add-ins and the Function
Wizard
Each Automation Add-in has its own
category in the Excel Function Wizard.
The category name is the ProgID for
the Add-in; you cannot specify a
different category name for Automation
Add-in functions. Additionally, there
is no way to specify function
descriptions, argument descriptions,
or help for Automation Add-in
functions in the Function Wizard.
This is a limitation for the 'Excel.Application.MacroOptions' approach only. (My apologies, I had forgotten about this limitation of the 'Excel.Application.MacroOptions' method with respect to automation add-ins when I wrote my original answer, above.) The more-complex 'Excel.Application. ExecuteExcel4Macro ' approach, however, absolutely does work for automation add-ins. It should also work for .NET ("managed") automation add-ins as well, because Excel has no idea whether it is loading a COM automation add-in created via VB 6.0/C++ versus a managed COM automation add-in created using VB.NET/C#. The mechanics are exactly the same from the COM side of the fence because Excel has no idea what .NET is, or that .NET even exists.
That said, the 'Excel.Application.Excel4Macro' approach would definitely be a lot of work...
You could either use one of the .Net Excel systems such as ExcelDNA or ADDIN Express, or try to adapt one of the VBA/VB6 solutions: look at Laurent Longre's FunCustomise
http://xcell05.free.fr/english/index.html
or Jan Karel Pieterse's article at http://www.jkp-ads.com/Articles/RegisterUDF00.asp
which uses a function overloading hack.
I have a link in one column and, based on it, I want
Number of Google searches in column 2
Page rank of first result in column 3
I know this can be done, as I saw a friend pulling google search result right in Excel. If anyone knows, please share how I could do that.
If I correctly interpret your question, one of the tasks you had to do is
How do I get programmatically the Google page rank for a list of URLs?
You can find the code to do this in this CodeProject article:
Request Google´s Pagerank programmatically
Regarding the Excel part: it depends which programming framework or platforms you could use. You could use to create a .NET extension for Excel using the Microsoft Visual Studio Tools for Office.
From Excel there is Data->Get External Data->New Web Query. Is this what you want?
You have two options, both of which are unfortunately poorly documented.
If you are comfortable in C/C++, you can write a special DLL called an "XLL" that you can call during Excel runtime. There is some sparse documentation available. Note that this stuff isn't very fun to use.
If you prefer .NET, there is a binding for the entire Office suite outlined here that allows you to write COM-based methods that you can call from Office. It is intended for automation, but you can write any managed code you want and have Excel call into it.
There is also what Remou just suggested; I don't actually own a copy of Excel to test that out, but it may be the easiest option.
By link i meant keywords and not URL. I want to put a keyword in one cell and pull number of searches and page rank in adjacent cells.
I tried doing the same with web query in excel but i can only reach till the number of searches. that too not in the proper cell (trying to figure out). But i have no clue about how to get the pageranks.
I am not that tech savvy to code a binder or plugin for myself. Although i am checking the link by splattne. Please focus more light on it. Is it gonna be time consuming if i try to make this one..?
Regards
Thinkjayant
There are some nice plugins for this (in various languages) on GitHub:
http://github.com/search?langOverride=&language=&q=pagerank&repo=&start_value=1&type=Repositories&x=0&y=0
I have a PR checker functions in my Excel plugin "SeoTools".
http://nielsbosma.se/projects/seotools/