How to build a Plug-in Emulator

When a hosted add-in calls the Excel SDK API, XLL Host attempts to emulate Excel in responding to the API call. However, XLL Host does not contain a complete set of API calls, and it may be necessary for the developer to create and register a plug-in emulator to respond to particular calls that are used by a hosted XLL.

XLL Host contains a set of Excel emulators, each of which can handle a fixed set of API calls. There are built-in emulators for handling essential calls such as xlfRegister, which is used by an XLL to register each add-in function. There are also a number of emulators to handle standard methods used by XLLs, such as date conversion and date arithmetic.

When an API call is being handled, XLL Host passes it to each emulator in turn, starting at the head of the list and continuing to the tail until one of the emulators returns true, to indicate that it has handled the call.

Steps

  1. Create a class derived from ExcelEmulatorBase, and override the virtual method HandleExcel4.
  2. Create an instance of the class and register it with a XllHostWrapperEngine instance by calling InstallEmulator, passing a list of the API function IDs that your emulator class can handle. In most cases you will register the emulator at the tail of the list, so that it is only invoked if none of the built-in emulators can handle a particular API call.

Example

The code below shows an emulator class that handles just one API call, xlfRoman, a function that converts a number to its Roman equivalent.

Note the implementation of HandleExcel4.

  1. If the API call is handled, then the method returns true. Otherwise it calls the base class.
  2. The result of the API call is put into the parameter resultValue.
  3. If an error occurs, then the resultCode parameter is set to 32.
using System;
using XllHost.ComWrappers.Runtime;
using System.Text;
namespace TextEmulatorLib
{
    public class TextEmulator : XllHost.ComWrappers.Runtime.ExcelEmulatorBase
    {
        static int xlfRoman = 354;
        public override bool HandleExcel4(int xlfn, ref Array arguments,
            ref int resultCode, ref object resultValue)
        {
            if (xlfn == xlfRoman)
            {
                try
                {
                    resultValue = Roman((int)Convert.ChangeType(
                        arguments.GetValue(0), typeof(int)));
                }
                catch (Exception)
                {
                    resultCode = 32;
                }
                return true;
            }
            return base.HandleExcel4(xlfn, ref arguments,
                ref resultCode, ref resultValue);
        }
        public static int[] GetFunctionIDs()
        {
            return new int[] { xlfRoman };
        }
        private static string Roman(int n)
        {
            StringBuilder sb = new StringBuilder();
            // Omitted for brevity
            return sb.ToString();
        }
    }
    public class Program
    {
        public void Main(string[] args)
        {
            using (XllHostWrapperEngine engine = new XllHostWrapperEngine())
            {
                engine.Create();
                engine.InstallEmulator(new TextEmulator(),
                    TextEmulator.GetFunctionIDs(), false);
                engine.LoadXll(GetXllPath());
                TestRunner run = new TestRunner(args);
                run.Run(engine);
            }
        }
    }
}