You know, I love working for Add-in Express! I think there are few companies that cover so many interesting things to write about. Take this article for example, Eugene asked me to write an article on how the Add-in Express team merged a number of add-ins into one assembly when they build the AbleBits Excel Add-ins Collection.
When I first heard about this topic, I had no idea how to even tackle this problem. Fortunately, one of the perks of writing this blog for Add-in Express is access to the best MS Office developers in the world, and Aleksey send me a sample project. Phew!
The scenario
Before we have a look at the sample project, let’s first examine the scenario for when you might want to consider using this approach. In the case of the Ultimate Suite for Excel, loading was a crucial factor, by following this approach the team effectively reduced the loading time by nearly 60%, because only one assembly needs to be loaded instead of 20+ separate ones.
Now if you ask me, a 60% speed increase is definitely worth-it! In this example, we’ll have two separate Microsoft Excel add-ins. One will have a custom Ribbon Tab including a Ribbon group with a few buttons and a custom Excel Task pane.

The other add-in will have a custom Ribbon Tab, custom Task Pane as well as some keyboard shortcuts and an Excel App Events component.

Before we can merge our Excel add-ins we need to create another plug-in which we’ll use to combine all the elements of the other add-ins.
Start by adding a new ADX COM Add-in project to the solution. Because the other two add-ins only support Excel, you need to select Excel as the supported application. Once the project has been created create two folders in the project called Addin1 and Addin2
Right-click on the Addin1 folder and select Add > Existing Item… Browse to the Addin1 project folder and select AddinModule.cs and the task pane class, in this example it is called ADXExcelTaskPane1.cs, and click the arrow on the right hand side of the Add button and select Add As Link.

Repeat the same process for the second plugin, only this time links the files in the Addin2 folder. Once done, the Visual Studio Solution Explorer should look similar to the following image:

Merging the add-in user interfaces
Since we’re merging our Excel add-ins we have to combine things like Ribbons tabs into a single Ribbon Tab and command bars into a single command bar. To do this, you need to add an empty ADXRibbonTab and ADXCommandBar control to the MergedAddin project’s AddinModule designer surface.
Once the required components are in place, switch to the AddinModule‘s code view and add a new List<T> object to the class:
private List<ADXAddinModule> _modules = new List<ADXAddinModule>();
We’ll add all the modules we need to merge to this collection and loop through each module’s components and add it to the MergedAddin project’s components.
public AddinModule()
{
Application.EnableVisualStyles();
InitializeComponent();
if (Process.GetCurrentProcess().ProcessName.ToLower() == "devenv")
return;
_modules.Add(new Addin1.AddinModule());
_modules.Add(new Addin2.AddinModule());
for (int i = 0; i < _modules.Count; i++)
{
System.ComponentModel.IContainer moduleComponents = _modules[i].GetContainer();
for (int j = moduleComponents.Components.Count - 1; j >= 0; j--)
{
// Keyboard Shortcuts
if (moduleComponents.Components[j] is AddinExpress.MSO.ADXKeyboardShortcut)
{
this.components.Add(moduleComponents.Components[j]);
continue;
}
// Excel Task Panes
if (moduleComponents.Components[j] is AddinExpress.XL.ADXExcelTaskPanesCollectionItem)
{
this.adxExcelTaskPanesManager1.Items.Add(moduleComponents.Components[j] as
AddinExpress.XL.ADXExcelTaskPanesCollectionItem);
this.components.Add(moduleComponents.Components[j]);
continue;
}
// Ribbon controls
if (moduleComponents.Components[j] is IADXRibbonComponent)
{
if (moduleComponents.Components[j] is ADXRibbonTab)
continue;
if (moduleComponents.Components[j] is ADXRibbonGroup)
this.adxRibbonTab1.Controls.Add(moduleComponents.Components[j] as ADXRibbonGroup);
this.components.Add(moduleComponents.Components[j]);
continue;
}
// Excel events
if (moduleComponents.Components[j] is ADXExcelAppEvents)
{
BindEvents(moduleComponents.Components[j], this.adxExcelEvents);
continue;
}
// Task Panes
if (moduleComponents.Components[j] is AddinExpress.XL.ADXExcelTaskPanesManager)
{
BindEvents(moduleComponents.Components[j], this.adxExcelTaskPanesManager1);
continue;
}
}
// Module events
BindEvents(_modules[i], this);
}
}
The BindEvents method does exactly as its name suggests and will bind the events of the source component to the destinations component in the MergedAddin project.
private void BindEvents(object source, object destination)
{
System.Reflection.EventInfo[] events = source.GetType().GetEvents();
if (events == null) return;
for (int i = 0; i < events.Length; i++)
{
System.Reflection.EventInfo eInfo = events[i];
System.Reflection.FieldInfo fieldSource =
source.GetType().GetField(eInfo.Name,
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
if (fieldSource == null) // addin module (!!!)
{
fieldSource = source.GetType().BaseType.GetField(eInfo.Name,
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
}
if (fieldSource != null)
{
Delegate delegateSource = fieldSource.GetValue(source) as Delegate;
if (delegateSource != null)
{
System.Reflection.FieldInfo fieldDestination =
destination.GetType().GetField(eInfo.Name,
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
if (fieldDestination == null)
{
fieldDestination = destination.GetType().BaseType.GetField(eInfo.Name,
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
}
if (fieldDestination != null)
{
System.Reflection.EventInfo eInfoDestination =
destination.GetType().GetEvent(eInfo.Name);
if (eInfoDestination != null)
{
eInfoDestination.AddEventHandler(destination, delegateSource);
}
}
}
}
}
}
If you build, register and run the MergedAddin project, you might see some strange behaviour as some of the components are added twice. To resolve this, you need to open the AddinModules of both Addin1 and Addin2 projects and add the following above the class name:
[ComVisible(false)]
Now, when you run your project you should see the UI elements of the two Excel add-ins combined into one.
Merged add-ins in Excel 2010:

There you have it! With a little bit of the Add-in Express teams’ know-how and some innovation you do not need to rewrite your add-ins to combine them into a single binary.
Thank you for reading. Until next time, keep coding!
Available downloads:
This sample Excel Add-in was developed using Add-in Express for Office and .net:
