Writing a shim to solve problems with managed Office COM Add-ins
If you’ve been following my and Omar’s blogs lately, you’ll know that we’ve been learning a lot about writing managed Outlook COM Add-ins and running into lots of complications in the process. Here I describe how a shim can help solve some of these problems. The issues here apply to all Office add-ins, not just Outlook (although the trust model for Outlook is a bit different).
Running in your own AppDomain
It’s amazing how you can write .NET code to define a COM interface, and the marshalling between the programming models is taken of for you magically. This is done through the Runtime Callable Wrapper (RCW). The complications come from the fact that the RCW is shared between all add-ins. There are also complications based on which version of the primary interop assembly (PIA) you install and which other add-ins install (and where). And, finally, if memory isn’t cleaned up properly, Outlook might fail to quit, but you can’t call ReleaseCOMObject from an add-in because that RCW may be in use by other add-ins. For more details, see Omar’s tales of woe here, and warnings around ReleaseCOMObject here, here, and here.
A shim solves this problem having an unmanaged COM add-in that simply loads your managed add-in into a new AppDomain and then proxies everything to your add-in. It doesn’t even require changes to your managed code.
Signing your add-in
The trust model for Outlook add-ins is a bit complicated. If your add-in is not signed, depending on your Outlook settings, the add-in may silently load, prompt on startup, or silently not load. If you digitally sign your add-in with a self-signed certificate, the add-in will silently load with most configurations. See the table here for the nitty gritty details. The problem is that when you write a managed plugin, mscoree.dll is the dll that’s registered to be loaded, and it takes care of loading your managed code, and mscoree.dll is not signed. That means, even if you sign your managed code, Outlook will see your add-in as unsigned.
The shim comes to the rescue again. You can sign your managed code, and then sign your shim. The shim loads your managed code as a strongly named assembly, which verifies that the shim is loading the right code. This step is very important. If you just signed the shim and not the managed code, then someone could replace your managed code with something malicious, and it would still appear signed to Outlook.
Implementing a shim
I was originally hoping to provide step by step instructions to write a shim here. However, there are just way too many steps, and they are described pretty well on MSDN. They even include an Excel spreadsheet to mark off the steps as you go! The introductory article is here, and then the step by step instructions are here. There are a couple of typos, but it’s otherwise explained pretty well. There are a couple of points worth noting if you adding this to an existing managed plugin that you created from the VS template:
- You’ll want to remove the primary output of the managed add-in from the setup project and follow the steps on the page. You’ll add the managed assembly to the setup project, and the primary output of the shim project.
- This is buried in the notes at the end, but you’ll have to turn off the “Register for COM Interop” setting for the managed add-in project. To do so, right-click the project, choose properties, and then go to Configuration Properties->Build and set Register for COM Interop to false.
Also, you can skip the signing part of the shim if you just want to solve the AppDomain related problems. To do so, just set szAddInAssemblyName to the assembly name without the PublicKeyToken part. As mentioned above, sign neither of the components or both of them. Don’t mix.
I’d be happy to help anyone that runs into trouble creating a shim. Just post a comment!
Comments
- Anonymous
May 07, 2004
Woha! Seems to good to be true :) Thanks!
>S - Anonymous
June 01, 2004
I've followed the MSDN step-by-step article to the point where it states to sign the unmanaged shim. I don't know how to do that?
Also, the example uses the "HelloCOMAddInVB.snk" key in the Assembly attribute. Does that mean the managed addin is already properly being "strong named"? Is there something else I must do with it? - Anonymous
June 08, 2004
You need to follow these instructions to sign your shim. I have not actually gone through that process, so I can't comment on specifics:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsmarttag/html/odc_dcss.asp
By strongly named assembly, I meant that the szAddInAssemblyName variable needs to have the public key in there. You should use your own key pair, not the .snk file that was provided in the sample. - Anonymous
June 18, 2004
Thanks for posting the tip about not adding the public token string in the shim. I was pulling my hair out all day trying to figure out why things weren't working.
For some reason whenever you recompile a dll you get a new public key token which causes A LOT of extra work in the build process. I would expect that since everyone goes through the trouble of using a snk key that this public key token wouldn't change. Also, if you don't check the 'Register for COM Interop' option in the vb project the connect method isn't called for debugging.
We're writing an add-in for visio and to authenticode sign everything and make it work we have to do these steps:
1. Compile the managed add-in on it's own
2. get the public key token with sn -t
3. Put the public key token in the unmanaged shim public token string
4. compile the unmanaged shim.
5. Authenticode sign the unmanaged shim
6. Add the managed addin and unmanaged shim to the installer binaries (we don't use the built in installer with .net as it's got TONS of problems).
7. Build and test installer
Note that after step 3 if you build or rebuild your addin the key will change and the unmanaged addin will no longer call it; you have to start over.
So far I'm only doing this with our dll's and I've just gotten it to work. Thanks for your tip. - Anonymous
July 21, 2004
can you provide an example project with c#?
my problem is, that my shim will not load in word
the addin is written in c#, i followed the steps from the article
everything is compiled fine, the shim is registered correctly but is not shown under word-comaddins - Anonymous
July 21, 2004
I'm not that familiar with Word add-ins. Was it loading before you added the shim? - Anonymous
January 21, 2009
The comment has been removed - Anonymous
June 13, 2009
PingBack from http://hairgrowthproducts.info/story.php?id=5469