Office add-ins typically feature a specific type that is truly the star of the show, with its responsibilities including things such as facilitating the connection to the target product, extending the Office ribbon, and more. We typically refer to this type as the Connect class, and given the amount of responsibilities it can potentially acquire, it can easily turn into a very large, bulky, and perhaps slightly Lovecraftian entity.

When such a thing becomes reality for your add-in, you may start to wonder if it is at all possible to break up these responsibilities into separate types; indeed, separation is possible, and this article will go into how. Understanding the solution however, of course requires understanding the actual problem at hand.

Before we start, however, I would note that if you use VSTO to develop your add-in, this article most likely does not apply to you. I can’t be sure, as I stay very far away from the thing. If interfaces such as IDTExtensibility2 and IRibbonExtensibility appear alien to you, then I can assure you that reading any more after this point would only serve to consume your limited time.

The Problem

The Parties Involved

An add-in’s implementation of the IDTExtensibility2 interface serves as its connection to the Office product it targets. This is why we typically use Connect as the name for the implementing class. Without it, our add-in has no way of being loaded/unloaded by the host Office application.

If we want our add-in to improve upon Office’s ribbon, then we must implement the IRibbonExtensibility automation interface. This is used by Office in order to load the custom ribbon XML markup from the add-in and execute callbacks via the use of IDispatch::GetIDsOfNames and IDispatch::Invoke. Because it is Office that makes use of these methods, then it is manifest that Office be able to locate its implementation, and the method in which it does so may be unclear to those coming from a strictly .NET/managed background.

In order to allow for our add-in to extend the ribbon, the usual course of action for those of us developing in a managed environment is to simply add a IRibbonExtensibility implementation to our Connect class. Office will pick up on this just fine (although many of us at the time may not be very sure as to how it does so) resulting in our envisioned custom ribbon making it onto the live application instance.

Let’s not forget that Office has a few other (albeit less common) extensibility points we may be interested in, such as the ability to provide custom take panes through the use of the ICustomTaskPaneConsumer interface. The prime candidate for implementation of such interfaces will yet again most likely need to be our trusty Connect class.

A Growing Manifestation

We like to keep our code clean and compartmentalized, with each module or class responsible for as few things as possible. This desire will quickly become an impossible dream to many when we start dabbling in areas such as extension of the Office ribbon.

If we’re dealing with anything more than the simplest of add-ins, we’re going to start to see a very large number of callbacks being added to our Connect class. In the end, our Connect class will be very large, with potentially lots of responsibilities.

So it may come to be that you want to separate your add-in entry point code (IDTExtensibility2) from your ribbon extension code (IRibbonExtensibility) into two separate entities. If you know little of the mechanisms in use by Office in order to tap into your IRibbonExtensibility implementation, this may seem nigh impossible at first.

If we do some blind digging around how Outlook seems to be finding and interacting with our add-in, we can see that the scant registration data pertaining to our add-in makes no mention of its ribbon extending capabilities; in most cases, the only thing related to our add-in that is registered with the system is our Connect class.

Office is a strictly unmanaged beast. Consequently, it certainly doesn’t make use of .NET Reflection APIs in order to figure out if your add-in’s entry point implements IRibbonExtensibility. So, how does Office know if your add-in extends its ribbon?

COM-mon Knowledge, Baby

Hopefully you wouldn’t be surprised if I told you that the add-in you’ve been developing is a COM add-in. Indeed, your add-in is an in-process COM server that implements the IDTExtensibility2 interface as described in Msaddndr.dll (which just rolls off the tongue, I know).

So, hopefully you don’t feel it to be a very large leap of faith to go a bit further here and extrapolate that Office is making use of the basic set of tools native to COM in order to do all of its digging (I’d think the mention of the IDispatch interface earlier might have been a bit of a giveaway).

