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:
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.
Comments
- Anonymous
March 03, 2015
How did you resolve the System and System::Reflection references? I keep getting the error "Must be a namespace name".