VSTO Add-ins, COMAddIns and RequestComAddInAutomationService

The COMAddIns property is a collection of COMAddIn objects exposed by Office applications that support COM add-ins. The COMAddIn interface defines a small number of methods/properties, such as the ProgId of the add-in and the Connect state. It also defines an Object property. By default, the value of the Object property is null. An add-in can set this value itself, and the purpose is to expose this add-in’s functionality to external callers. VSTO supports this mechanism through a new virtual method on the AddIn base class, RequestComAddInAutomationService. Most developers will never use this service, and its an example of one of the little things that VSTO does to support the widest range of add-in developers. Here’s how it works.

In your VSTO add-in class, you decide which methods you want to expose to external callers, and wrap these methods in a ComVisible class. Then, you override the RequestComAddInAutomationService virtual method to return an instance of this class. For example, we’ll expose a DisplayMessage method. The calls to this method will be made via automation, so I’m defining an automation (dual) interface to define the method:




public interface IAddinUtilities


    void DisplayMessage();



I can also define a class that will implement the interface to perform some suitable operation in the method:



public class AddinUtilities : IAddinUtilities


    public void DisplayMessage()


        MessageBox.Show(“Hello World”);




Then, in my add-in class, I override RequestComAddInAutomationService to return an instance of this class. As you can see, the programming model for this method is very similar to the generic RequestService method that VSTO uses for the new extensibility interfaces (although of course the underlying mechanism is completely different):

public partial class ThisAddIn


    private AddinUtilities addinUtilities;


    protected override object RequestComAddInAutomationService()


        if (addinUtilities == null)


            addinUtilities = new AddinUtilities();


        return addinUtilities;




Then, I can create a suitable Office document and insert some VBA to call this exposed method. So, if my add-in is an Excel add-in, I can create an XLSM (macro-enabled) workbook and Alt-F11 to get the VBA editor up. I’ll put a CommandButton on the worksheet, and code it to call the DisplayMessage method:

Private Sub CommandButton1_Click()

    Dim addin As Office.COMAddIn

    Dim automationObject As Object

    Set addin = Application.COMAddIns(“ExcelAddinService”)

    Set automationObject = addin.Object


End Sub


From the VBA code, you can see that my add-in is registered as “ExcelAddinService”. All I’m doing is fetching the COMAddIn object that represents this particular add-in in the COMAddIns collection (specified by ProgId). Then, I’m fetching the Object property of this add-in, and invoking the exposed method. If you’re following along, joining the dots as it were, you can infer that the VSTO runtime takes the return value from the RequestComAddInAutomationService method in the add-in to set the COMAddIn::Object property to the instance of the AddinUtilities class defined in the add-in.

Note that my VBA is using late binding – I don’t have a reference to the add-in at design-time. If the add-in exposed many methods with varying signatures, it might be worth adding a reference to it in the VBA editor.

So, to show this, I’ll expand my add-in to expose a second method, this one takes a couple of parameters and uses them to interact with the active Worksheet.




public interface IAddinUtilities


    void DisplayMessage();

    void SetCellValue(String cellAddress, object cellValue);





public class AddinUtilities : IAddinUtilities


    public void DisplayMessage()


        MessageBox.Show(“Hello World”);



    public void SetCellValue(String cellAddress, object cellValue)


        Excel.Worksheet sheet = (Excel.Worksheet)


        Excel.Range cell = sheet.Cells.get_Range(

            cellAddress, Type.Missing);

        cell.Value2 = cellValue;





In my VBA, I can add a reference to the AddinService add-in, so that I get design-time intellisense. I’ll put a second CommandButton on the worksheet, and code it to call the SetCellValue method:

Private Sub CommandButton2_Click()

    Dim addin As Office.COMAddIn

    Dim utilities As ExcelAddinService.addinUtilities

    Set addin = Application.COMAddIns(“ExcelAddinService”)

    Set utilities = addin.Object

    Call utilities.SetCellValue(“a1”, 456.78)

End Sub


I can even write a Windows Forms app to automate Excel externally, and invoke the exposed add-in methods. For example, this is a Windows Forms app with 2 buttons – I launch Excel when the form loads, and cache the Application and the add-in Object. Then, I call one of the exposed methods in each button Click handler:

