Andrei Smolin

Building and deploying a bit-specific Office add-in

Add-in Express is essentially bitness-neutral. The downside is: creating a pure 64bit add-in isn’t directly supported. When you invoke the Register Add-in Express Project command in Visual Studio, Add-in Express shows a message suggesting that you use the Any CPU platform instead. Below I describe how to work around this.

Let me talk a bit about this message first. When you choose that command, Add-in Express creates an instance of the add-in module and invokes the AddinRegister method defined on the add-in module. This works if you choose the Any CPU or x86 platforms for the add-in. If you choose the x64 platform, creating an instance of the add-in module fails because Visual Studio is 32 bit and you cannot load a 64bit DLL in a 32bit process. So that message is in fact an attempt to prevent that fail.

Now on to the example. Let’s create an add-in project, a test class library project and invoke the test assembly from the add-in. Below are the steps.

Create an add-in project invoking a method from an assembly (Any CPU)

  • Create an add-in project, call it LoadAssemblyExample
  • Add a class library project to the solution, call the new project TestAssembly
  • Since the add-in project is strong-named, you need to strong-name the assembly project as well. Choose TestAsembly properties on the Project menu, switch to the Signing tab, check the Sign the assembly check box and specify or create a .SNK file.
  • Add System.Windows.Forms to the References section of the TestAsembly project
  • In the TestAsembly project, rename Class1.cs to TestClass.cs, and paste the following code:
    using System;
    using System.Windows.Forms;
     
    namespace TestAssembly {
        public class TestClass {
            public void TestMethod() {
                MessageBox.Show("OK. \n" + System.Reflection.Assembly.GetExecutingAssembly().FullName);
            }
        }
    }
  • In the References section of the LoadAssemblyExample project, add a reference to the TestAssembly project.
  • On the LoadAssemblyExample project, open the add-in module designer, use the designer’s toolbar to put an ADXRibbonTab component onto the add-in module; set the Caption property of the component to Example
  • Select the ADXRibbonTab component, and use the in-place designer to add a group; set the Caption property of the ADXRibbonGroup component to Load assembly
  • In the in-place designer, select the ADXRibbonGroup component and add a Ribbon button to the group; set the Caption property of the ADXRibbonButton component to TestMethod

    Creating the UI of the add-in

  • Add an event handler to the Click event of the ADXRibbonButton component and paste the following code:
    TestAssembly.TestClass testClass = new TestAssembly.TestClass();
    testClass.TestMethod();
  • Register the add-in and test it.

Loading an assembly dynamically

Let’s change the above so that the add-in can load the TestAssembly whether it is 32bit or 64bit. Note that because Visual Studio is 32bit, you must leave the LoadAssemblyExample project’s platform Any CPU. This means, you need to load the assembly on the fly and invoke TestMethod using Reflection.

  • Delete the TestAssembly reference in the References section of the LoadAssemblyExample project
  • Replace the code in the event handler of the Click event of the ADXRibbonButton component with the following one:
    string location = Assembly.GetExecutingAssembly().CodeBase;
    string fullPath = new Uri(location).LocalPath; // path including the dll
    string directoryPath = Path.GetDirectoryName(fullPath); // directory path
    string assemblyToLoad = "";
    if (IntPtr.Size == 4) //x86
        assemblyToLoad = Path.Combine(directoryPath, "TestAssembly.dll");
    else // x64
        assemblyToLoad = Path.Combine(directoryPath, "TestAssembly64.dll");
     
    Assembly assembly = Assembly.LoadFile(assemblyToLoad);
    Type type = assembly.GetType("TestAssembly.TestClass");
    var obj = Activator.CreateInstance(type);
     
    type.InvokeMember("TestMethod", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, obj, new object[] { });

The next step is to modify the TestAssembly project so that it can produce 32bit and 64bit assemblies.

  • Select the TestAssembly project in the Solution Explorer, choose Configuration Manager on the Build menu and create x86 and X64 platforms for the TestAssembly project
  • Paste the code below to the PostBuildEvent of the TestAssembly project. These command lines copy the TestAssembly.dll and TestAssembly.pdb files to the output folder of the LoadAssemblyExample project; for the x64 platform, the files are renamed to TestAssembly64.dll and TestAssembly64.pdb
if "$(PlatformName)" == "x86" (
    copy /y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)LoadAssemblyExample\bin\Debug\$(TargetName).dll"
    copy /y "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)LoadAssemblyExample\bin\Debug\$(TargetName).pdb"
)

if "$(PlatformName)" == "x64" (
    copy /y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)LoadAssemblyExample\bin\Debug\$(TargetName)64.dll"
    copy /y "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)LoadAssemblyExample\bin\Debug\$(TargetName)64.pdb"
)

Now, to build TestAssembly.dll, you open the Configuration Manager dialog (choose Configuration Manager on the Build menu), set the TestAssembly project’s platform to x86, close the dialog and build the project. To build TestAssembly64.dll, you open the Configuration Manager dialog, set the TestAssemblyproject’s platform to x64, close the dialog and build the project. The resulting .DLL and PDB files are located in the bin\Debug folder of the add-in project.

Deploying a bitness-specific add-in files

In this project I choose to deploy x86 and x64 assemblies in the same installer so that the add-in will support user uninstalling Office and installing Office of a different bitness. The installer must be x86 to be able to run on Windows 32bit and 64bit.

You cannot achieve this using VDProj – the standard setup project available in VS 2005-2010 and VS 2013 (available here): building a setup project containing both x86 and x64 assemblies produces an error described at https://msdn.microsoft.com/en-US/library/ms228639%28v=vs.80%29.aspx.

The best way to handle this is to create a WiX setup project: select the add-in project in the Solution Explorer and choose Create Setup Project on the Project menu to start the setup project wizard. If the WiX option is disabled in the dialog window below, check to make sure WiX is installed on your PC and listed in the About dialog of your Visual Studio.

If you build the TestAssembly and LoadAssemblyExample projects before you create the setup project, the project wizard includes the corresponding files into the setup project and you won’t need to modify it manually.

Creating a WiX setup project for the add-in

The resulting installer installs the add-in’s files to the specified folder and registers the add-in. In the sample project above, the result looks as follows:

The add-in running in the Excel UI

Good luck!

Available downloads:

This sample Excel add-in was developed using Add-in Express for Office and .net:

Load Assembly Dynamically sample add-in project

2 Comments

Post a comment

Have any questions? Ask us right now!