Delay Signing a C++/CLI Assembly

This should be easy, right? Just set the link options to delay sign the assembly with an SNK file. There were two issues I ran into, which I’ll describe here.

Fixing Delay Signing in SP1

I used the /DELAYSIGN and /KEYFILE settings in the properties page for my C++/CLI project and everything compiled just fine. However, when I tried to use an object from this DLL, I got this message::

CS1577: Assembly generation failed … does not have a strong name

This certainly wasn’t what I expected. My first step was to double-check the signing on the assembly. I used the following command-line command to check:

 sn -T AssemblyName.dll

When I ran this command, it reported “AssemblyName.dll does not represent a strongly named assembly". Obviously the properties I set in the project settings dialog weren’t working. After quite a bit of searching, I found a blog post by Amit Mohindra that explained the problem, which is a change in Visual Studio 2010 SP1.

The blog post had suggestions on how to fix the problem, but it seemed like quite a bit of work. I tried another approach, which worked just fine.

Signing via AssemblyInfo.cpp

I added an new file called AssemblyInfo.cpp to my project, which has the following contents:

 #include "stdafx.h"
 

using namespace System;
using namespace System::Reflection;
 

[assembly:AssemblyKeyFile("myKey.snk")];
[assembly:AssemblyDelaySign(true)];

This took care of signing the assembly, which I verified using the sn command.

Dealing with C++/CLI vs C# Assemblies

One this was all working, we added a call from our C# EXE into the C++/CLI assembly, and got this run-time error:

Could not load file or assembly 'AssemblyName, Version=0.0.0.0, Culture=neutral, PublicKeyToken=…' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Incorrect format? Huh?

With a little more searching, I found the problem, and now that I understand the problem, it makes perfect sense. First, the solution. You need to change the Platform from Any CPU to x86 for you main EXE (or x64 if you’re building a 64-bit version) to match the bitness of your C++/CLI assembly:

image

Here’s why we had to make this change. Our C++/CLI assembly is calling not a pure .NET assembly since it’s making calls to windows APIs. As such, the C++/CLI assembly needs to be either 32- or 64-bit. It can’t be both because of the native C++ code it contains. A .NET assembly that is built for Any CPU can run as either a 32- or 64-bit process, but you can’t load a 32-bit DLL into a 64-bit process, hence the error. Building a 32-bit .NET EXE that loads the 32-bit C++/CLI DLL fixes the problem.