public partial class WinTestAddinServiceForm : Form


    public WinTestAddinServiceForm()





    private Excel.Application excel;

    private ExcelAddinService.IAddinUtilities utils;


    private void WinTestAddinServiceForm_Load(object sender, EventArgs e)


        // Launch Excel, make it visible, and ensure there is

        // at least one sheet.

        excel = new Excel.Application();

        excel.Visible = true;



        // Fetch the add-in we want to exercise, and cache

        // its exposed object.

        object addinName = “ExcelAddinService”;

        Office.COMAddIn addin = excel.COMAddIns.Item(ref addinName);

        utils = (ExcelAddinService.IAddinUtilities)addin.Object;



    private void WinTestAddinServiceForm_FormClosed(

object sender, FormClosedEventArgs e)


        // Clean up all Excel object references.

        utils = null;

        excel = null;







    private void displayMessage_Click(object sender, EventArgs e)





    private void setCellValue_Click(object sender, EventArgs e)


        utils.SetCellValue(“a1”, 123.45);




As you can see, I’ve obviously got a reference to the ExcelAddinService assembly in this project – that’s only so that I can use the IAddinUtilities interface. Realistically of course, the interface would be best defined in an assembly separate from the add-in.

This feature seems like a small thing, but actually its part of a wider strategy to support the idea of Office as a true development platform. That idea implies at least some minimal level of interconnectivity support between various custom pieces in a solution.

UPDATE NOTE: See here for an update to this post: http://blogs.msdn.com/andreww/archive/2008/08/11/why-your-comaddin-object-should-derive-from-standardolemarshalobject.aspx