Your Connect class (well, actually the IDTExtensibility2 implementation found in your unmanaged shim, you are using a shim right?) is actually registered as an in-process server for your add-in via an InProcServer32 registry key. Office will get an interface pointer to the IUnknown of the object that implements IDTExtensibility2, and then use that pointer to QueryInterface for any subsequent interfaces (such as IRibbonExtensibility, etc.).

That’s all we need to know.

The Solution

If we want the responsibilities of extending Office’s ribbon delegated to another class, we need to return a pointer to that class when queried. Before we get into how we do that, let’s put what we’re working with on the table first.

We’ll be working with two managed classes: one which provides the point of connection to Office (Connect) and one which extends the Office ribbon (Ribbon).

Connect.cs
[ComVisible(true)]
[ProgId(CONNECT_PROG_ID)]
[Guid("5842D85C-3E55-423F-A114-9D3368EBC64F")]
[ClassInterface(ClassInterfaceType.None)]
public sealed class Connect: IDTExtensibility2
{
.
.
.
}
Ribbon.cs
[ComVisible(true)]
public sealed class Ribbon : IRibbonExtensibility
{
.
.
.
}

With these two classes, we can separate our connection logic from our ribbon logic. The tough part is getting Office to make use of our Ribbon class; as was stated previously, by default, the COM shim wizards require the Connect class to implement c>IRibbonExtensibility in addition to IDTExtensibility2 in order for us to be able to influence the Office ribbon.

So, naturally, the changes we’ll need to make will be to our unmanaged COM shim. The various file/class names I’ll be referencing here should be the ones generated by the Office COM shim wizard; if I’m making references to files that appear wholly foreign to you, let me know in the comments, as there is a chance that I’ve renamed them.

The first file we’ll be modifying is the header file for our outer aggregator (IOuterAggregator). This is the interface implemented by our ConnectProxy class and provided to a managed component so that the managed component can supply the shim with references to the various managed instances it either needs to use in response to queries or forward those queries to.

By default, the outer aggregator is used to supply a reference to only a single managed component, that being our Connect class. We need to be able to supply an additional reference to our Ribbon class, so we modify its only method’s signature to accept an additional IUnknown.

IOuterAggregator.h
__interface __declspec(uuid("7b70c487-b741-4973-b915-c812a91bdf63"))
IOuterAggregator : public IUnknown
{
	HRESULT __stdcall SetInnerPointers(IUnknown *pUnkRibbon, IUnknown *pUnkBlind);
};

Don’t forget that there is also a managed COM import declaration of this type in either your add-in or (if you didn’t combine the two) your external “managed aggregator”. This will also need to be updated.

IOuterAggregator.cs
[ComImport]
[Guid("7B70C487-B741-4973-B915-C812A91BDF63")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IOuterAggregator
{
    void SetInnerPointers(IntPtr pUnkRibbon, IntPtr pUnkBlind);
}

The next file we’ll be modifying is the header file for the class that acts as the proxy between Office and our managed components (ConnectProxy). The first modification we need to make is the addition of a separate pointer that will hold (indirectly of course) a reference to our managed Ribbon instance. We can simply add a new IUnknown declaration to the private section of the header file. In the end, we should have something like the following:

ConnectProxy.h
.
.
.
private:
    IDTExtensibility2 *_pConnect;
    CLRLoader *_pCLRLoader;
    IUnknown *_pUnkBlind;
    IUnknown *_pUnkRibbon;
};

OBJECT_ENTRY_AUTO(__uuidof(ConnectProxy), ConnectProxy)

Above, we can see the new IUnknown declaration for our ribbon. And before you yell at me about using Hungarian notation, know that the code generated by the wizard uses COM notation, and I continue to do so as well so as to remain consistent.

Next we need to make some changes to the COM map declared in this header file. Normally, there is no mention of IRibbonExtensibility2 in our COM map, even if the COM shim wizard has been configured to support IRibbonExtensibility2, and that’s because of the following line:

COM_INTERFACE_ENTRY_AGGREGATE_BLIND(_pUnkBlind)

