Using TLBIMP.exe to create Strong Named Interop Assemblies

Filed under .NET, Utilities

Working on a VSTO 8 Word addin recently, I discovered to in order to deploy it, you must “strong name” the assembly.

I’d already obtained a Verisign certificate for digital code signing, and had a password protected PFX file containing both my public and private keys, so I figured I had what I needed.

So, I loaded the project, set the signing options to use my PFX file and compiled.

Full stop.

“Interop.Word.dll” is not strong named

Doh.

A little research later and it turns out that if you strong name one assembly, every single assembly that it references must also be strong named!

Yikes. In my case, I have almost a dozen, plus piles of interop assemblies for accessing legacy COM libraries.

First, the .NET assemblies. Setting them to be strong named using the same PFX file is easy, just use VS, under the project properties.

image

But, if your .net code refers to any COM components, it’s very likely you also have references to “interop” assemblies. These are DLLs that VS creates for you “behind the scenes” to act as convenient .net wrappers around the COM library objects.

The problem is that VS won’t automatically strong name those interop assemblies, and if you strong name your .net assembly, those interop assemblies also must be strong named.

First, I tried just creating an interop assembly.

I chose the Word 2000 object library to initially play with, but just about any COM dll or TLB or OLB file will do.

tlbimp "{path}\msword9.olb" /verbose /out:Interop.Word2000.dll /sysarray

(note, {path} is the path to your copy of this file, and the /sysarray option appears to be required if your working with just about any COM based interface). Worked like a champ.

So, I add in the keyfilename argument:

tlbimp "{path}\msword9.olb" /verbose /keyfilename:mycert.pfx /out:Interop.Word2000.dll /sysarray

and TLBIMP responds with an “Incorrect strong name arguments specified” error.

I then tried the PUBLICKEY option, like so:

tlbimp "{path}\msword9.olb" /verbose /keyfilename:mycert.pfx /out:Interop.Word2000.dll /sysarray

This appeared to work, until I actually tried to run my application. It failed, indicating that the “Strong Named Assembly was corrupt or was not signed with a private key”. Apparently, PUBLICKEY means just that, that the public key is used for one part of the signing process, and that you have to use a private key for the other.

I really didn’t want this to be a two step process so I kept looking.

Eventually, I discovered that signing an assembly is a completely separate process from “Strong Naming” an assembly.

Strong Naming an assembly doesn’t guarantee that you wrote it, but it does provide a way for one assembly to guarantee that it is loading the exact same assembly that it was compiled to work with, a subtle but significant difference.

Signing an assembly, on the other hand, requires a certificate from a signing authority, like Verisign. Signing does guarantee that an assembly was written by who the certificate says it was written by.

From what I can tell with VS2008, signing an assembly automatically strong names it, but the reverse is not true.

And certain assemblies need to be signed, (such as the primary assembly for an Office Addin), but others don’t.

And still others need to be strong named, but don’t necessarily need to be signed (such as any assembly or interop assembly referenced by an Office Addin.

But when you do this, you might notice that you end up with another unexplained dll in your output folder, called Office.dll.

After some digging, it turns out that TLBIMP will also create interop files for those COM libraries referenced by the COM library that you’re creating an interop file from. And you’ll need to include those additional interop files with your app for everything to load properly.

This is where the /reference option comes in. First, generate a strong named interop file for the referenced COM library, and then for the COM library you actually care about, like so:

tlbimp "{path}mso9.dll" /out:Interop.Office2000.dll /sysarray /verbose /keyfilename:mycert.snk 
tlbimp "{path}msword9.olb" /out:Interop.Word2000.dll /sysarray /verbose /keyfilename:mycert.snk /reference:Interop.Office2000.dll

The first line will create the Interop file for the Office.dll, which is referenced by Word.

The second line will create the interop file for Word itself, but note that it uses the /reference option to indicate that this interop file should reference the just created interop file for the Office library.

Finally, a note about namespaces. You’ll notice that I specified an OUT filename of Interop.Word2000.dll.

TLBIMP appears to automatically assume that when you do that, you want the classes defined within that interop file to exist within the “Interop.Word2000” namespace (ie the file name minus the “.dll”).

image

This may be appropriate, but it may not be, depending on your needs. Why might you want to change it? The only reason I can think of offhand is that you are referencing multiple versions of a single COM interface. A common example would be the need to reference both the Office 2007 Primary Interop files (available directly from Microsoft), and the Office 2000 interop files you created yourself (because MS doesn’t provide them).

It is possible that the two Interop files would have the same namespace and would collide.

Changing the namespace of one of them will allow your assembly to reference both interop files with no collisions. This is one element of .net that is, at the same time, unfortunately complicated, but incredibly useful.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*