ExecuteExcel4Macro on custom xll functions - c#

I have a C++ .xll addIn for Excel. The following test worksheet function works fine with the xll loaded:
LPXLOPER __stdcall Test()
{
return &xlstring("Yayage",true)
}
i.e. =Test() returns "Yayage" in the worksheet. xlstring is my own custom method which turns a string into an excel string and specifies whether excel or the xll are responsible for freeing its' memory.
I intend to use VBA to produce a 'GUI companion' AddIn for versions 2003 and previous, and a C# Excel 2007 AddIn project for 2007 onwards. These will both work with a version-independant .xll that communicates with a web service.
Both C# and VBA have the following Excel functions:
Application.ExecuteExcel4Macro(string)
Application.Evaluate(string)
Application.Run(...)
These work fine (Except .Run which, in C#, wants to take 32 parameters) with normal worksheet functions that return strings, e.g. in VBA:
MsgBox Application.<Any above method>("=Trim("" Billy Bob Fred "")")
Produces a message box containing "Billy Bob Fred"
However, I cannot get this to work with any of my custom worksheet functions. Registering them as commands instead of worksheet functions doesn't work either.
I've tried different styles of function name, with and without = / (), and just about everything else I can think of.
Can anyone help me with this?

Is your xlstring returning the address of a temporary object?

Related

Call xll functions in c# app

Is there any way I can import an xll into my C# WPF project? I require some of the functions that are usually called via the xll addin in Excel. I have read that xll performs like normal dlls, but sharpdevelop does not seem to be able to read any of its functions and methods. I know the formulas that are usually called in excel, can I access those same functions in my WPF app?
If, and only if :
you know the prototype of the function.
arguments are only primitives C type , (no xloper type).
the function is independent of Excel (does not require to be initialized by excel)
then yes you can call it from C# thanks to DllImport

How to call a C# method for OnUndo in an Excel VSTO add-in?

I'm currently writing a VSTO add-in for Excel in C#, and am having trouble getting the undo functionality to work correctly.
As far as I can tell from the documentation, you are meant to use Application.OnUndo to register an undo callback. However, it's not clear to me whether it's possible for the Procedure argument to refer to a C# method.
Ideally I would like to set the undo callback to an instance method, eg:
this.Application = Globals.ThisAddIn.Application;
// ...
this.Application.OnUndo("Undo color change", "this.UndoTextColorChange");
Unfortunately, while this registers an undo, actually clicking 'undo' in Excel gives the error:
Cannot run the macro 'this.UndoTextColorChange'. The macro may not be available in this workbook or all macros may be disabled.
To me, this almost suggests that the Procedure argument has to be a VB macro (rather than a C# method). However, it's also possible that I haven't been able to work out the fully-qualified procedure name to use in the .OnUndo call.
Is it possible to have Application.OnUndo call a C# method? If so, what should I use as the argument for Procedure? If not, how is undo functionality typically implemented in C# VSTO add-ins?
You are right that the Procedure argument of the Application.OnUndo has to be a VBA macro.
If you want the Application.OnUndo to call a C# method you will have to add a VBA macro to your workbook which will be triggered by the Application.OnUndo. Then the macro may call C# code from your VSTO add-in. Here is a good article describing how you can call VSTO code from VBA macro.
In order to inject a VBA macro into a workbook from your VSTO add-in you may create an .xlam Excel Add-in and distribute it together with the VSTO Add-in (basically put it into the same folder or even embed it into VSTO Add-in itself as a resource file).
The .xlam Excel Add-in will be very simple and will contain a single function like below:
Sub UndoLastAction()
Application.COMAddIns("YourVSTOLibraryName").UndoInVSTO
End Sub
When VSTO Add-in is started it can load .xlam add-in, so all the workbooks will have access to that VBA macro even if the workbook itself is not macro-enabled.
Below is a sample how you can load .xlam Excel Add-in from VSTO:
var undoManager = Globals.ThisAddIn.Application.AddIns.Add("UndoManager.xlam", true);
undoManager.Installed = true;
Now, when you execute a certain modification via your VSTO Add-in and then would like to be able to Undo it you will have to call Application.OnUndo:
Globals.ThisAddIn.Application.OnUndo("Undo Last Operation", "UndoManager.xlam!UndoLastAction");
When Application.OnUndo is executed the Excel will allow user to click "Undo" button which will trigger UndoLastAction macro declared in the .xlam Add-in which will trigger UndoInVSTO function declared in YourVSTOLibraryName dll where you can do whatever you need to undo your last operation.

HRESULT Codes in Excel interop in C#

I'm looking for a clean way to output errors in C# when using Excel with interop.
When the file is not "right" a have a message like "blabla HRESULT: 0x800AC472".
I'd rather want a message like "The file used has this or that problem". In order to do that I would need to know to what error does each HRESULT map to ?
How to get such a list of errors ?
I've look at MSDN, found some description, but I can't seem to find the list of all codes like the "0x800AC472" mention above.
I have the Excel HRESULT code 0x800AC472 as VBA_E_IGNORE, which indicates that Excel has 'suspended the object browser'.
Under certain circumstances Excel will reject all incoming COM requests. Two cases where this happens are where the user
is busy editing a formula, or
presses down the mouse button on the Excel sheet.
There might well be other cases - for example I'm not sure what the error code is when Excel is busy calculating.
If you are doing COM automation to talk to an Excel instance that is interactively being used, then any COM call you make to Excel might return this error. One approach I take with Excel-DNA (where the interop always happens from an add-in inside the Excel process) is to attempt to call Application.Run(...) to run a macro in the add-in. Once the Application.Run call succeeds, the macro will run on the main Excel thread in a context where the COM requests won't fail due to Excel suspending the COM calls.
Some other COM errors you can expect from Excel are:
const uint RPC_E_SERVERCALL_RETRYLATER = 0x8001010A;
const uint RPC_E_CALL_REJECTED = 0x80010001; // Not sure when we get this one?
// Maybe when trying to get the Application object from another thread,
// triggered by a ribbon handler, while Excel is editing a cell.
const uint VBA_E_IGNORE = 0x800AC472; // Excel has suspended the object browser
const uint NAME_NOT_FOUND = 0x800A03EC; // When called from the main thread, but Excel is busy anyway.

Calling function in XLL file from C#

I have a xll file which have a function and I want to call that function from C#.
This xll file is used in excel.any body have idea how to do that?.I tried refrencing the xll file but I am not getting the value.If I open excel like start-->programms-->excel and
in excel if i directly give the function I am getting right value.Same thing If i automate excel in c# and opened excel from Microsoft.Office.Interop.Excel and applied the function I am getting error
You probably won't be able to invoke the function directly because an XLL will expect the Excel interfaces to be driving. You'd have to do some serious faking.
Automating it through Excel will work though.
An xll is just a dll. If you know the signature of the function you want to call, you can call it just like any other function. If you don't know the signature but can load the add-in in Excel, there is a way to get Excel to tell you the signature.
Automation only works if you are running Excel. There is no need for that once you know the signature.
There is a few tools you can use:
XLL Plus
XLL Host
The question has also been asked on MSDN Use XLL from C#, this is the answer:
If it is a COM project, you can add it via the COM tab in the Add reference window.
If you need to create a .NET assembly from the dll, you can try to use Type Library Import tool to create a wrapper around the dll:
tlbimp.exe xll.dll /out:xllnet.dll
If the object does not support COM, but only native calls, you will need to platform invoke the methods using the DllImport attribute. See the Platform Invoke tutorial for more information.
I gave all 3 suggestions a go but didn't have any luck. Given the author of the XLL tool Excel-DNA recommends using a tool I suspect consuming a XLL in a Winform/WPF/Console or Web app is not trivial:
https://stackoverflow.com/a/2865023/495455

Create UDF using VSTO and no VBA

Similar to this question (but in my case not VSTO SE), however, I just want to confirm that it is not possible to create a UDF using pure VSTO in Visual Studio 2005 and Excel 2003 - so, to absolutely clear, my question is:
Is it possible to create a Excel 2003 UDF using Visual Studio 2005 and a VSTO solution without using any VBA or other tricks?
I'm aware of ManagedXLL, ExcelDNA, Excel4Net etc but don't want to consider those for the moment.
Thanks
Concerning whether there is a way around COM or VBA I don't think that it is possible (at least not without any very dirty tricks). The reason is that the only way Office can execute external code (i.e. you add-in) is via COM. Even VSTO is still using the old IDTExtensibility2 COM interface underneath. IDTExtensibility2 is a COM interface that all add-ins for Microsoft Office applications must implement.
Before VSTO, Office add-ins had to implement this IDTExtensibility2 interface themselves. In such a COM based add-in (or COM-visible managed add-in) you can simply add your UDF as described here.
However, now with VSTO, there is an additional layer of abstraction: VSTO uses a so-called Solution Loader implementing IDTExtensibility2, which is a dll provided by the VSTO runtime. This means that your add-in is no longer COM-visible. Hence, if you added a UDF to your VSTO add-in it won't be visible to Office.
Paul Stubbs explains on his blog how to do with VSTO and VBA: How to create Excel UDFs in VSTO managed code
Create a class with your functions in VSTO
<System.Runtime.InteropServices.ComVisible(True)>
Public Class MyManagedFunctions
Public Function GetNumber() As Integer
Return 42
End Function
End Class
Wire up your class to VBA in VSTO
Private Sub ThisWorkbook_Open() Handles Me.Open
Me.Application.Run("RegisterCallback", New MyManagedFunctions)
End Sub
Create Hook for managed code and a wrapper for the functions in VBA
In a VBA module in your spreadsheet or document
Dim managedObject As Object
Public Sub RegisterCallback(callback As Object)
Set managedObject = callback
End Sub
Public Function GetNumberFromVSTO() As Integer
GetNumberFromVSTO = managedObject.GetNumber()
End Function
Now you can enter =GetNumberFromVSTO()
in a cell, when excel starts the cell
value should be 42.
I don't understand why you want to do this?
VSTO and exposing UDFs via COM interop (from .NET) are two different tasks.
Why do you want to host a UDF method inside of a VSTO project?
The way you register the .net UDF assembly means it will have to be in a seperate project to the VSTO project. However if you wanted to share data between the two apps then you have a variety of native .net methods for this, or simply "call" the UDF function from the appropriate range object within your VSTO project.
Is there a reason that you feel it is necessary to have UDF in VSTO?
In this article Eric Carter goes on to explain how to do what you're asking. At the top he even links to an update of the aforementioned blog post.
Create the UDF as Eric Carter explained and pass as parameter to your UDF an Excel range. You're able to access Excel's object model through VSTO by using the given range:
Excel.Range rg = param1 as Excel.Range;
Excel.Workbook wb = rg1.Worksheet.Application.ActiveWorkbook;
I am not familiar with a method of creating a UDF in Excel 2003 using VS2005 and VSTO without having at least a bit of VBA. Here are 2 links that discuss this a bit further:
<Link>
<Link>

Categories

Resources