This macro essentially causes queries for IIDs that do not match previous COM map entries to be forwarded to the provided pointer. So any queries for IRibbonExtensibility2 would hit up _pUnkBlind, which essentially points to the same thing pointed to by _pConnect.

Since we want our _pUnkRibbon instance to be forwarded ribbon related queries, we’ll need to it to the COM map. However, just adding an entry for IRibbonExtensibility2 is not enough; an entry for the IDispatch interface is also required. This is because the IDispatch interface provides the mechanic used for when we need to add callbacks to the various elements of a ribbon. Office sees that it needs to call a method named GetButtonLabel in order to get a button’s label, so it will query for IDispatch and use that to find a method named GetButtonLabel. Remember, we’re in unmanaged land, there’s no Reflection API to help us here.

Here’s what our COM map will look like when we’re done:

ConnectProxy.h
.
.
.
public:
.
.
.
BEGIN_COM_MAP(ConnectProxy)
    COM_INTERFACE_ENTRY(IDTExtensibility2)
    COM_INTERFACE_ENTRY(IOuterAggregator)
	COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(IRibbonExtensibility), _pUnkRibbon)
	COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(IDispatch), _pUnkRibbon)
    COM_INTERFACE_ENTRY_AGGREGATE_BLIND(_pUnkBlind)
END_COM_MAP()

The final change we need to make to this header file is related to the changes we made to the IOuterAggregator interface. Because ConnectProxy implements said interface, we need to propagate the changes we made to it to the proxy’s header file.

ConnectProxy.h
.
.
.
public:
.
.
.
STDMETHOD(SetInnerPointers)(IUnknown* pUnkRibbon, IUnknown* pUnkBlind);
.
.
.

That’s it as far as the header file is concerned. Next, because we made changes to the header file, we’re going to make some changes to the actual class file. We added a new member to the class, so be sure to initialize the _pUnkRibbon pointer to null in the constructor’s initializer list, as well as add the necessary clean up logic for it in the FinalRelease method.

Other than those routine concerns, the main changes will be to the SetInnerPointers method. It needs to reflect the updated declaration we committed to the IOuterAggregator.h file, as well as store the additional ribbon pointer being provided to us.

ConnectProxy.cpp
HRESULT __stdcall ConnectProxy::SetInnerPointers(IUnknown* pUnkRibbon, IUnknown* pUnkBlind)
{
	if (pUnkRibbon == NULL || pUnkBlind == NULL)
	{
        return E_POINTER;
    }

    if (_pUnkRibbon != NULL || _pUnkBlind != NULL)
    {
        return E_UNEXPECTED;
    }

	_pUnkRibbon = pUnkRibbon;
	_pUnkRibbon->AddRef();

    _pUnkBlind = pUnkBlind;
    _pUnkBlind->AddRef();

    return S_OK;
}

The last class we need to change is our managed implementation of the IInnerAggregator class. This is where the pointer to our now separate ribbon type will get provided to the shim, so we need to add the work required in order to do this to it.

InnerAggregator.cs
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Your.ProgId")]
internal sealed class InnerAggregator : IInnerAggregator
{
    /// <inheritdoc/>
    public void CreateAggregatedInstance(IOuterAggregator outerObject)
    {
        IntPtr pOuter = IntPtr.Zero;
        IntPtr pBlindInner = IntPtr.Zero;
        IntPtr pRibbonInner = IntPtr.Zero;

        try
        {
            pOuter = Marshal.GetIUnknownForObject(outerObject);

            Connect connect = new Connect();
            Ribbon ribbon = new Ribbon();

            pBlindInner = Marshal.CreateAggregatedObject(pOuter, connect);
            pRibbonInner = Marshal.CreateAggregatedObject(pOuter, ribbon);

            outerObject.SetInnerPointers(pRibbonInner, pBlindInner);
        }
        finally
        {
            if (pOuter != IntPtr.Zero)
                Marshal.Release(pOuter);
            if (pBlindInner != IntPtr.Zero)
                Marshal.Release(pBlindInner);
            if (pRibbonInner != IntPtr.Zero)
                Marshal.Release(pRibbonInner);

            Marshal.ReleaseComObject(outerObject);
        }
    }
}

