Stubbornness is a form of persistence and I’m continually amazed at my inability to give something up and move on – at least when it comes to programming. Getting a signed C++/CLI DLL to work with a C# project had me stumped for a while. Here’s the process I went through.
First, create a new solution:
Now add, a C++/CLI class library project:
I’ve called the project ClassLibrary1 and added some trivial code:
public ref class Class1
public: void Foo()
The first step to making this a strong-named DLL is to generate a cryptographic key pair using sn.exe. This command line utility is located under the “Microsoft Visual Studio 8SDKv2.0Bin” directory path. To execute sn.exe you’ll need a Run prompt. To bring up the Run prompt hit the Windows+R key combo. Now type CMD and hit Enter:
You have to navigate to the Bin directory mentioned earlier. The DOS command to do this is called CD (change directory). For example:
Call sn.exe with the -k option to generate a new key pair to the specified file. In this example, a new key pair is generated and written to the file ClassLibrary1.snk:
Grab the newly generated file from the Bin folder and cut ‘n paste it into your project folder:
Inside of AssemblyInfo.cpp, add the following line of code:
Compile the project and mt.exe (manifest tool) returns the following:
general warning 810100b3: ..debugClassLibrary1.dll is a strong-name
signed assembly and embedding a manifest invalidates the signature.
You will need to re-sign this file to make it a valid assembly.
Okay…So let’s get rid of the embedded manifest:
A rebuild proves successful. Now add a CLR console app:
Right-click the project and select References to bring up the following dialog:
Under the Projects tab select ClassLibrary1 and click OK:
You should see the newly added ClassLibrary1 in the References section. None of the Build Properties need to be altered.
I’ve added the following code to test things out:
using namespace System;
using namespace System::Reflection;
int main(array<System::String ^>^ args)
for each(Assembly^ a in AppDomain::CurrentDomain->GetAssemblies())
Set ConsoleApplication1 as the startup project and test it app. Output example:
The output shows the full name of ClassLibrary1 with PublicKeyToken and hash value. Now, you may think everything is working fine but let’s see what happens when a C# project tries to use ClassLibrary1.dll. Add a new C# console project and a reference to ClassLibrary1:
As soon as you do so, the following warning pops up:
And sure enough, if you compile it, the build fails with a ResolveNativeReference task failure. So, delete the reference to ClassLibrary1. Add the reference again but this time, do so from the Browse tab:
Recompile and it builds successfully. Now, just because it compiles doesn’t mean it works, so let’s test it out.
static void Main(string args)
ClassLibrary1.Class1 c1 = new ClassLibrary1.Class1();
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
Hit F5 to launch a debug session and:
The specified module could not be found. Great…but which module? After messing with this failure for a long time it turns out I should have signed the assembly in a different manner (not using the AssemblyKeyFile attribute). Have you ever signed a C# DLL? If you open the AssemblyInfo.cs file (it’s inside the Properties folder) and add the following:
It returns with a warning not to use it.
Use command line option '/keyfile' or appropriate project settings instead of
Visual Studio prefers you go under project properties to set the stong name.
Okay. Perhaps we can do something similar with the C++/CLI DLL? In the ClassLibrary1 project, remove the AssemblyKeyFile attribute from the AssemblyInfo.cpp file. Under the project properties, restore Embed Manifest to Yes. Now go to the Advanced section and set:
A rebuild proves successful. Run it and it works! Finally…
In the future, don’t forget to add the library via the Browse tab or you’ll get a ResolveNativeReference error.