A Refresh button/method in an Excel Add-In needs to be invoked via an external winform application. Here is where I am up to:
private Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
public FormMain()
{
InitializeComponent();
RefreshExcelSheet(#C:\a.xls");
}
private bool RefreshExcelSheet(string path)
{
using (var wb = excel.Workbooks.Open(path).WithComCleanup())
How do I click the Refresh button or simply invoke its event?
I was looking at these articles but they are using VBA, I want a Winform app to open the spreadsheets and click the button:
Accessing a VSTO application-addin types from VBA (Excel)
Expose VSTO functionality to VBA w/o local admin
The simplest way to solve this problem is to just expose the existing custom .net method as a COM method by making is a com callable wrapper object (CCW).
VSTO provides you with a simple method to expose the COM Automation server.
http://blogs.msdn.com/b/andreww/archive/2007/01/15/vsto-add-ins-comaddins-and-requestcomaddinautomationservice.aspx
EDIT BY OP:
Andrew Whitechapel has updated the article, but I cannot get it to work. Even with StandardOleMarshalObject and Register for COM interop I still get the same error message as detailed in this article: http://blogs.msdn.com/b/andreww/archive/2008/08/11/why-your-comaddin-object-should-derive-from-standardolemarshalobject.asp
Anonymous Type's suggestion is surely the best approach if you can extend the Excel add-in.
If it's a 3rd party tool it's still possible to use the ribbon's IAccessible interface to invoke the ribbon button. However, you can expect this to be much more complicated. In case you have to follow that path here are some links to get you started:
How to get Ribbon custom Tabs IDs?
http://www.codeproject.com/Articles/38906/UI-Automation-Using-Microsoft-Active-Accessibility
Related
Is it possible to unregister methods that I previously registered via ExcelIntegration.RegisterMethods without restarting Excel?
Basically, I'm looking for the opposite of ExcelIntegration.RegisterMethods.
Excel-DNA does not currently let you unregister methods in a loaded add-in. This is just a limitation of the implementation, and how exported functions are hooked up to the native exports of the .xll. You an however unload an entire Excel-DNA add-in, (from another add-in) as long as it only exports UDFs and not ribbons, an RTD server or other COM features.
Another workaround is to re-register the function as "hidden". The new registration will take up another slot in the (fixed-size) .xll export table, but will at least not appear in the worksheet function completion list anymore.
how I can programatically load and unload a VSTO add-in in Word on button click.
I have unloaded it on event click bu using below code.
foreach (Office.COMAddIn addin in Globals.ThisAddIn.Application.COMAddIns)
{
if (addin.ProgId == "DocDrafter")
{
addin.Connect = false;
return;
}
}
but on document change and document start I have to load the add-in again.
But once addin is unloaded I am unable to load it again.
You have a couple of possibilities - it depends on what, exactly, you want to do. To begin with, you should (have) read the information in the Word object model Help for the AddIns collection and the Addin object. (We're talking about Globals.ThisAddIn.Application.Addin/s for your VSTO project.)
There are basically two approaches. One is to used the Installed property of the Addin object which loads (=true)/unloads(=false) the add-in from the Word UI, leaving it in the list of Add-ins (the list in Word's File/Options/Add-ins tab) so that the user (or your code) can load it again as required. It sounds like this is what you need.
The other approach is to remove/add the add-in to/from that list. Use the Addin.Delete method to remove the add-in; use Addins.Add to add an add-in to the list.
If you disconnect the Add-in from within the VSTO project, as your code does, I don't think there's any way within the scope of VSTO that you're going to get it to connect, again...
Help topic in the documentation: start here:https://msdn.microsoft.com/en-us/vba/word-vba/articles/addins-add-method-word
I'm currently developing a VSTO Word Document-Level addin, and a WPF app. The WPF app uses the classes and methods in the Microsoft.Office.Interop.Word.dll assembly to open the Word DOCX file associated with the Document-Level addin.
My WPF app needs to communicate with the VSTO Word Document-Level addin to update the document while the DOCX file is open.
I found an article on the web called VSTO Add-ins, COMAddIns and RequestComAddInAutomationService that shows how to communicate to an Excel Addin from VBA. I thought I could use the same ideal to make my WPF app communicate with my VSTO Word Document-Level addin.
The article describes how to override the RequestComAddInAutomationService method in the add-in class.
public partial class ThisAddIn
{
private AddinUtilities addinUtilities;
protected override object RequestComAddInAutomationService()
{
if (addinUtilities == null)
{
addinUtilities = new AddinUtilities();
}
return addinUtilities;
}
}
My VSTO Word Document-Level addin doesn't have a ThisAddin class that inherits from the Microsoft.Office.Tools.AddinBase class. It has a ThisDocument class that inherits from the Microsoft.Office.Tools.Word.DocumentBase class. And the DocumentBase class doesn't contain a method called RequestComAddInAutomationService that can be overridden.
So the question is, is it possible for another app to communicate with a VSTO Word Document-Level addin? And if so can you please show me a C# example of how to do it?
The VSTO technology doesn't have any tools that expose code in a document-level customization to outside code, such as an Add-in. It apparently is possible, although I've never tried it. There's a discussion on MSDN, in the VSTO forum, that outlines the steps involved.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/10decfd2-b1b6-4bf2-aa99-16c1f08b9159/call-code-in-doclevel-assembly-from-addin?forum=vsto
I've copied McLean Schofields "Answer" to the question below as there's no knowing when the link may break.
That discussion mentions a sample from Andrew Whitechapel. That sample is no longer available, but his blog article that relates to it is:
http://blogs.msdn.com/b/andreww/archive/2008/03/20/integrating-doc-level-and-add-in-solutions.aspx.
Quote from McLean Schofield in MSDN post Dec. 16 2008:
"In the sample, .NET remoting is used to send the IDocumentCommands object from the document-level customization to the application-level add-in, and to transmit calls that the add-in makes on this object to the document customization. .NET remoting comes into play in the definition of the DocumentCommands class in the document customization. This class
implements the IDocumentCommands interface, which is how the add-in views this object, and it also derives from MarshalByRefObject, which enables it to be transmitted to the add-in (across application domains) via .NET remoting.
In a nutshell, this is how the sample works:
1.When the add-in loads, its override of the RequestComAddInAutomationService method exposes an IAddInCommands object to the document customization (and to any other Office solution that can access the Application.COMAddIns collection). This feature of add-ins is documented in more detail in Calling Code in Application-Level Add-ins from Other Office Solutions. When you expose an object in an add-in in the way described in this topic, you enable the object to be accessed by other Office solutions via COM interop.
2.When the document customization starts, code in ThisDocument_Startup gets the COMAddIn object that represents the add-in, and calls the RegisterDocument method exposed by the add-in to send it an instance of the IDocumentCommands object defined by the document customization. Because the instance it sends derives from MarshalByRefObject, this object is automatically sent to the add-in via .NET Remoting. For more information about .NET remoting, see Remotable and Non-remotable Objects.
3.Now the communication infrastructure is set up. When the user clicks on the actions pane button in the document customization, the btnCallAddIn_Click event handler uses the exposed IAddInCommands object to call the InsertText method defined in the add-in - this call uses the "standard CLR COM interop" that Andrew refers to. When the user clicks on the Ribbon button created by the add-in, the btnCallDocument_Click event handler uses the exposed IDocumentCommands object to call the InsertText method defined in the document customization - this call relies on .NET remoting.
Defining interfaces that are referenced by both the document-level customization and the application-level add-in is necessary in this scenario. For the add-in to call a method defined by the document customization (or vice versa), the solutions need a common "contract" object that defines the method. In order for both solutions to use the same object, the object must implement an interface that is defined in an assembly that both solutions reference. If you were to instead define this interface separately, once in the customization and again in the add-in, these interfaces would be viewed at run time as separate types, and the communication wouldn't work."
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>
I have a C# Excel Add-in project "MyExcelAddIn" that has a public method Foo() to do something complex. For testing purposes, the add-in also defines a toolbar button which is wired to Foo() so I can test this and verify that clicking the button calls Foo() and does what I want it to do. This is fine.
Now I want to call this method from a C# Windows Forms project. In the Windows Forms project I can create an Excel instance and make it visible and verify that my VSTO add-in is running as I can see the button and it works. But I can't work out how to call Foo() programatically from the Windows Forms project. I've googled a bit and got as far as getting the "MyExcelAddIn" COMAddIn object, but can't work out how to call Foo().
It looks something like this:
// Create Excel and make it visible
Application excelApp = new Application();
excelApp.Visible = true;
// I know my VSTO add-in is running because I can see my test button
// Now get a reference to my VSTO add-in
Microsoft.Office.Core.COMAddIns comAddIns = _excelApp.COMAddIns;
object addinName = "MyExcelAddIn";
Microsoft.Office.Core.COMAddIn myAddin = comAddIns.Item(ref addinName);
// This works, but now what? How do I make a call on myAddin?
// Note that myAddin.Object is null...
So I want to know what I can do to call Foo() from my Windows Forms application. Note that I have full control over both the Windows Forms application and the add-in and I suspect I have to make changes to both of them (particularly the add-in) but I have no idea how to do this.
Note that this is a VS2008 C# application and I'm using Excel 2003.
If you're building an application-level add-in, I believe this may be your answer: MSDN VSTO Article
It involves two steps: (From the article)
In your add-in, expose an object to other solutions.
In another solution, access the object exposed by your add-in, and call members of the object.
The other solution may be: (Again from the article)
Any solution that is running in a different process than your add-in (these types of solutions are also named out-of-process clients). These include applications that automate an Office application, such as a Windows Forms or console application, and add-ins that are loaded in a different process.
I'm using the SendMessage Win32 API to do this. My C# Add-in creates a "NativeWindow" with a uniqe window title that the WinForm app can locate.
I assume that your method Foo somehow interacts with Excel. Otherwise you can just add a reference to the assembly containing the class with the Foo method and call it from there without instantiating Excel.
The only other way I can think is to get a reference to your CommandBarButton through the excelApp object. CommandBarButton has a method called Execute which is similar to clicking the button. Something like this:
Excel.Application excelApp = new Excel.Application();
CommandBarButton btn = excelApp.CommandBars.FindControl(...) as CommandBarButton;
btn.Execute();
For anyone else who finds this here's what I did:
object addInName = "AddinName";
var excelApplication = (Microsoft.Office.Interop.Excel.Application)Marshal.GetActiveObject("Excel.Application");
COMAddIn addIn = excelApplication.COMAddIns.Item(ref addInName);
addIn.Object.AddinMethodName(params);
Also had to add a reference to Microsoft.Office.Core under COM and Excel.Interop under Assemblies.