And that does it. Any ribbon related queries made by Office should be correctly redirected to your managed Ribbon class, and connection related activities will continue to be covered by the managed Connect class. No additional registry entries need to be made relating to all of this, everything will be handled by the additional code we added. Enjoy slightly more neat and compartmentalized Office add-in code.

 

In a previous article I wrote, I introduced a way to compare expressions on the basis of their makeup as opposed to simple reference equality checks. This functionality was provided in the form of an IEqualityComparer<T> implementation, which itself was supported by several components.

Like all equality comparers, our expression equality comparer must be able to perform two functions:

  1. Determine the equality between two given expression instances
  2. Generate a hash code for a given expression instance

The previous article covered the first of these jobs; in this article, we’ll be covering the hash code generation aspect of the comparer.

Revisiting Our Equality Comparer

Just to make sure we’re all on board in regards to how and where our hash code generator will be used, let’s take a second to revisit the equality comparer presented in the previous article.

ExpressionEqualityComparer.cs
/// <summary>
/// Provides methods to compare <see cref="Expression"/> objects for equality.
/// </summary>
public sealed class ExpressionEqualityComparer : IEqualityComparer<Expression>
{
    private static readonly ExpressionEqualityComparer _Instance = new ExpressionEqualityComparer();

    /// <summary>
    /// Gets the default <see cref="ExpressionEqualityComparer"/> instance.
    /// </summary>
    public static ExpressionEqualityComparer Instance
    {
        get { return _Instance; }
    }

    /// <inheritdoc/>
    public bool Equals(Expression x, Expression y)
    {
        return new ExpressionComparison(x, y).ExpressionsAreEqual;
    }

    /// <inheritdoc/>
    public int GetHashCode(Expression obj)
    {
        return new ExpressionHashCodeCalculator(obj).Output;
    }
}

As we can see above, the brunt of the equality comparison work is performed by the ExpressionComparison class, which is a type that we covered in the first article in this series.

If you look at the code for the ExpressionComparison type, you’ll see that it is a derivative of the .NET provided ExpressionVisitor class. The reason why ExpressionComparison was subclassed from ExpressionVisitor is because hooking into that infrastructure is logically congruent with the structure of the expressions it would be comparing.

In order to take into account all the various types of expressions and their properties, we needed to override the majority of the virtual (Visit[x]) methods exposed by ExpressionVisitor. We did not have to override all of them, only the ones targeting expression types whose makeup was unique among all other types.

Just like we did with ExpressionComparison, our ExpressionHashCodeCalculator will also subclass ExpressionVisitor, and it will behave in much the same way, except it will be calculate a running total of the hash codes of all the various properties significant to the given type of expression.

Expression Hash Code Calculator

Now, let’s get into the meat of the matter. As usual, I need to state a disclaimer regarding the usage of the code before we go over it. Although I’ve personally tested all part of the code, I would encourage you to do so yourself before just plopping into what you’re doing.

This code has received a fair amount of scrutiny and is used in some important parts of a larger project I’ve been authoring. In fact, the hash code generation aspect of my comparer rests at the heart of the reasons why I started out on this endeavor (it was my wish to be able to use expressions as keys in a dictionary).

We’ll first take a look at the code for the ExpressionHashCodeCalculator type, and then discuss its merits afterwards.

ExpressionHashCodeCalculator.cs

Update: Thanks to Denis in the comments for pointing out that there was a lack of support for constant collections; code has now been updated to support constant collections.

/// <summary>
/// Provides a visitor that calculates a hash code for an entire expression tree.
/// This class cannot be inherited.
/// </summary>
public sealed class ExpressionHashCodeCalculator : ExpressionVisitor
{
    /// <summary>
    /// Initializes a new instance of the <see cref="ExpressionHashCodeCalculator"/> class.
    /// </summary>
    /// <param name="expression">The expression tree to walk when calculating the has code.</param>
    public ExpressionHashCodeCalculator(Expression expression)
    {
        Visit(expression);
    }

