W 64-bitowych systemach Windows mogą działać aplikacje skomplikowane na platformę 64-bitową, jak też w trybie symulacji 32-bitowe (skompilowane na platformę x86, ale ... aplikacja 64-bitowa może korzystać tylko z 64-bitowych komponentów (np. bibliotek), a aplikacja 32-bitowa może korzystać tylko z 32-bitowych komponentów. Do tego na platformie .NET dochodzi jeszcze kompilacja typu „Any CPU”, co w konsekwencji może spowodować nie małe zamieszanie.... Przyjrzyjmy się może tym zagadnieniom.
W niniejszych rozważaniach wykorzystane zostanie solution składające się z trzech aplikacji (każda skompilowana w „inny sposób”, ale każda skompilowana jest na platformę .NET 2.0) i biblioteki DLL, która dostarcza nam pewnych informacji w postaci łańcucha tekstowego:
Wspomniana biblioteka dostarcza następującej funkcjonalności:
using System; namespace lib_x86_x64 { public class ClassLib { public static string GetInformationAboutEnvironment() { return String.Format( "IntPtr.Size={0}, Environment (proces) is x64: {1}", IntPtr.Size, IntPtr.Size == 8 ); } } }
W funkcji GetInformationAboutEnvironment sprawdzana jest długość wskaźnika do pamięci (IntPtr). Długość ta jest inna
na 64-biotwych i 32-bitowych systemach (wynosi ona 8 dla systemów
x64 i 4 dla x86).
W przytoczonym przykładzie każda z aplikacji wykonuje następującą operację:
static void Main( string[] args ) { Console.WriteLine( "Information from referenced library: {0}", lib_x86_x64.ClassLib.GetInformationAboutEnvironment() ); Console.ReadLine(); }
Tryb kompilacji wybieramy we właściwościach „Build” dla projektu w Visual Studio:
Zobaczmy teraz, jakie będą efekty (w systemie Windows 7 x64):
- W aplikacji app_anycpu otrzymamy: „Information from referenced library: IntPtr.Size=8, Environment (proces) is x64: True”
- W aplikacji app_x86 otrzymamy: „Information from referenced library: IntPtr.Size=4, Environment (proces) is x64: False”
- W aplikacji app_x64 otrzymamy: „Information from referenced library: IntPtr.Size=8, Environment (proces) is x64: True”
Czyli kompilując na konkretną platformę (x86 lu x64) możemy
wymusić, by aplikacja działała w środowisku 32 lub 64 –
bitowym. Przy wyborze kompilacji typu „Any CPU” aplikacja
powinna się „dostosować” i w systemie 32-bit działać jako
32-bit, natomiast w systemie 64-bit jako 64-bit. Przy kompilacji „Any
CPU” należy jednak uważać, by wszystkie wykorzystane
biblioteki były zgodne z aktualną platformą. Np. gdy we
wspomnianym przykładzie ustawimy kompilację x86 dla biblioteki
lib_x86_x64 ze wspomnianego solution, to uruchamiając
aplikację app_anycpu w systemie 64-bitowym otrzymamy wyjątek:
System.BadImageFormatException was unhandled Message=Nie można załadować pliku lub zestawu 'lib_x86_x64, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' lub jednej z jego zależności. Próbowano załadować program w niepoprawnym formacie. Source=app_anycpu FileName=lib_x86_x64, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null FusionLog==== Informacje o stanie sprzed powiązania === StackTrace: w app_anycpu.Program.Main(String[] args) w System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) w Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() w System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) w System.Threading.ThreadHelper.ThreadStart()
Czyli aplikacja została uruchomiona jako 64 bit, ale spróbowała
zażądać innej biblioteki, ale ta przygotowana była na platformę
32 bit i nie udało jej się załadować. Z podobnymi problemami
można się spotkać również przy korzystaniu z innych zasobów
systemu operacyjnego, np. gdy z poziomu naszej aplikacji
(kompilowanej na platformę x86) korzystamy z połączenia z bazą
danych, a w systemie operacyjnym sterowniki są 64 bitowe.
Dzięki, przyda się ta wiedza :)
OdpowiedzUsuńDopiero się uczę .NET i takie rzeczy mnie przerażają. Technologia jest reklamowana jako coś przenaszalnego, multiplatformowego, a tu okazuje się, że kod jest generowany pod konkretną platformę. Czyli w momencie gdy wyjdzie Win 8 na ARM stare programy się na nim nie odpalą?
OdpowiedzUsuńOtóż okazuje się (o czym piszę w następnym wpisie: http://maciej-progtech.blogspot.com/2011/04/sprawdzamy-platforme-na-jaka-zostao.html), że kod kompilowany jest zawsze tak samo! Aby mieć przenoszalny kod trzeba wybierać "Any CPU", jednak jest to rozwiązanie dobre tylko, gdy całe oprogramowanie jest na platformie .NET, nie korzysta z COM, sterowników w systemie operacyjnym, itp... I właśnie takich ograniczeń trzeba mieć świadomość!
OdpowiedzUsuń