Я создал простое решение, способное загружать сборку для конкретной платформы из исполняемого файла, скомпилированного как AnyCPU. Используемая техника может быть кратко изложена следующим образом:
- Убедитесь, что механизм загрузки сборки .NET по умолчанию (механизм "Fusion") не может найти версию сборки для платформы x86 или x64
- Перед тем, как основное приложение попытается загрузить сборку для конкретной платформы, установите пользовательский распознаватель сборок в текущем домене приложений
- Теперь, когда основному приложению требуется сборка для конкретной платформы, механизм Fusion сдается (из-за шага 1) и вызывает наш собственный распознаватель (из-за шага 2); в пользовательском преобразователе мы определяем текущую платформу и используем поиск на основе каталогов для загрузки соответствующей DLL.
Чтобы продемонстрировать эту технику, я прилагаю краткое руководство на основе командной строки. Я протестировал полученные двоичные файлы в Windows XP x86, а затем в Vista SP1 x64 (скопировав двоичные файлы, как при развертывании).
Примечание 1 : "csc.exe" - это компилятор C-sharp. В этом руководстве предполагается, что он находится на вашем пути (в моих тестах использовалось «C: \ WINDOWS \ Microsoft.NET \ Framework \ v3.5 \ csc.exe»)
Примечание 2 : я рекомендую вам создать временную папку для тестов и запустить командную строку (или powershell), чей текущий рабочий каталог настроен на это расположение, например
(cmd.exe)
C:
mkdir \TEMP\CrossPlatformTest
cd \TEMP\CrossPlatformTest
Шаг 1 : Сборка для конкретной платформы представлена простой библиотекой классов C #:
// file 'library.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Library
{
public static class Worker
{
public static void Run()
{
System.Console.WriteLine("Worker is running");
System.Console.WriteLine("(Enter to continue)");
System.Console.ReadLine();
}
}
}
Шаг 2 : Мы компилируем сборки для платформы, используя простые команды командной строки:
(cmd.exe from Note 2)
mkdir platform\x86
csc /out:platform\x86\library.dll /target:library /platform:x86 library.cs
mkdir platform\amd64
csc /out:platform\amd64\library.dll /target:library /platform:x64 library.cs
Шаг 3 : Основная программа разделена на две части. «Bootstrapper» содержит основную точку входа для исполняемого файла и регистрирует пользовательский преобразователь сборок в текущем домене приложения:
// file 'bootstrapper.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Program
{
public static class Bootstrapper
{
public static void Main()
{
System.AppDomain.CurrentDomain.AssemblyResolve += CustomResolve;
App.Run();
}
private static System.Reflection.Assembly CustomResolve(
object sender,
System.ResolveEventArgs args)
{
if (args.Name.StartsWith("library"))
{
string fileName = System.IO.Path.GetFullPath(
"platform\\"
+ System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE")
+ "\\library.dll");
System.Console.WriteLine(fileName);
if (System.IO.File.Exists(fileName))
{
return System.Reflection.Assembly.LoadFile(fileName);
}
}
return null;
}
}
}
«Программа» - это «реальная» реализация приложения (обратите внимание, что App.Run был вызван в конце Bootstrapper.Main):
// file 'program.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Program
{
public static class App
{
public static void Run()
{
Cross.Platform.Library.Worker.Run();
}
}
}
Шаг 4 : скомпилировать главное приложение в командной строке:
(cmd.exe from Note 2)
csc /reference:platform\x86\library.dll /out:program.exe program.cs bootstrapper.cs
Шаг 5 : Теперь мы закончили. Структура созданного нами каталога должна быть следующей:
(C:\TEMP\CrossPlatformTest, root dir)
platform (dir)
amd64 (dir)
library.dll
x86 (dir)
library.dll
program.exe
*.cs (source files)
Если вы теперь запустите program.exe на 32-битной платформе, будет загружена платформа \ x86 \ library.dll; если вы запустите program.exe на 64-битной платформе, будет загружена платформа \ amd64 \ library.dll. Обратите внимание, что я добавил Console.ReadLine () в конце метода Worker.Run, чтобы вы могли использовать диспетчер задач / обозреватель процесса для исследования загруженных библиотек DLL или использовать отладчик Visual Studio / Windows для подключения к процессу, чтобы увидеть стек вызовов и т. д.
При запуске program.exe наш пользовательский распознаватель сборок присоединяется к текущему домену приложения. Как только .NET начинает загружать класс Program, он видит зависимость от сборки библиотеки, поэтому он пытается загрузить ее. Однако, такая сборка не найдена (потому что мы скрыли ее в подкаталогах platform / *). К счастью, наш пользовательский распознаватель знает нашу хитрость и на основе текущей платформы пытается загрузить сборку из соответствующей подкаталога platform / *.