Overview of wrapper classes

For each XLL which is to be called from a client application, a wrapper library is generated.

The command line tool CWGENCLS generates all the code for the wrapper library. For each XLL, two classes are generated: one is for use from Visual Basic for Applications (VBA) - which has a limited implementation of the COM interface - and the other is for use from all other development environments. The add-in functions of the XLL are exposed as methods of each wrapper class.

Wrapper libraries are authored in C#. A simple wrapper class might look like this:

CopyC#
namespace Planatech.Demos
{
    /// <summary>
    /// A lightweight wrapper object which supports calls to a set of Excel add-in functions.
    /// </summary>
    /// <remarks>
    /// This class is designed for use by standard COM clients.      
    /// </remarks>
    [ComVisible(true)]
    [Guid("2d42a1e1-3659-4869-81fc-36e7ad4b0889")]
    [ComDefaultInterface(typeof(IApiTest))]
    [Description("A lightweight wrapper class which supports calls to a set of Excel add-in functions.")]
    public class ApiTest : AddinWrapperBase, IApiTest
    {
        #region Construction
        /// <summary>
        /// Constructs a new instance of ApiTest.
        /// </summary>
        /// <remarks>
        /// The object is not ready for use until the Engine property has been set.
        /// </remarks>
        public ApiTest() { }
        #endregion

        #region Error handling
        private string[] errorPrefixes = new string[] { "#Error:" };
        #endregion

        #region Wrapped Excel add-in functions

        /// <summary>
        /// Returns the sum of two numbers
        /// </summary>
        /// <param name="A">is the first number</param>
        /// <param name="B">is the second number</param>
        /// <exception cref="XllWrapperException">Will be thrown if any errors occur in the call to Excel,
        /// or if the add-in function returns an error value.</exception>
        [Description("Returns the sum of two numbers")]
        [DispId(1002)]
        public double ScalarAdd(double A, double B)
        {
            CheckEngine();
            object res__ = Engine.CallExcelWithErrorCheck("ScalarAdd", true, errorPrefixes, A, B);
            return (double)Unwrap(res__, typeof(double));
        }

        #endregion
    }
}

Notice that all the help text from the add-in functions has been copied into the C# comments, so that developers who use the wrapper class will get the benefit of on-line help and Intellisense.

A number of COM attributes are set for the class, to make it fully available in COM client environments, as well as from .NET clients.

Every wrapper class is derived from AddinWrapperBase, which contains a number of methods used for doing common tasks and one important property: Engine.

Engine

Each of the wrapper methods delegates the actual work of calling the XLL method to an engine, which is represented by the IWrapperEngine interface. There are two available implementations of IWrapperEngine available:

  1. XllPlus.ComWrappers.Runtime..::.ExcelWrapperEngine uses an instance of Excel to execute the XLL add-in function. The Excel instance is fully controlled by the engine: it is invisible to the user, and it is closed by the engine when it is no longer required.
  2. XllHostWrapperEngine uses an instance of XLL Host. This engine should be used when Excel cannot be available on a computer or when Excel is considered too unstable to be part of an application stack.

The code in the wrapper class is ignorant of which engine is being used; the same wrapper classes can be used with any engine class that implements IWrapperEngine.

A wrapper class cannot be used until its Engine property has been set to a valid instance of IWrapperEngine. A typical pattern of use for a wrapper class (which is a very light-weight object) is shown below.

CopyC#
ExcelWrapperEngine theEngine = new ExcelWrapperEngine();

...

using (ApiTest wrapper = new ApiTest())
{
    wrapper.Engine = theEngine;
    try
    {
        double dResult = wrapper.ScalarAdd(1.23, 4.56);
        ...
    }
    catch(XllWrapperException ex)
    {
        ...
    }
}

The wrapper object is automatically disposed at the end of the using block.

Initializing the engine

ExcelWrapperEngine is a heavy-weight object, (since it can own an invisible instance of Excel) and so it should be created and destroyed with care.

It must be initialized before it can be used with a wrapper object. In environments other than VBA, a typical pattern is:

CopyC#
ExcelWrapperEngine theEngine = new ExcelWrapperEngine();
theEngine.Create();
theEngine.LoadXll(theXllFileName);

... Use the engine ...

theEngine.Destroy();

A wrapper object cannot be used until the XLL containing its add-in functions has been loaded. LoadXll is used for this purpose. The developer is responsible for specifying the full path to the XLL file. If the XLL is deployed to the same directory as the wrapper assembly, then for an XLL named ApiTest.xll and a wrapper class named ApiTest you can use code such as this:

CopyC#
string theXllFileName = Path.Combine(
    Path.GetDirectoryName(typeof(ApiTest).Assembly.Location),
    "ApiTest.xll");

Output files

When the add-in project is built, there are three output files of interest:

Assembly
This is a .NET assembly that contains the code for the wrapper. For a wrapper library named ApiTest, the file is named ApiTest.dll.
Type library
This is a COM type library file that exports all the function definitions for COM clients, including VBA. It has the extension "tlb", e.g. ApiTest.tlb.
Documentation
This is an XML file that contains the documentation for the wrapper library. This will be available to .NET client application developers as Intellisense help in Visual Studio. It has the extension "xml", e.g. ApiTest.xml.

See Also