Stworzyłem proste rozwiązanie, które jest w stanie załadować specyficzny dla platformy zestaw z pliku wykonywalnego skompilowanego jako AnyCPU. Technika stosowana można podsumować w następujący sposób:
- Upewnij domyślnego mechanizmu ładowania .NET montaż („Fusion” silnika) nie można znaleźć zarówno w wersji x86 lub x64 zespołu platformy specyficzne
- przed głównym Próby aplikacji ładują specyficzny dla platformy montaż, instalują niestandardowy resolver zespołu w bieżącej aplikacji AppDomain
- Teraz, gdy główna aplikacja potrzebuje zespołu specyficznego dla platformy, silnik Fusion zrezygnuje (z powodu kroku 1) i wywoła nasz niestandardowy przelicznik (z powodu kroku 2); w niestandardowym przeliczniku określamy aktualną platformę i korzystamy z wyszukiwania opartego na katalogu, aby załadować odpowiednią bibliotekę DLL.
Aby zademonstrować tę technikę, dołączam krótki samouczek oparty na wierszu poleceń. Przetestowałem powstałe pliki binarne w systemie Windows XP x86, a następnie Vista SP1 x64 (przez skopiowanie plików binarnych, podobnie jak w przypadku wdrożenia).
Uwaga 1: "csc.exe" jest kompilatorem C-sharp. Ten poradnik zakłada, że jest na swojej drodze (moje testy były przy użyciu "C: \ WINDOWS \ Microsoft.NET \ Framework \ v3.5 \ csc.exe")
UWAGA 2: Polecam utworzyć folder tymczasowy dla testów i uruchom linię poleceń (lub powershell), których aktualny katalog roboczy jest ustawiony na tę lokalizację, np
(cmd.exe)
C:
mkdir \TEMP\CrossPlatformTest
cd \TEMP\CrossPlatformTest
Etap 1: Zespół od platformy jest reprezentowany przez proste C# biblioteki klas:
// 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();
}
}
}
Etap 2: W kompilacji zespołów danej platformy za pomocą komend linii poleceń :
(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
Etap 3: Główny program jest podzielony na dwie części. „Inicjującego” zawiera główny punkt wejścia do pliku wykonywalnego i rejestruje resolverowi zwyczaj składania w bieżącym AppDomain:
// 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;
}
}
}
„Program” jest „prawdziwy” Wdrażanie aplikacji (zauważ, że App.Run została wywołana u koniec Bootstrapper.Główny):
// file 'program.cs' in C:\TEMP\CrossPlatformTest
namespace Cross.Platform.Program
{
public static class App
{
public static void Run()
{
Cross.Platform.Library.Worker.Run();
}
}
}
Krok 4: Kompilacja główny wniosek z linii komend:
(cmd.exe from Note 2)
csc /reference:platform\x86\library.dll /out:program.exe program.cs bootstrapper.cs
Krok 5: Mamy teraz zakończona. Struktura katalogu stworzyliśmy powinna być następująca:
(C:\TEMP\CrossPlatformTest, root dir)
platform (dir)
amd64 (dir)
library.dll
x86 (dir)
library.dll
program.exe
*.cs (source files)
Jeśli teraz uruchomić program.exe na platformie 32-bitowej, platforma \ x86 \ library.dll zostanie załadowany; jeśli uruchomisz program.exe na 64-bitowej platformie, zostanie załadowana platforma \ amd64 \ library.dll. Zauważ, że dodałem Console.ReadLine() na końcu metody Worker.Run, dzięki czemu możesz użyć menedżera zadań/eksploratora procesów do zbadania załadowanych bibliotek DLL lub możesz użyć Visual Studio/Windows Debugger, aby dołączyć do procesu, aby zobaczyć stos wywołań itp.
Po uruchomieniu programu program.exe nasz moduł rozwiązywania problemów z połączeniem niestandardowym jest dołączany do bieżącego appdomain. Gdy tylko .NET rozpoczyna ładowanie klasy Program, widzi zależność od złożenia "biblioteki", więc próbuje załadować ją. Jednak nie znaleziono takiego zestawu (ponieważ ukryliśmy go w podkatalogach platform/*). Na szczęście nasz niestandardowy resolver zna naszą sztuczkę i bazuje na bieżącej platformie, którą próbuje załadować złożenie z odpowiedniego podkatalogu platform/*.
Używamy podobne podejście, ale zdarzenie jest dołączony w statycznym konstruktorze - ten sposób w niektórych przypadkach dzieje się przed przywiązanie.NET próbuje załadować inny zestaw. – Yurik
Proszę zaktualizować, aby użyć Environment.Is64BitProcess - ponieważ może się różnić od procesora na komputerze. W przeciwnym razie - bardzo dobrze odpowiedziano - używamy czegoś podobnego. – Yurik
"PROCESSOR_ARCHITECTURE" jest poprawne - w rzeczywistości odzwierciedla proces, a nie maszynę. – Fowl