We have two versions of a managed C++ assembly, one for x86 and one for x64. This assembly is called by a .net application complied for AnyCPU. We are deploying our code via a file copy install, and would like to continue to do so.
Is it possible to use a Side-by-Side assembly manifest to loading a x86 or x64 assembly respectively when an application is dynamically selecting it’s processor architecture? Or is there another way to get this done in a file copy deployment (e.g. not using the GAC)?
I created a simple solution that is able to load platform-specific assembly from an executable compiled as AnyCPU. The technique used can be summarized as follows:
To demonstrate this technique, I am attaching a short, command-line based tutorial. I tested the resulting binaries on Windows XP x86 and then Vista SP1 x64 (by copying the binaries over, just like your deployment).
Note 1: ‘csc.exe’ is a C-sharp compiler. This tutorial assumes it is in your path (my tests were using ‘C:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe’)
Note 2: I recommend you create a temporary folder for the tests and run command line (or powershell) whose current working directory is set to this location, e.g.
Step 1: The platform-specific assembly is represented by a simple C# class library:
Step 2: We compile platform-specific assemblies using simple command-line commands:
Step 3: Main program is split into two parts. ‘Bootstrapper’ contains main entry point for the executable and it registers a custom assembly resolver in current appdomain:
‘Program’ is the ‘real’ implementation of the application (note that App.Run was invoked at the end of Bootstrapper.Main):
Step 4: Compile the main application on command line:
Step 5: We’re now finished. The structure of the directory we created should be as follows:
If you now run program.exe on a 32bit platform, platform\x86\library.dll will be loaded; if you run program.exe on a 64bit platform, platform\amd64\library.dll will be loaded. Note that I added Console.ReadLine() at the end of the Worker.Run method so that you can use task manager/process explorer to investigate loaded DLLs, or you can use Visual Studio/Windows Debugger to attach to the process to see the call stack etc.
When program.exe is run, our custom assembly resolver is attached to current appdomain. As soon as .NET starts loading the Program class, it sees a dependency on ‘library’ assembly, so it tries loading it. However, no such assembly is found (because we’ve hidden it in platform/* subdirectories). Luckily, our custom resolver knows our trickery and based on the current platform it tries loading the assembly from appropriate platform/* subdirectory.