środa, 13 kwietnia 2011

Zamieszanie z Any CPU, x86, x64 w .NET (Wstęp) [PL]

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.
Warto również przeczytać artykuł: MSDN: 64-bit Applications.

Czytaj dalej ...
Promuj

3 komentarze:

  1. Dzięki, przyda się ta wiedza :)

    OdpowiedzUsuń
  2. 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ń
  3. 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ń

Posty powiązane / Related posts