Comments (73)

  1. Qanuc says:


    I tried to use your code to builf an Outlook AddIn. The whole things works great until it reaches the line

    ‘utils = (ExcelAddinService.IAddinUtilities)addin.Object;’

    An Exception is thrown because addin.Object is a System.__ComObject and cannot be cast to my interface.

    Any idea about this?



  2. Garry Trinder says:

    Hi M – a few questions:

    Did you return an instance of the AddinUtilities class in the RequestComAddInAutomationService method?

    How did you attribute the class?

    Did you make the assembly ComVisible?

    Did you mark it as Register for COM interop?



  3. Conor says:

    I am also seeing the casting error when I try to write a C# (early-bound) program to replicate what I’ve seen here.  The late-bound vbs version works fine.  To answer your questions:

    1. Yes, I returned an instance of the AddinUtilities class in RequestComAddInAutomationService.
    2. attributes should match your example:




         public interface IAddinUtilities


             void DisplayMessage();




         public class AddinUtilities : IAddinUtilities


             public void DisplayMessage()


                 MessageBox.Show("Hello World");



    3. Your example only has methods marked as ComVisible.  

    I have tried marking the add in project to be comvisible such that reflector shows:

    // Assembly ExcelAddIn1, Version

    [assembly: AssemblyVersion("")]

    [assembly: AssemblyTitle("ExcelAddIn1")]

    [assembly: Debuggable(DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.EnableEditAndContinue | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.Default)]

    [assembly: CompilationRelaxations(8)]

    [assembly: AssemblyDescription("")]

    [assembly: Guid("8d818b4d-3f48-4e88-9e27-4559992a7325")]

    [assembly: RuntimeCompatibility(WrapNonExceptionThrows=true)]

    [assembly: ComVisible(true)] <==== HERE

    [assembly: AssemblyTrademark("")]

    [assembly: AssemblyConfiguration("")]

    [assembly: AssemblyFileVersion("")]

    [assembly: AssemblyCopyright("Copyright x00a9  2007")]

    [assembly: AssemblyCompany("")]

    [assembly: AssemblyProduct("ExcelAddIn1")]

    1. Beyond clicking "Make assembly COM-Visible" in the Build property Application..Assembly Information, is there another step to take?



  4. Mike Kelley says:

    The example code provided works fine for C# early binding – you have to set your add-in project’s Build settings to "Register for COM Interop" – as Andrew stated above.

    You do not need to set the ‘make assembly com visible’ as the decorations take care of the needed interfaces/classes.

    It will throw casting exceptions if you do not have this build option set.

  5. Scott says:

    In my ThisAddIn Class , I cann’t override RequestComAddInAutomationService method,what’s the problem.    

    Thanks & Regards

  6. Telmo says:


    I had also your problem , the solution i found was to change my project to a vb.net one,  that solved my problem.

    Now i have a problem each time i change the add  i have to remove and add the updated addin is this correct or am i missing something ?

    Thanks in advance


  7. Bartolomeo says:


    How to implement similar functionality in shimmed add-in?

  8. markovich says:

    Did you make the assembly ComVisible?

    Did you mark it as Register for COM interop?

  9. Denis_Rutovitz says:

    To Andrew Whitehead:

    your example is just what I need, except that I want to write the Addin in MS Studio 2005 VB, not in C++ (because (1) its 10 years since I last used C, and (2) I ‘m trying to make an addin of a body of code, forms etc written in VBA)

    Is it possible? Any suggestions ?

  10. Denis_Rutovitz says:

    Apologies, I should have said Andrew Whitechapel, not Andrew Whitehead.

  11. Oleg Krupnov says:

    Is there a way to avoid any VBA code and call managed routines directly? You see, I need to connect it to a KeyBinding command – a string kind of "ModuleName.MethodName", but instead of referencing to the corresponding VBA Module and Sub, I need to reference directly to my managed add-in (or customization) method. Is this possible? Having to write any VBA code would cause additional macro security issues and generally nullifies the idea. Thanks!

  12. Adam says:

    Thanks for the great article, one question though. I’ve put together an addon using your example here for Outlook 2003.

    What I’d like to do is start outlook through automation ie:

    dim app as new Outlook.Application()

    Then go ahead and read in the addin’s Object refrence.

    The problem is this: It works perfectly if outlook is already running, but if outlook is not running the Object always returns null.

    I’m guessing that my addin is not being loaded because Outlook.exe was started with automation, so the call to RequestComAddinAutomationService never happened.

    Do you know is this is the case? If so, do you know a work around, or an update to correct this behavior?

    Again, appriciate your work in writing this, it was a real help.

  13. Steve Booth says:

    I would be really grateful if you could describe how to overcom the early binding issue when calling an addin from .Net

    I can set the addin object to a .Net object and then call using late binding but i cannot for the life of my work out how to cast/set the addin object to my class created in the .Net addin

    I am using all the techniques described above. The addin is for Outlook 2003.

  14. Garry Trinder says:

    Adam – apologies for taking so long to reply. For some reason the email notifications from this post stopped coming to me.

    Anyway, this works fine for me with Outlook being externally automated. The only caveat is that when you first launch Outlook, it will take some time to perform housekeeping before you can be sure that all add-ins are actually loaded.

    So, you need to wait a reasonable period of time before attempting to retrieve your add-in. I’m not sure there’s a suitable event that Outlook fires that you could use – if not, you’ll have to figure out some other workaround.

  15. Garry Trinder says:

    Steve – apologies to you also for the delay.

    I’m not sure what you mean by the "early binding issue". Is this the same problem that Conor had? If so, the answer is the same one Mike Kelley gave – that is, make sure you have your project set to Register for COM interop.

  16. Paul Berridge says:

    Like Oleg Krupnov I want to avoid any VBA macros and link a keyboard shortcut to a comvisible method. Any idea how this can be done?


    Private Sub ThisAddIn_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup

           ‘ Start of VSTO generated code

           Me.Application = CType(Microsoft.Office.Tools.Excel.ExcelLocale1033Proxy.Wrap(GetType(Excel.Application), Me.Application), Excel.Application)

           ‘ End of VSTO generated code

           Me.Application.OnKey("^f", "ExcelAddIn2.tlb!HelloWorld")

       End Sub

    … and HelloWorld() is a comvisible function like this …

    Imports System.Runtime.InteropServices

    <ClassInterface(ClassInterfaceType.AutoDual), ProgId("ExcelAddIn2.ComClass1"), ComVisible(True)> _

    Public Class ComClass1

       Public Function HelloWorld() As Boolean


           Return True

       End Function

    End Class

  17. Garry Trinder says:


    Unfortunately, both Excel’s OnKey and Word’s KeyBindings are restricted to VBA macros only: you cannot directly use these to invoke managed code.

  18. Terry Aney says:

    So I attempted to do what your last comment said about putting the interface a seperate assembly.  When I do that, I only have following:

    namespace BTR.Extensibility.Excel.Interfaces


    [ComVisible( true )]
    [InterfaceType( ComInterfaceType.InterfaceIsDual )]
    public interface IAddinUtilities
        void TestArchitecture( int count );


    However when I try to COM register this, I get an error:

    RegAsm : warning RA0000 : No types were registered

    Any ideas?

  19. Terry Aney says:

    Just to clarify…I’m having early binding cast problems as well.

    Currently I have 3 projects:

    1) An Add-in project with essentially ThisAddin.cs and AddinUtilities.cs.

    2) An inteface assembly/project with only IAddinUtilities.cs.

    3) A Windows form application for the test host.  

    Both the test host and the add-in both reference the interfaces assembly.

    No assemblies have ‘register for com interop’ checked as I’m manually calling regasm after placing the assemblies in the appropriate directory (c:prog files…).  I plan on having my setup project do this, so I don’t want to have it ‘automatically’ done by VS.

    So I guess my question is, even given your setup above, does the IAddinUtilities interface show up in the registry anywhere?  The warning about ‘no types were registered’ above that I wrote happened on manual regasm calls as well as VS calls due to ‘register for com interop’.

    After regasm’ing both my add-in and interface assemblies, I have the following present in my registry (don’t think I’ve missed anything):







    [HKEY_CLASSES_ROOTCLSID{9E5B4D63-4365-30A5-AA35-07B926BECDA5}Implemented Categories]

    [HKEY_CLASSES_ROOTCLSID{9E5B4D63-4365-30A5-AA35-07B926BECDA5}Implemented Categories{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]





    "Assembly"="BTR.Extensibility.Excel.RBL.2003, Version=, Culture=neutral, PublicKeyToken=824d1f6daf83e0eb"




    "Assembly"="BTR.Extensibility.Excel.RBL.2003, Version=, Culture=neutral, PublicKeyToken=824d1f6daf83e0eb"




    Any information would be appreciated.

  20. Garry Trinder says:

    Terry – the regasm error message you’re getting is because you can’t regasm an assembly which doesn’t contain any createable types. An interface is not a createable type. So, you’d need to declare a class in your interface assembly that implements the interface (as in the original example in my post). This class could either be the real class used by your code, or it could simply be a dummy placeholder with ‘do nothing’ methods that will never get instantiated but serves to allow regasm to register the interface.

  21. Terry Aney says:

    Thanks for the info.  Either I’m not doing something right or there are other problems.  Here’s where I’m at:

    a) VSTOAddIn.dll – in RequestComAddInAutomationService, creates and returns AddinUtilities class.

    b) I’ve moved the IAddinUtilities and AddinUtilities interface/class back into the VSTOAddIn.dll to attempt to mimic your sample exactly and both are marked as COMVisible.  Note: the code is pasted below.

    c) Automation Client.exe – VSTOAddIn.dll and tries to cast to early bound type:

    d) My registry still looks about the ‘same’.  In that I only have AddinUtilities in registry and not the IAddinUtilities (is that ever supposed to show up?  I’m assuming yes).

    Let me know if it is worth sending you a sample project offline and if so, if/when we resolve issue, I could post a textual representation of the solution on your blog for others to see?

    Here’s the relevant code:

    (from ThisAddin.cs)

    protected override object RequestComAddInAutomationService()


     if ( addinUtilities == null )


       addinUtilities = new AddInUtilities();


     return addinUtilities;


    (This is entire my ‘Automation.dll’ code)

    namespace BTR.Extensibility.Excel.RBL.Automation


     [ComVisible( true )]

     [Guid( "5231D3C0-3465-493C-BFD8-9BEA4AAB25E1" )]

     [InterfaceType( ComInterfaceType.InterfaceIsDual )]

     public interface IAddinUtilities


       void TestArchitecture( int count );


     [ComVisible( true )]

     [ClassInterface( ClassInterfaceType.None )]

     public class AddInUtilities : IAddinUtilities


       public void TestArchitecture( int count )


         MessageBox.Show( count.ToString() );




    (Automation client snippet)

    var xlApp = Activator.CreateInstance( Type.GetTypeFromProgID( "Excel.Application" ) ) as Excel._Application;

    object progId = "BTR.Extensibility.Excel.RBL.2003";

    var comAddin = xlApp.COMAddIns.Item( ref progId );

    var test = comAddin.Object as IAddinUtilities; // I’ve tried the actual class AddInUtilities cast as well

    Any information would be greatly appreciated.

  22. Garry Trinder says:

    Terry – your code looks ok. It is an odd choice to use implicit types when you know for sure what the types must be (Excel._Application, COMAddIn and IAddinUtilities), but it should still work.

    In the simplest case (like both your simple code and mine, where we try to retrieve the COMAddIns collection immediately after launching the app) there is an outside chance of a race condition where Excel has not fully initialized its COMAddIns collection, or (more likely) each add-in has not yet set its COMAddIn.Object value. In this event, you’d get a NullReferenceException not a cast exception.

    So, if you’re still getting a cast exception, it must be due to some mismatch in type registration. The IAddInUtilities interface should be in the registry under HKCRInterface. Also, this should map to the typelib, which will have the GUID you used for the assembly that contains IAddInUtilities (either the separate DLL or the add-in DLL, depending on how you’ve implemented it).

  23. Terry Aney says:

    Thanks for the info.  The implicit types is more ‘laziness’ than anything else :$.

    Anyway, My COMAddIn.Object is set to _ComObject (or something like that) and I didn’t see my GUID under HKCRInterface :O

    As I mentioned above, I’m not marking the assembly as ‘Register for COM interop’ but rather manually running regasm after copying dll to proper location.  There isn’t something I need to run in addition to regasm to ‘register interfaces’ is there?

    You also asked about whether I have separate DLL or just an add-in DLL…just to answer (I stated above as well, but could be easily overlooked), I have only a single add-in dll.

    Sorry for the ignorance on COM interop, I’ve minimal experience with it.  I appreciate the back and forth and still hoping you might have some idea and/or other users reading this might have had same problem and fixed (yn).

    Anyway, thanks again.

  24. Garry Trinder says:

    I don’t understand why you wouldn’t use the VS ‘Register for COM Interop’ project setting. This not only registers your assembly for COM interop, it also exports and registers a COM typelib, which as I mentioned is cross-referenced by your interface registration. If you need to use regasm directly for some reason, then you should use the /tlb switch (or tlbexp) to get a typelib, and make sure that both are correctly registered. I’m not sure, but I suspect you’ll also have to manually register your interface.

  25. Terry Aney says:

    Well, the only real reason for avoiding ‘Register for COM Interop’ is that I wanted to know the manual steps I needed to take so that I knew how to set it up on other people’s computer.  I probably have not given the VS setup project enough credit and maybe it’ll figure all this out as well.  In any case, I guess I’ll try register for COM interop and see how far I get.

    Thanks for reply.

  26. padvit says:

    I have Word COM AddIn created using VSTO SE 2005. It shows up and work fine when I open word out side my application.

    Through my application when I activate word through

    1. Office.Interop it doesnt show COMAddIn.

        a. The comAddin object is null when tried to access through object property, in the collections  the addin is there.

        b. In the project properties of comAddIn "Register for com interop" is set to true.

    2. If I invoke word by writing contents through response object even at this point it doesnt show my comAdd in word.

  27. Garry Trinder says:

    padvit – it’s not completely clear what you’re trying to do, but your add-in should be loaded even when you automate Word externally, which seems to be what you’re doing (unless you’re starting the Word process with the /a commandline switch). I don’t know what you mean by a "response object" but if you’re trying to automate Word on a server from an ASP page, you should know this is not a supported scenario – see here for details: http://support.microsoft.com/?id=257757. The only other likely issue is that there might be a delay (depending on how many add-ins you’re loading, and what they’re doing) before your add-in is correctly set in the COMAddIns collection.

  28. padvit says:


      Thanks for the reply.

    To be more clear, I have asp.net page, Where Iam creating word application wordApp object using  Office.Interop. if I invoke word through wordApp.visible =true;

    The word is invoked but my AddIn deployed is not visible to me.

    The same AddIn invoked outside my applicaion through "WINWORD.exe" pops up.

  29. Garry Trinder says:

    padvit – as I said, there is no general reason why your add-in should not be available in the COMAddIns collection. Are you sure it is getting loaded? Have you debugged through to find out where it is failing?

  30. padvit says:

    When I debug in the COMAddIns collection it is very much there, but the object is set to null.

  31. padvit says:

    Hi Andrew,

      This is the code Iam using

    Through wordApp object iam creating the document.

    after creating the doc, Iam using the client side script to invoke the word as mentioned in the following article


    buffer = objLinkedDocFacade.GetFileContent(docGUID);


    Response.AppendHeader("Content-Disposition", "inline; filename=" + DocumentName);

    Response.AppendHeader("Content-Length", buffer.Length.ToString());

    Response.ContentType = "application/msword";

    Response.CacheControl = "public";

    Response.OutputStream.Write(buffer, 0, buffer.Length);


    but even then word is opening up but AddIn is not poppingup.

  32. Garry Trinder says:

    padvit – I don’t undersand what you’re doing. You say you’re invoking "client-side script" but then you list server-side ASP code. You say the script is mentioned in a support article, but the support article you list does not have any script in it. Previously, you said you created the Word Application object through "Office.Interop" which is part of the namespace for the Office PIAs, but it doesn’t look like you’re doing that at all.

    If you want to show us the code where you’re creating the Word Application object, it might help. But in any event, please note that as I said before what you’re doing (automating Word on the server) is not supported and not encouraged.

  33. Mathew says:


    I have an implementation similar to the example that you have given ,My Addin can be launched thru a webpage , I need my Add-in to be created on an STA thread , but my exposed method is launched on an MTA thread . this is a problem for me as I launch a winform form the addin (similar to the "Word New" dialog) which in-turn launches a web widget and this activeX control cannot run on an MTA thread .

    Is there anyway we can mark the launch Method to ONLY launch as STA , I tried attributing the method ("[STAThread]") but to no luck .

  34. Garry Trinder says:

    Matthew – please provide some clarification.

    If I understand you correctly, you have a web page, and the code behind the web page connects to an add-in running in Office?

  35. Andrew, I think the great enhancement for out-of-proc consumers of AddInUtilities could be if they derived from System.Runtime.InteropServices.StandardOleMarshalObject. The reason here is that by default all managed objects are neutrally threaded – hence out-of-proc calls will activate the AddInUtilities on the thread the RPC call came in. However, you can change by deriving from SOMO and this will cause the incoming calls to be marshalled onto the thread (or, to be more precise, COM apartment) the object has been initially created on (which is in most circumstances the main UI thread).

  36. mathjcb says:


    I have Javascript that launches the Add-in , its not code behind .

  37. Garry Trinder says:

    Matthew/mathjcb – did you try Misha’s suggestion? That is, to derive your AddInUtilities class from System.Runtime.InteropServices.StandardOleMarshalObject.

  38. mathjcb says:

    Thanks Misha and Andrew . Deriving from System.Runtime.InteropServices.StandardOleMarshalObject" has solved my problem !

    Thanks again .!

  39. PT says:

    Thanks Andrew for the sample.  It works well.  I jsut have one questions, you said "In my VBA, I can add a reference to the AddinService add-in, so that I get design-time intellisense".  Could you show me how to do that?

    I see the COM object under Tools –> COM Addins, but in VB, Tools –> References, I simply couldn’t find it.  I can click the browse button to find the dll but couldn’t load it as it complains "Can’t add reference to specfied file".

  40. Garry Trinder says:

    PT – you need to add a reference to the typelib (.tlb) not the dll, from Tools | References in the VBE. If the tlb is not listed, check that it is being generated during the build. You should have "Register for COM Interop" checked in the build properties – this generates a tlb and registers it.

  41. PT says:

    Awesome, it worked!

    Many Thanks!

  42. Mariano Liceaga says:

    I’m using your example to try to pass an object to the AddinUtilities class. AddinUtilities it’s inheriting from StandardOleMarshalObject and implementing IAddinUtilities. If I pass an integer value it works fine, but as soon as I try to pass an object, either by value or by reference, I get an Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

    Is it possible to pass complex objects or am I trying something impossible?

  43. I’ve posted a few times on the best way to expose methods from an add-in to automation clients – for

  44. Lilu says:

    Hi Andrew,

    Thanks a lot this wonderful article. I’m using this article as a starting point for my project.

    We have a requirement where we need to expose a class from the Word add-in, using which VB/VBA user can customize the Word Ribbon interface like hidding or disabling the different control. Can you please suggest me how should I do ribbon customization inside my exposed class?

    Here are some of the MSDN articles I’m referring but did not help:



  45. Garry Trinder says:

    Lilu – thanks for your comments. The articles you reference should provide you with the information you need for dynamic ribbon customization.

    You can expose an automation object from your add-in, as described in my blog posts. This object can expose suitable methods for showing/hiding ribbon controls, changing ribbon control images or labels, and so on. The basic mechanism behind this is as described in the quoted articles – that is, in your ribbon XML you specify callbacks for status methods such as getVisible, getEnabled, getImage, getLabel, and so on. Details of these callbacks are here: http://msdn.microsoft.com/en-us/library/aa722523.aspx

    The main ribbon developer portal is here: http://msdn.microsoft.com/en-us/office/aa905530.aspx

    So, your VBA could get hold of your add-in’s automation object, and call methods. These methods internally would set some state (boolean flag for control visibility, text for label, etc), and then invoke the IRibbonUI.Invalidate or InvalidateControl methods to cause the ribbon to be refreshed.

  46. Mathew says:

    Hi Andrew ,

    I thought I’ll let you know , I had to roll back Misha’s suggestions on July 3rd for implementing System.Runtime.InteropServices.StandardOleMarshalObject interface for out of proc process to access add-in .

    After implementation we have observed weird behavior with some API’s like UpdateToC stopped updating and content control enter and exit events had some issues .

    In short after implementing rhe interface we had issue with some native word behavior.

  47. Garry Trinder says:

    Mathew – thanks very much for the update. When you get a chance, please could you provide a simple sample solution that reproduces the problems you’re getting? That would help us to investigate this and figure out the root cause. Many thanks.

  48. Manish says:

    Hi sir.

    I am developing application in VSTO Excel 2007 Workbook type.

    I have added some buttons in that now I want to give short cut key to that button like CTRL+L for one win forms.

    I am totally new to VSTO or windows application so please help me how to get rid of this problem.

    Thanks & Regards



  49. Garry Trinder says:

    Manish – you can use the same technique as with standard Windows Forms. That is, put an ampersand "&" in the Text property, in front of the character you want to use for your shortcut.

    For example, set the Text property of a Button control to "H&ello". Then, the shortcut will be Alt-e.

  50. Manish says:

    That’s correct but I need same Shortcut for several buttons and different cell and with the combination with Ctrl+"Anykey" only.

  51. Garry Trinder says:

    Manish – sorry, I don’t understand your last comment. Please clarify.

  52. manish says:

    I have 10 buttons in different column like "A","B" ,"C", "D" and so on.

    Now what I want to do is based on my active cell I want to click that button using the short cut.

    the short cut will be same for all the buttons but those will be click based on active cell. I hope now you got the problem.

    and that shortcut should be ctrl based not alt base means ctrl + "L" something like that.

  53. Garry Trinder says:

    manish – there’s really no supported way to do this.

  54. Manish says:

    It is Possible in VBA code version of client and he is running a macro on one image click

    but now I don’t want to run any macro code.

    and customer is saying that such thing is possible is old things why not in new product.

    my ans is 😛

    so need any bad solution if there is ?

    ha ha i will call it as hack and limitation of VSTO as well

    because we don’t have any key press event of sheet else my plan was to find key stork and current column of active cell

    based on the column of the cell call the click event of that column button

  55. v-jbrown@microsoft.com says:

    Andrew I have 2 VSTO project, one is an Excel Add-In, one is an Excel Workbook.

    I’d like the Add-In to be able to open the Excel Workbook, allow the user to enter some data, and then allow the Add-In to call an interface implemented by the workbook to send the data from the workbook to a database. So I need to open the workbook in excel, and also have an object reference in the Add-In to manage the workbook.

    Your example is allowing the workbook to call methods on the add-in, I’d like to go the other way, and can’t seem to fit the pieces together.

  56. Garry Trinder says:

    v-jbrown – the problem is that while Office exposes add-ins in a well-defined manner through the COMAddIns collection, it does not expose doc-level customizations in any way whatsoever. So, your design is going to have to initiate the conversation between add-in and doc-customization from the doc-customization. See here for more: http://blogs.msdn.com/andreww/archive/2008/03/20/integrating-doc-level-and-add-in-solutions.aspx

  57. v-jbrown@microsoft.com says:

    Thanks for the info Andrew. Here’s another question. When you open a VSTO workbook from a winforms app, similar to what you’ve done above, the code behind of the VSTO workbook is executed and all is well.

    However when you open the same workbook from an Excel add-in, the code behind is not executed.

    Is there a threading issue here? Perhaps the workbook is not opening on the UI thread?

  58. Garry Trinder says:

    v-jbrown – there should be no problems opening a workbook and its associated customization from an add-in. Are you sure you’re using the correct path for the workbook (typically, the copy in the targets folder for the workbook project)?

  59. Paul says:

    Hi Andrew,

    I built an Excel VSTO Addin using your detailed post and everything has been working fine for all users for several months. In the last day or so some users have been experiencing the following error when trying to call the Addin from the VBA code

    "Object variable or With block variable not set"

    This occurs at the following line in the VBA

       Set addin = Application.COMAddIns("MQ2Addin")

       Set automationObject = addin.Object

    –> Call automationObject.MQ2Movements(numEntries,   sourceSystem, mineSiteCode, startRow, lastDataRow, errorColumn)

    As I say this has been working fine and I can not find a reason for it yet.

    I did have one difference in the Thisaddin code in that I did not include the GUID line as in your example


    [Guid("B523844E-1A41-4118-A0F0-FDFA7BCD77C9")] <—-


    But everything else is as you specified. The Addin’s Loadbehaviour is set to 3 and I can not find any errors when I set VSTO_SUPRESSDISPLAYALERTS = 0 and launch Excel. The Addin also appears in the COMAddins collection but has no Object value.

    Any help gratefully received.



  60. Garry Trinder says:

    Paul – see my later post here: http://blogs.msdn.com/andreww/archive/2008/08/13/comaddins-race-condition.aspx.

    This describes the situation where you can get hold of an add-in before it has been fully loaded. This applies in particular to VSTO add-ins. The workaround is to attempt to get the COMAddIn.Object in a loop until it succeeds.

    The condition is erratic, and may become more obvious when other add-ins are loaded, or some other factor comes into play that affects the startup time of the host application.

  61. Paul says:


    Thanks for the rapid response.

    I tried a delay and still no luck.



  62. Garry Trinder says:

    Paul – a couple of questions for you.

    1. When are you trying to get the COMAddIn.Object? In the ThisAddIn_Startup or at some other time?

    2. Does it fail for all users on all machines all the time, or only under certain conditions? If the latter, can you identify any differences between the success states and the failure states?

    3. On a machine/user where it fails, does it always fail?

    4. When it fails, is the add-in itself fully loaded and otherwise fully functional?

  63. Paul says:


    1. I try to get the COMAddin,Object in the VBA code behind the spreadheet as follows

    Set addin = Application.COMAddIns("MQ2Addin")

    Set automationObject = addin.Object

    Call automationObject.MQ2Movements

    1. It has only failed for one user and I can not determine what changed on his machine or any pattern of the failure. It has also failed on a development machine and I am currently trying to ascertain why. It appears as though it does not even "see" the addin dll and thinks the COMAddin is loaded successfully.
    2. Once it has failed on a machine it always fails on that machine even after uninstall and re-install. I have installed to a fresh machine ie where it has not previously been installed and the Addin works fine.

    3. The Load behaviour is still set to 3 after the Excel spreadheet is opened but I have it deployed to HKLM so it does not appear in the COMAddin dialogue. It also does not appear as a disabled item and when I invoke it from cmd using VSTOSUPPRESSDISPLAYALERTS I get no error messages.



  64. Garry Trinder says:


    1. What type is your automationObject declared as?

    2. Can you run AddInSpy on the good and bad machines to see if it can find any differences? You can get this tool here: http://code.msdn.microsoft.com/AddInSpy

    3. You say the add-in is loaded, LoadBehavior=3, and it doesn’t show up in the disabled items – but is it actually functioning? Perhaps it has got itself into a bad state, and even though it is loaded and not disabled, it is not actually working correctly?

  65. Paul says:

    Aplogies if you get this more than once

    1. Dim automationObject As Object
    2. The Exposed value is false on the machine where the Addin is not working and true on the one where it is. These are identical versions of the Addin and obviously this is the problem but what would cause that to happen ?



  66. Garry Trinder says:

    Paul – and Q3?

    I think you’re going to have to attach a debugger to the host process to try to figure out at what point the add-in is failing. Set breakpoints in ThisAddIn_Startup, RequestComAddInAutomationService, the ctor for the automation object class, etc, and step through.

  67. Paul says:


    Q3 I put a displaymessage in the startip and I see it on the devlopment mnachine but don’t see when its installed on the machine that was not working.

    I afraid I do not know how to attach a debugger to the host process…..do you know of a step by step description of this anywhere



  68. Garry Trinder says:

    Paul – open the add-in project in VS, and set lots of breakpoints. Then hit F5.

    See here for documentation: http://msdn.microsoft.com/en-us/library/sc65sadd.aspx

  69. Paul says:

    So I need VS on the machine where the addin is not working ?  It works in VS on the development machine

  70. Garry Trinder says:

    Paul – sorry, no – you can set up remote debugging. That is, use VS on your dev machine to connect to the process on the bad machine. See here: http://msdn.microsoft.com/en-us/library/y7f5zaaa.aspx

    (this is a sub-topic of the main debugging docs I mentioned before).

  71. Paul says:

    Hi Andrew,

    I am not getting to break points in the override class or the Thisaddin_Starup. I ran the VSTO trouble shooter and noticed a difference in the Office 2003 PIA assemblies for the Microsoft Office Forms PIA and whilst that is not used by my project I figure I would uninstall them and re-install them. I did the uninstall and rebooted but the troubleshooter still told me that they were installed. They are not showing in the Control Panel Add/Remove programs do you know how I can completely remove them ?



  72. Garry Trinder says:

    Paul – that doesn’t seem to make sense. If the add-inn is truly loaded then the ThisAddIn_Startup should get called. If the problem is CLR can’t resolve assembly dependencies, you should be able to detect this with fuslogvw – the fusion log viewer http://msdn.microsoft.com/en-us/library/e74a18c4(VS.80).aspx.

    Also, can you confirm this is an Excel 2003 add-in? Which version of VSTO are you using?

    Re PIAs, these are normally installed with Office, although they can also be installed via the separate PIA Redist, and a dev set of the Office PIAs is instaleld with VS2008. So, uninstalling them depends on how you installed them in the first place.

  73. Paul says:

    I have managed to fix the problem and I am a little red faced to say the least. I had checked for disabled Addins and none were listed but when I chcek the users machine again today (he has been away) low and behold its disabled, re-enabled it and all is working again.

    Thanks you for your help, at least I learned a lot about the various daignosis tools.

    kind regards