    /// <summary>
    /// Gets the calculated hash code for the expression tree.
    /// </summary>
    public int Output
    { get; private set; }

    /// <summary>
    /// Calculates the hash code for the common <see cref="Expression"/> properties offered by the provided
    /// node before dispatching it to more specialized visit methods for further calculations.
    /// </summary>
    /// <inheritdoc/>
    public override Expression Visit(Expression node)
    {
        if (null == node)
            return null;

        Output += node.GetHashCode(node.NodeType, node.Type);

        return base.Visit(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitBinary(BinaryExpression node)
    {
        Output += node.GetHashCode(node.Method, node.IsLifted, node.IsLiftedToNull);

        return base.VisitBinary(node);
    }

    /// <inheritdoc/>
    protected override CatchBlock VisitCatchBlock(CatchBlock node)
    {
        Output += node.GetHashCode(node.Test);

        return base.VisitCatchBlock(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitConstant(ConstantExpression node)
    {
        IEnumerable nodeSequence = node.Value as IEnumerable;

        if (null == nodeSequence)
            Output += node.GetHashCode(node.Value);
        else
        {
            foreach (object item in nodeSequence)
            {
                Output += node.GetHashCode(item);
            }
        }

        return base.VisitConstant(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitDebugInfo(DebugInfoExpression node)
    {
        Output += node.GetHashCode(node.Document,
                                        node.EndColumn,
                                        node.EndLine,
                                        node.IsClear,
                                        node.StartColumn,
                                        node.StartLine);

        return base.VisitDebugInfo(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitDynamic(DynamicExpression node)
    {
        Output += node.GetHashCode(node.Binder, node.DelegateType);

        return base.VisitDynamic(node);
    }

    /// <inheritdoc/>
    protected override ElementInit VisitElementInit(ElementInit node)
    {
        Output += node.GetHashCode(node.AddMethod);

        return base.VisitElementInit(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitGoto(GotoExpression node)
    {
        Output += node.GetHashCode(node.Kind);

        return base.VisitGoto(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitIndex(IndexExpression node)
    {
        Output += node.GetHashCode(node.Indexer);

        return base.VisitIndex(node);
    }

    /// <inheritdoc/>
    protected override LabelTarget VisitLabelTarget(LabelTarget node)
    {
        Output += node.GetHashCode(node.Name, node.Type);

        return base.VisitLabelTarget(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitLambda<T>(Expression<T> node)
    {
        Output += node.GetHashCode(node.Name, node.ReturnType, node.TailCall);

        return base.VisitLambda(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitMember(MemberExpression node)
    {
        Output += node.GetHashCode(node.Member);

        return base.VisitMember(node);
    }

    /// <inheritdoc/>
    protected override MemberBinding VisitMemberBinding(MemberBinding node)
    {
        Output += node.GetHashCode(node.BindingType, node.Member);

        return base.VisitMemberBinding(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        Output += node.GetHashCode(node.Method);

        return base.VisitMethodCall(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitNew(NewExpression node)
    {
        Output += node.GetHashCode(node.Constructor);

        return base.VisitNew(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitParameter(ParameterExpression node)
    {
        Output += node.GetHashCode(node.IsByRef);

        return base.VisitParameter(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitSwitch(SwitchExpression node)
    {
        Output += node.GetHashCode(node.Comparison);

        return base.VisitSwitch(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitTypeBinary(TypeBinaryExpression node)
    {
        Output += node.GetHashCode(node.TypeOperand);

        return base.VisitTypeBinary(node);
    }

    /// <inheritdoc/>
    protected override Expression VisitUnary(UnaryExpression node)
    {
        Output += node.GetHashCode(node.IsLifted, node.IsLiftedToNull, node.Method);

        return base.VisitUnary(node);
    }
}

As you can see from the above code, the general method for calculating the hash code of a given expression is by visiting all its manifestations and parts and then generating hash codes from the properties significant to those parts.

The GetHashCode methods being invoked in the code are not native to the types they are being invoked on. Rather, they are extension methods, and are something I talked about in another article I wrote.

Each part of the calculate tacks on the total value of the various parts to an Output property, which holds the running total for our hash code. Calculation will end upon our Visit override being executed with a null node being passed.

There are many virtual Visit[x] methods offered by the ExpressionVisitor type. As I stated in the first article of this series, there were in general a large number of new types of expressions added to the .NET framework with 4.0.

When creating our ExpressionComparison class, we overrode many of these methods, but only the ones that held some bearing on the actual shape of the expression as far as an equality check was concerned. The same applies to our hash code calculator; it visits many of the same parts as was visited by the equality comparer, with some differences, namely, some overrides found in ExpressionComparison are not found in ExpressionHashCodeCalculator, and vice versa.

The reasons for not overriding a particular virtual method typically boil down to a lack of properties offered from which to grab hash codes that wouldn’t be offered in another, more centrally invoked override.

For example, one virtual method not overridden is the VisitBlock, method. This method accepts a single BlockExpression typed parameter. If we look at the BlockExpression type, we’ll notice that it offers no additional properties unique to what’s offered by more base Expression types. Well…at least except for the Result property. But even the presence of this property is not cause enough for us to override the method, the reason being that the Result property itself (which is an Expression) is visited by the base VisitBlock implementation, and therefore would be end up being visited by another block of our code anyways.

There are a few more methods not included, but I’ll leave them as an exercise for the reader.

If anyone finds any types of expressions that the above code does not account for, I’d appreciate your input. When constructing this code, however, I tried to be fairly exhaustive in my efforts.

 

This article is meant to serve as a reference for a particular set of functions that may be present in code snippets found in subsequent articles. Every so often one may find themselves tasked with writing hash code generation algorithms for a particular type of object. This sort of requirement typically arises whenever we’re authoring either [Read on for more...]

 

As I have stated elsewhere on this site, it is my intent to limit the scope of the articles I write to areas that fall within my field of expertise. Once again, however, I desire to break away from my usual routine to cover another legislative issue making the rounds in the current events sphere; [Read on for more...]

 

I’ve been swimming in a sea of COM Interop lately. Some time ago, I wrote an article that had some important tidbits regarding the nature of Runtime Callable Wrappers, or RCWs. I’d thought I’d bring to the surface one of the more important questions I answered in that article, specifically: What actions, when executed, incur [Read on for more...]

 

When working with .NET, it is lovely when everything we’re interacting with is rooted in .NET code; however, sometimes we need functionalities that can only be found in one or more COM types. Something that should cross our minds when dealing with COM types is what the implications may be for deployment efforts. Depending on [Read on for more...]

 

DataTemplates are essential tools provided by WPF that allow us to describe the visual structure of  any type of object. When declaring a DataTemplate, one typically is doing so with the intention of targeting a specific type (or valid subtype) of object. This is done by setting the DataType property of the DataTemplate to the Type of object we’re [Read on for more...]

 

Microsoft has recently released a preview version of their new Office 2013 product which adds support for their new touch screen platforms (while maintaining support for PCs). Looks like anyone can grab a copy and try it out for themselves, if interested you can head on over to the official site. If you have a [Read on for more...]

 

WPF affords developers the opportunity to create layouts that coincide greatly with how the look and behavior of a particular user interface was envisioned to be. The tricky part is, as always, knowing how to use the tools we’re given. One common layout-related issue people run into is the layout of items displayed within an [Read on for more...]

 

Resource mailboxes play host to a number of room resource specific settings and policies, such as the window (in days) in which you can “book” the resource, as well as a many-layered system of policies and permissions which affect who may use them as well as their experience in doing so. Your application may have [Read on for more...]

© 2012-2013 Matt Weber. All Rights Reserved. Terms of Use.