Sdílet prostřednictvím


Migrace 32bitového spravovaného kódu na 64bitovou verzi

 

Microsoft Corporation

Aktualizováno v květnu 2005

Platí pro:
   Microsoft .NET
   Microsoft .NET Framework 2.0

Shrnutí: Zjistěte, co je součástí migrace 32bitových spravovaných aplikací na 64bitovou verzi, problémy, které můžou mít vliv na migraci, a nástroje, které jsou k dispozici pro pomoc. (17 tištěných stránek)

Obsah

Úvod
Spravovaný kód v 32bitovém prostředí
Zadejte CLR pro 64bitové prostředí.
Migrace a vyvolání platformy
Migrace a interoperabilita modelu COM
Migrace a nebezpečný kód
Migrace a zařazování
Migrace a serializace
Souhrn

Úvod

Tento dokument white paper popisuje:

  • Co je součástí migrace spravovaných aplikací z 32bitové na 64bitovou verzi
  • Problémy, které můžou mít vliv na migraci
  • Jaké nástroje jsou k dispozici, aby vám pomohly

Tyto informace nemají být preskriptivní; jeho cílem je spíše seznámit vás s různými oblastmi, které jsou náchylné k problémům během procesu migrace na 64bitovou verzi. V tuto chvíli neexistuje žádná konkrétní "kuchařka" kroků, kterou byste mohli postupovat a ujistit se, že váš kód bude fungovat na 64bitové verzi. Informace obsažené v tomto dokumentu white paper vás seznámí s různými problémy a s tím, co byste měli zkontrolovat.

Jak brzy uvidíte, pokud vaše spravované sestavení není 100% typ bezpečný kód, budete muset zkontrolovat aplikaci a její závislosti, abyste zjistili problémy s migrací na 64bitovou verzi. Mnohé z položek, o které si přečtete v dalších částech, se dají vyřešit prostřednictvím programovacích změn. V řadě případů budete také muset vyhradit čas na aktualizaci kódu, aby mohl správně běžet v 32bitovém i 64bitovém prostředí, pokud chcete, aby se kód spouštěl v obou.

Microsoft .NET je sada softwarových technologií pro propojení informací, lidí, systémů a zařízení. Od vydání verze 1.0 v roce 2002 se organizacím podařilo nasadit . Řešení založená na technologii NET, ať už jsou vytvořená interně, nezávislými výrobci softwaru (ISV) nebo nějakou kombinací. Existuje několik typů aplikací .NET, které využívají limity 32bitového prostředí. Mezi tyto výzvy patří mimo jiné potřeba reálnější adresovatelné paměti a potřeba vyššího výkonu s plovoucí desetinnou čárkou. x64 a Itanium nabízejí lepší výkon pro operace s plovoucí desetinnou čárkou, než můžete získat na platformě x86. Je však také možné, že výsledky, které získáte na platformě x64 nebo Itanium, se budou lišit od výsledků, které získáte na platformě x86. Cílem 64bitové platformy je tyto problémy vyřešit.

S vydáním rozhraní .NET Framework verze 2.0 microsoft zahrnuje podporu spravovaného kódu spuštěného na 64bitových platformách x64 a Itanium.

Spravovaný kód je jednoduše "kód", který poskytuje dostatek informací, aby modul CLR (Common Language Runtime) .NET mohl poskytovat sadu základních služeb, mezi které patří:

  • Vlastní popis kódu a dat prostřednictvím metadat
  • Stack walking
  • Zabezpečení
  • Uvolnění paměti
  • Kompilace za běhu

Kromě spravovaného kódu existuje několik dalších definic, kterým je důležité porozumět při zkoumání problémů s migrací.

Spravovaná data – data přidělená na spravované haldě a shromážděná prostřednictvím uvolňování paměti.

Sestavení – jednotka nasazení, která umožňuje CLR plně porozumět obsahu aplikace a vynutit pravidla správy verzí a závislostí definovaná aplikací.

Bezpečný kód typu – kód, který používá pouze spravovaná data, a žádné neověřitelné datové typy nebo nepodporované operace převodu/donucování datových typů (to znamená nediskriminované sjednocení nebo ukazatele struktury/rozhraní). Kód jazyka C#, Visual Basic .NET a Visual C++ kompilovaný pomocí /clr:safe vygeneruje typ bezpečného kódu.

Nebezpečný kód – kód, který může provádět takové operace nižší úrovně, jako je deklarace a operace s ukazateli, provádění převodů mezi ukazateli a integrálními typy a převzetí adresy proměnných. Tyto operace umožňují propojení se základním operačním systémem, přístup k zařízení mapovanému paměti nebo implementaci časově kritického algoritmu. Nativní kód je nebezpečný.

Spravovaný kód v 32bitovém prostředí

Abychom pochopili složitost migrace spravovaného kódu do 64bitového prostředí, podívejme se, jak se spravovaný kód spouští v 32bitovém prostředí.

Pokud je vybrána aplikace, spravovaná nebo nespravovaná, která má být spuštěna, vyvolá se zavaděč systému Windows, který je zodpovědný za rozhodnutí o tom, jak aplikaci načíst a pak spustit. Součástí tohoto procesu je nahlédnutí do hlavičky portable execution (PE) spustitelného souboru, aby se zjistilo, jestli se clR vyžaduje. Jak jste už možná uhodli, v pe jsou příznaky, které označují spravovaný kód. V tomto případě zavaděč systému Windows spustí CLR, který pak zodpovídá za načtení a spuštění spravované aplikace. (Toto je zjednodušený popis procesu, protože zahrnuje mnoho kroků, včetně určení verze CLR, která se má spustit, nastavení sandboxu appdomain atd.)

Vzájemná funkční spolupráce

Při spuštění spravované aplikace může (za předpokladu odpovídajících oprávnění zabezpečení) interagovat s nativními rozhraními API (včetně rozhraní API Win32) a objekty COM prostřednictvím funkcí interoperability CLR. Ať už volá rozhraní API nativní platformy, vytváří požadavek modelu COM nebo zařaďuje strukturu, je vývojář při úplném spuštění v 32bitovém prostředí izolovaný od toho, aby musel myslet na velikosti a zarovnání dat datových typů.

Při zvažování migrace na 64bitovou verzi bude nezbytné zjistit, jaké závislosti má vaše aplikace.

Zadejte CLR pro 64bitové prostředí.

Aby bylo možné spustit spravovaný kód v 64bitovém prostředí konzistentním s 32bitovým prostředím, tým .NET vyvinul modul CLR (Common Language Runtime) pro 64bitové systémy Itanium a x64. ClR musel striktně dodržovat pravidla common language infrastructure (CLI) a Common Language Type System, aby se ujistil, že kód napsaný v některém z jazyků .NET bude schopen spolupracovat stejně jako v 32bitovém prostředí. Kromě toho je následující seznam některých dalších částí, které se také musely přenést nebo vyvinout pro 64bitové prostředí:

  • Knihovny základních tříd (System.*)
  • Kompilátor za běhu
  • Podpora ladění
  • sada SDK služby .NET Framework

Podpora 64bitového spravovaného kódu

Rozhraní .NET Framework verze 2.0 podporuje 64bitové procesory Itanium a x64 se systémem:

  • Windows Server 2003 SP1
  • Budoucí verze 64bitového klienta Windows

(V systému Windows 2000 nelze nainstalovat rozhraní .NET Framework verze 2.0. Výstupní soubory vytvořené pomocí rozhraní .NET Framework verze 1.0 a 1.1 budou v 64bitovém operačním systému spouštět pod wow64.)

Při instalaci rozhraní .NET Framework verze 2.0 na 64bitovou platformu neinstalujete jenom veškerou infrastrukturu potřebnou ke spuštění spravovaného kódu v 64bitovém režimu, ale instalujete infrastrukturu potřebnou ke spuštění spravovaného kódu v subsystému Windows on-Windows nebo WoW64 (32bitový režim).

Jednoduchá 64bitová migrace

Představte si aplikaci .NET, která je 100% typem bezpečného kódu. V tomto scénáři je možné vzít spustitelný soubor .NET spuštěný na 32bitovém počítači a přesunout ho do 64bitového systému a nechat ho úspěšně spustit. Proč to funguje? Vzhledem k tomu, že sestavení je 100% typ bezpečné, víme, že neexistují žádné závislosti na nativním kódu nebo objektech COM a že neexistuje žádný nebezpečný kód, což znamená, že aplikace běží zcela pod kontrolou CLR. CLR zaručuje, že zatímco binární kód vygenerovaný jako výsledek kompilace ZA běhu (JIT) se bude mezi 32bitovou a 64bitovou verzí lišit, kód, který se spustí, bude sémanticky stejný. (V systému Windows 2000 nelze nainstalovat rozhraní .NET Framework verze 2.0. Výstupní soubory vytvořené pomocí rozhraní .NET Framework verze 1.0 a 1.1 budou v 64bitovém operačním systému spuštěny v rámci wow64.)

Ve skutečnosti je předchozí scénář z hlediska načtení spravované aplikace trochu složitější. Jak je popsáno v předchozí části, za zavaděč systému Windows zodpovídá za rozhodování, jak aplikaci načíst a spustit. Na rozdíl od 32bitového prostředí však spuštění na 64bitové platformě Windows znamená, že existují dvě (2) prostředí, ve kterých je možné aplikaci spustit, a to buď v nativním 64bitovém režimu, nebo ve WoW64.

Zavaděč windows se teď musí rozhodovat na základě toho, co zjistí v hlavičce PE. Jak jste možná uhodli, ve spravovaném kódu jsou nastavené příznaky, které pomáhají s tímto procesem. (Viz corflags.exe zobrazení nastavení v pe.) Následující seznam představuje informace, které jsou nalezeny v PE, které pomáhají v rozhodovacím procesu.

  • 64bitová verze – označuje, že vývojář sestavil sestavení speciálně zaměřené na 64bitový proces.
  • 32bitová verze – označuje, že vývojář sestavil sestavení určené speciálně pro 32bitový proces. V tomto případě se sestavení spustí ve WoW64.
  • Agnostic – označuje, že vývojář vytvořil sestavení pomocí sady Visual Studio 2005 s kódem "Whidbey". nebo novější nástroje a že sestavení může běžet v 64bitovém nebo 32bitovém režimu. V tomto případě 64bitový zavaděč systému Windows spustí sestavení v 64bitové verzi.
  • Starší – označuje, že nástroje, které sestavu vytvořily, byly "pre-Whidbey". V tomto konkrétním případě se sestavení spustí ve WoW64.

Poznámka V pe jsou také informace, které říkají zavaděče Systému Windows, pokud je sestavení cílem pro konkrétní architekturu. Tyto další informace zajišťují, že sestavení určená pro konkrétní architekturu nebudou načtena v jiné architektuře.

Kompilátory C#, Visual Basic .NET a C++ Whidbey umožňují nastavit příslušné příznaky v hlavičce pe. Například C# a THIRD mají možnost kompilátoru /platform:{anycpu, x86, Itanium, x64} .

Poznámka I když je technicky možné upravit příznaky v hlavičce PE sestavení po jeho kompilaci, Microsoft to nedoporučuje.

Pokud vás zajímá, jak jsou tyto příznaky nastaveny ve spravovaném sestavení, můžete spustit nástroj ILDASM, který je součástí sady .NET Framework SDK. Následující obrázek znázorňuje "starší" aplikaci.

Mějte na paměti, že vývojář, který označil sestavení jako Win64, zjistil, že všechny závislosti aplikace se spustí v 64bitovém režimu. 64bitový proces nemůže v procesu používat 32bitovou komponentu (a 32bitový proces nemůže načíst 64bitovou komponentu v procesu). Mějte na paměti, že schopnost systému načíst sestavení do 64bitového procesu automaticky neznamená, že se provede správně.

Nyní tedy víme, že aplikaci složenou ze spravovaného kódu, který je 100% bezpečný, je možné zkopírovat (nebo ji nasadit xcopy ) na 64bitovou platformu a nechat ji jit a úspěšně spustit s .NET v 64bitovém režimu.

Často ale vidíme situace, které nejsou ideální, a to nás přivádí k hlavnímu zaměření tohoto dokumentu, kterým je zvýšit povědomí o problémech souvisejících s migrací.

Můžete mít aplikaci, která není 100% typ bezpečná a která je stále schopná úspěšně spustit v 64bitové verzi v .NET. Bude důležité, abyste se na svou aplikaci podívali pečlivě, měli byste mít na paměti potenciální problémy probírané v následujících částech a určit, jestli můžete nebo nemůžete úspěšně spustit v 64bitové verzi.

Migrace a vyvolání platformy

Použití funkcí volání platformy (nebo p/invoke) v .NET odkazuje na spravovaný kód, který volá nespravovaný nebo nativní kód. V typickém scénáři je tímto nativním kódem dynamická knihovna (DLL), která je buď součástí systému (rozhraní API systému Windows atd.), součástí vaší aplikace nebo knihovnou třetí strany.

Použití nespravovaný kód explicitně neznamená, že migrace na 64bitovou verzi bude mít problémy. spíše by mělo být považováno za ukazatel, že je vyžadováno další šetření.

Datové typy ve Windows

Každá aplikace a každý operační systém má abstraktní datový model. Mnoho aplikací tento datový model explicitně nezpřístupňuje, ale model řídí způsob psaní kódu aplikace. V 32bitovém programovacím modelu (známém jako model ILP32) mají datové typy celé číslo, dlouhé a ukazatele délku 32 bitů. Většina vývojářů tento model použila, aniž by si to uvědomila.

V 64bitové verzi Systému Microsoft Windows je tento předpoklad parity ve velikostech datových typů neplatný. Vytvoření všech datových typů o délce 64 bitů by plýtlo místem, protože většina aplikací větší velikost nepotřebuje. Aplikace ale potřebují ukazatele na 64bitová data a ve vybraných případech potřebují mít 64bitové datové typy. Tyto aspekty vedly tým Windows k výběru abstraktního datového modelu s názvem LLP64 (nebo P64). V datovém modelu LLP64 se pouze ukazatele rozšiřují na 64 bitů; všechny ostatní základní datové typy (celé číslo a dlouhé) mají délku 32 bitů.

.NET CLR pro 64bitové platformy používá stejný abstraktní datový model LLP64. V .NET existuje celočíselný datový typ, který není všeobecně známý, který je speciálně určený pro uložení informací o ukazateli: IntPtr , jehož velikost závisí na platformě (např. 32bitová nebo 64bitová), na které běží. Představte si následující fragment kódu:

[C#]
public void SizeOfIntPtr() {
Console.WriteLine( "SizeOf IntPtr is: {0}", IntPtr.Size );
}

Při spuštění na 32bitové platformě získáte v konzole následující výstup:

SizeOf IntPtr is: 4

Na 64bitové platformě získáte na konzole následující výstup:

SizeOf IntPtr is: 8

Poznámka Pokud chcete za běhu zkontrolovat, jestli používáte 64bitové prostředí, můžete k tomuto určení použít IntPtr.Size .

Posouzení migrace

Při migraci spravovaných aplikací, které používají p/invoke, zvažte následující položky:

  • Dostupnost 64bitové verze knihovny DLL
  • Použití datových typů

Dostupnost

Jednou z prvních věcí, které je potřeba zjistit, je, jestli je nespravovaný kód, na který má vaše aplikace závislost, dostupný pro 64bitovou verzi.

Pokud byl tento kód vyvinut interně, zvýší se vaše schopnost úspěchu. Samozřejmě budete i nadále muset přidělit prostředky k přenosu nespravovaný kód do 64bitové verze spolu s vhodnými prostředky pro testování, zajištění kvality atd. (Tento dokument white paper nedává doporučení k vývojovým procesům, spíše se snaží poukázat na to, že může být potřeba přidělit prostředky úkolům pro portování kódu.)

Pokud je tento kód od třetí strany, budete muset prozkoumat, jestli už má tato třetí strana kód k dispozici pro 64bitovou verzi a jestli je tato třetí strana ochotná ho zpřístupnit.

K problému s vyšším rizikem dojde, pokud třetí strana již neposkytuje podporu pro tento kód nebo pokud třetí strana není ochotná provést práci. Tyto případy vyžadují další výzkum dostupných knihoven, které mají podobné funkce, zda třetí strana umožní zákazníkovi provést port sám atd.

Je důležité mít na paměti, že 64bitová verze závislého kódu může mít změněné podpisy rozhraní, které mohou znamenat další práci na vývoji, a vyřešit rozdíly mezi 32bitovou a 64bitovou verzí aplikace.

Typy dat

Použití p/invoke vyžaduje, aby kód vyvinutý v .NET deklaruje prototyp metody, na kterou se spravovaný kód zaměřuje. Vzhledem k následující deklaraci jazyka C:

[C++]
typedef void * HANDLE
HANDLE GetData();

Příklady metod prototypů jsou uvedené níže:

[C#]

[DllImport( "sampleDLL", CallingConvention=CallingConvention.Cdecl )]
      public static extern int DoWork( int x, int y );

[DllImport( "sampleDLL", CallingConvention=CallingConvention.Cdecl )]
      public unsafe static extern int GetData();

Pojďme se podívat na tyto příklady s pohledem na problémy s 64bitovou migrací:

První příklad volá metodu DoWork předávající dvě (2) 32bitová celá čísla a očekáváme, že se vrátí 32bitové celé číslo. I když běžíme na 64bitové platformě, celé číslo je stále 32 bitů. V tomto konkrétním příkladu není nic, co by mělo bránit našemu úsilí o migraci.

Druhý příklad vyžaduje některé změny kódu, aby se úspěšně spustilo v 64bitové verzi. To, co zde děláme, je volání metody GetData a deklarováno, že očekáváme, že se vrátí celé číslo, ale funkce ve skutečnosti vrací ukazatel int. Tady je náš problém: Mějte na paměti, že celá čísla jsou 32 bitů, ale v 64bitových ukazatelích jsou 8 bajtů. Jak se ukázalo, poměrně hodně kódu v 32bitovém světě bylo napsáno za předpokladu, že ukazatel a celé číslo mají stejnou délku, 4 bajty. V 64bitovém světě to už neplatí.

V tomto posledním případě lze problém vyřešit změnou deklarace metody na použití IntPtr místo int.

public unsafe static extern IntPtr GetData();

Provedení této změny bude fungovat v 32bitovém i 64bitovém prostředí. Nezapomeňte, že IntPtr je specifický pro konkrétní platformu.

Použití p/invoke ve spravované aplikaci neznamená, že migrace na 64bitovou platformu nebude možná. Ani to neznamená, že budou problémy. Znamená to, že musíte zkontrolovat závislosti na nespravovaný kód, který má vaše spravovaná aplikace, a určit, jestli nedojde k nějakým problémům.

Migrace a interoperabilita modelu COM

Interoperabilita modelu COM je předpokládanou funkcí platformy .NET. Stejně jako v předchozí diskuzi o volání platformy znamená použití interoperability modelu COM, že spravovaný kód volá nespravovaný kód. Na rozdíl od volání platformy ale interoperabilita modelu COM také znamená schopnost nespravovaného kódu volat spravovaný kód, jako by se jednalo o součást modelu COM.

Opět platí, že použití nespravovaný kód COM neznamená, že migrace na 64bitovou verzi bude mít problémy; spíše by mělo být považováno za ukazatel, že je vyžadováno další šetření.

Posouzení migrace

Je důležité si uvědomit, že s vydáním rozhraní .NET Framework verze 2.0 není podporována interoperabilita mezi architekturami. Chcete-li být stručnější, nemůžete využít interoperabilitu modelu COM mezi 32bitovou a 64bitovou verzí ve stejném procesu. Pokud ale máte mimoprocesový server COM, můžete využít interoperabilitu modelu COM mezi 32bitovou a 64bitovou verzí. Pokud nemůžete použít server COM mimo proces, budete chtít označit spravované sestavení jako Win32 místo Win64 nebo Agnostic, aby váš program běžel ve WoW64, aby mohl spolupracovat s 32bitovým objektem COM.

Následuje diskuse o různých aspektech, které je třeba vzít v úvahu při využití interoperability modelu COM, kde spravovaný kód provádí volání modelu COM v 64bitovém prostředí. Konkrétně:

  • Dostupnost 64bitové verze knihovny DLL
  • Použití datových typů
  • Knihovny typů

Dostupnost

Pro tuto část je relevantní také diskuze v části p/invoke týkající se dostupnosti 64bitové verze závislého kódu.

Typy dat

Pro tuto část je relevantní také diskuze v části p/invoke týkající se datových typů 64bitové verze závislého kódu.

Knihovny typů

Na rozdíl od sestavení nelze knihovny typů označit jako neutrální; Musí být označeny jako Win32 nebo Win64. Kromě toho musí být knihovna typů zaregistrovaná pro každé prostředí, ve kterém bude com spuštěn. K vygenerování 32bitového nebo 64bitového sestavení z knihovny typů použijte tlbimp.exe.

Použití interoperability modelu COM ve spravované aplikaci neznamená, že migrace na 64bitovou platformu nebude možná. Ani to neznamená, že budou problémy. Znamená to, že musíte zkontrolovat závislosti, které má vaše spravovaná aplikace, a určit, jestli nedojde k nějakým problémům.

Migrace a nebezpečný kód

Základní jazyk C# se od jazyka C a C++ liší hlavně tím, že vynechá ukazatele jako datový typ. Místo toho jazyk C# poskytuje odkazy a možnost vytvářet objekty spravované uvolňováním paměti. V základním jazyce C# jednoduše není možné mít neinicializovanou proměnnou, "visící" ukazatel nebo výraz, který indexuje pole za jeho hranicemi. Tím se eliminují celé kategorie chyb, které rutinně zamořují programy C a C++.

I když prakticky každý konstruktor typu ukazatele v jazyce C nebo C++ má v jazyce C# protějšek typu odkazu, existují situace, kdy se přístup k typům ukazatelů stává nutností. Například propojení se základním operačním systémem, přístup k zařízení mapovanému paměti nebo implementace algoritmu kritického pro čas nemusí být možné nebo praktické bez přístupu k ukazatelům. K vyřešení této potřeby poskytuje jazyk C# možnost psát nebezpečný kód.

V nebezpečném kódu je možné deklarovat a pracovat s ukazateli, provádět převody mezi ukazateli a integrálními typy, převzít adresu proměnných atd. V jistém smyslu se psaní nebezpečného kódu podobá psaní kódu jazyka C v rámci programu jazyka C#.

Nebezpečný kód je ve skutečnosti "bezpečná" funkce z pohledu vývojářů i uživatelů. Nebezpečný kód musí být jasně označený modifikátorem nebezpečný, aby vývojáři nemohli nebezpečné funkce použít omylem.

Posouzení migrace

Abychom mohli probrat potenciální problémy s nebezpečným kódem, pojďme se podívat na následující příklad. Náš spravovaný kód volá nespravovanou knihovnu DLL. Konkrétně existuje metoda s názvem GetDataBuffer , která vrací 100 položek (v tomto příkladu vracíme pevný počet položek). Každá z těchto položek se skládá z celého čísla a ukazatele. Níže uvedený ukázkový kód je výňatek ze spravovaného kódu znázorňující nebezpečnou funkci zodpovědnou za zpracování těchto vrácených dat.

[C#]

public unsafe int UnsafeFn() {
   IntPtr * inputBuffer = sampleDLL.GetDataBuffer();
   IntPtr * ptr = inputBuffer;
   int   result = 0;

   for ( int idx = 0; idx < 100; idx ++ ) {
      // Add 'int' from DLL to our result
      result = result + ((int) *ptr);

// Increment pointer over int (
      ptr = (IntPtr*)( ( (byte *) ptr ) + sizeof( int ) );

      // Increment pointer over pointer (
      ptr = (IntPtr*)( ( (byte *) ptr ) + sizeof( int ) );
   }
   return result;
}

Poznámka Tento konkrétní příklad by se dal provést bez použití nebezpečného kódu. Přesněji řečeno, existují další techniky, jako je zařazování, které bylo možné použít. K tomuto účelu ale používáme nebezpečný kód.

UnsafeFn prochází 100 položek a sečte celočíselná data. Při procházení vyrovnávací paměti dat musí kód krokovat přes celé číslo i ukazatel. Ve 32bitovém prostředí tento kód funguje správně. Jak jsme ale už dříve probírali, v 64bitovém prostředí mají ukazatele 8 bajtů, a proto segment kódu (zobrazený níže) nebude fungovat správně, protože používá běžnou programovací techniku, například považuje ukazatel za ekvivalent celočíselného čísla.

// Increment pointer over pointer (
ptr = (IntPtr*)( ( (byte *) ptr ) + sizeof( int ) );

Aby tento kód fungoval v 32bitovém i 64bitovém prostředí, bylo by nutné změnit kód na následující kód.

// Increment pointer over pointer (
ptr = (IntPtr*)( ( (byte *) ptr ) + sizeof( IntPtr ) );

Jak jsme právě viděli, existují případy, kdy je použití nebezpečného kódu nezbytné. Ve většině případů je to nutné v důsledku závislosti spravovaného kódu na jiném rozhraní. Bez ohledu na to, proč nebezpečný kód existuje, je potřeba ho v rámci procesu migrace zkontrolovat.

Příklad, který jsme použili výše, je poměrně jednoduchý a oprava, aby program fungoval v 64bitové verzi, byla jednoduchá. Je zřejmé, že existuje mnoho příkladů nebezpečného kódu, které jsou složitější. Některé z nich budou vyžadovat podrobnou kontrolu a možná se vrátí zpět a přehodnotí přístup, který spravovaný kód používá.

Opakování toho, co jste už četli – použití nebezpečného kódu ve spravované aplikaci neznamená, že migrace na 64bitovou platformu nebude možná. Ani to neznamená, že budou problémy. Znamená to, že musíte zkontrolovat veškerý nebezpečný kód, který má vaše spravovaná aplikace, a určit, jestli dojde k nějakým problémům.

Migrace a zařazování

Zařazování poskytuje kolekci metod pro přidělování nespravované paměti, kopírování nespravovaných bloků paměti a převod spravovaných na nespravované typy, stejně jako další různé metody používané při interakci s nespravovaným kódem.

Zařazování se projevuje prostřednictvím třídy .NET Marshal . Statické nebo sdílené v jazyce Visual Basic, metody definované ve třídě Marshal jsou nezbytné pro práci s nespravovanými daty. Pokročilí vývojáři vytvářející vlastní zařazovače, kteří potřebují vytvořit most mezi spravovanými a nespravovanými programovacími modely, obvykle používají většinu definovaných metod.

Posouzení migrace

Zařazování představuje některé složitější problémy spojené s migrací aplikací na 64bitovou verzi. Vzhledem k povaze toho, čeho se vývojář snaží dosáhnout pomocí zařazování, konkrétně přenos strukturovaných informací do spravovaného a nespravovaného kódu, z nebo do spravovaného a nespravovaného kódu, uvidíme, že poskytujeme informace, někdy i nízké úrovně, abychom systému pomohli.

Z hlediska rozložení existují dvě konkrétní deklarace, které může vývojář provést; tyto deklarace se obvykle provádějí pomocí atributů kódování.

LayoutKind.Sequential

Podívejme se na definici, která je součástí nápovědy k sadě .NET Framework SDK:

"Členy objektu jsou rozloženy postupně v pořadí, ve kterém se objeví při exportu do nespravované paměti. Členy jsou rozloženy podle balení zadaného v StructLayoutAttribute.Pack a mohou být nesouvislé."

Bylo nám řečeno, že rozložení je specifické pro pořadí, ve kterém je definováno. Pak stačí, abychom se ujistili, že spravované a nespravované deklarace jsou podobné. Ale také nám bylo řečeno, že balení je také důležitou složkou. V tomto okamžiku vás nepřekvapí, že bez explicitního zásahu vývojáře existuje výchozí hodnota balíčku. Jak už jste možná uhodli, výchozí hodnota balíčku není stejná mezi 32bitovými a 64bitovými systémy.

Tvrzení v definici týkající se nesouvislých členů odkazuje na skutečnost, že vzhledem k tomu, že existují výchozí velikosti balíčků, data, která jsou rozložena v paměti, nemusí být v bajtu 0, bajtu 1, bajtu2 atd. První člen bude na bajtu 0, ale druhý člen může být v bajtu 4. Systém toto výchozí zabalení provede tak, aby počítač získal přístup ke členům, aniž by musel řešit problémy s chybným zarovnáním.

Tady je oblast, kterou musíme věnovat zvýšenou pozornost balení a zároveň se pokusit nechat systém jednat ve svém upřednostňovaném režimu.

Následuje příklad struktury definované ve spravovaném kódu a odpovídající struktury definované v nespravovaném kódu. Měli byste si pečlivě uvědomit, jak tento příklad ukazuje nastavení hodnoty balíčku v obou prostředích.

[C#]
[StructLayout(LayoutKind.Sequential, Pack=1)]
public class XYZ {
      public byte arraysize = unchecked((byte)-1);
      [MarshalAs(UnmanagedType.ByValArray, SizeConst=52)]
      public int[] padding = new int[13];
};
[unmanaged c++]
#pragma pack(1)
typedef struct{
      BYTE arraysize;      // = (byte)-1;
      int      padding[13];
} XYZ;

LayoutKind.Explicit

Podívejme se na definici v nápovědě k rozhraní .NET FrameworkSDK:

"Přesná pozice každého člena objektu v nespravované paměti je explicitně řízena. Každý člen musí použít FieldOffsetAttribute k označení pozice tohoto pole v rámci typu.

Tady se nám říká, že vývojář bude poskytovat přesné posuny, které pomohou při zařazování informací. Proto je nezbytné, aby vývojář správně zadal informace v atributu FieldOffset .

Kde jsou tedy potenciální problémy? Mějte na paměti, že posuny polí jsou definovány s vědomím velikosti probíhajícího datového členu, je důležité si uvědomit, že ne všechny velikosti datových typů jsou stejné mezi 32bitovou a 64bitovou verzí. Konkrétně mají ukazatele délku 4 nebo 8 bajtů.

Teď máme případ, kdy možná budeme muset aktualizovat spravovaný zdrojový kód tak, aby cílil na konkrétní prostředí. Následující příklad ukazuje strukturu, která obsahuje ukazatel. I když jsme ukazatel změnili na IntPtr, při přechodu na 64bitovou verzi je stále rozdíl.

[C#]
[StructLayout(LayoutKind.Explicit)]
    internal struct FooValue {
        [FieldOffset(0)] public int dwType;
        [FieldOffset(4)] public IntPtr pType;
        [FieldOffset(8)] public int typeValue;
    }

Pro 64bitovou verzi musíme upravit posun pole pro poslední datový člen ve struktuře, protože ve skutečnosti začíná posunem 12 místo 8.

[C#]
[StructLayout(LayoutKind.Explicit)]
    internal struct FooValue {
        [FieldOffset(0)] public int dwType;
        [FieldOffset(4)] public IntPtr pType;
        [FieldOffset(12)] public int typeValue;
    }

Použití zařazování je realitou, když se vyžaduje složitá interoperabilita mezi spravovaným a nespravovaným kódem. Využití této výkonné funkce není indikátorem toho, že byste mohli 32bitovou aplikaci migrovat do 64bitového prostředí. Vzhledem ke složitostem spojeným s používáním zařazování se ale jedná o oblast, kde je potřeba věnovat pozornost podrobnostem.

Analýza kódu vám ukáže, jestli jsou pro každou z platforem potřeba samostatné binární soubory a jestli budete také muset upravit nespravovaný kód, abyste vyřešili problémy, jako je balení.

Migrace a serializace

Serializace je proces převodu stav objektu do tvaru, který může být zachována nebo přenosu. Doplňkovým serializace je deserializace, která převádí na objekt datového proudu. Tyto procesy dohromady, povolit, aby snadno ukládat a přenesených údaje.

Rozhraní .NET Framework obsahuje dvě technologie serializace:

  • Binární serializace zachová věrnost typu, což je užitečné pro zachování stav objektu mezi různé volání aplikace. Například můžete sdílet objekt mezi různými aplikacemi pomocí jeho serializace do schránky. Může serializovat objekt do datového proudu, na disk do paměti, v síti a tak dále. Vzdálené komunikace .NET používá serializaci k předávání objektů "podle hodnoty" z jednoho počítače nebo domény aplikace do jiné.
  • Serializace XML serializuje pouze veřejné vlastnosti a pole a nezachovává věrnost typu. To je užitečné, pokud chcete zadat nebo spotřebovat data bez omezení aplikace, která používá data. Protože kód XML je otevřený standard, je to atraktivní volba pro sdílení dat v rámci webu. Protokol SOAP je rovněž otevřený standard, díky čemuž je atraktivní výběru.

Posouzení migrace

Když přemýšlíme o serializaci, musíme mít na paměti, co se snažíme dosáhnout. Při migraci na 64bitovou verzi je třeba mít na paměti, zda máte v úmyslu sdílet serializované informace mezi různými platformami. Jinými slovy, bude 64bitová spravovaná aplikace číst (nebo deserializovat) informace uložené 32bitovou spravovanou aplikací.

Vaše odpověď vám pomůže zvýšit složitost vašeho řešení.

  • Můžete chtít napsat vlastní serializace rutiny pro zohlednění platforem.
  • Můžete chtít omezit sdílení informací a zároveň povolit, aby každá platforma mohla číst a zapisovat vlastní data.
  • Možná budete chtít znovu navštívit, co serializujete a provést změny, aby se zabránilo některým problémům.

Takže po tom všem, co jsou úvahy s ohledem na serializaci?

  • IntPtr má v závislosti na platformě délku 4 nebo 8 bajtů. Pokud serializujete informace, pak zapisujete data specifická pro platformu do výstupu. To znamená, že pokud se pokusíte tyto informace sdílet, může dojít k problémům.

Pokud uvažujete o naší diskuzi v předchozí části o zařazování a odsazení, můžete přijít na otázku nebo dvě ohledně toho, jak serializace řeší informace o balení. Pro binární serializaci .NET interně používá správný nezarovnaný přístup k serializačnímu streamu pomocí čtení na základě bajtů a správného zpracování dat.

Jak jsme právě viděli, použití serializace nebrání migraci na 64bitovou verzi. Pokud používáte serializaci XML musíte převést z a na nativní spravované typy během procesu serializace, izolovat vás od rozdílů mezi platformami. Použití binární serializace poskytuje bohatší řešení, ale vytváří situaci, kdy je třeba rozhodnout o tom, jak různé platformy sdílejí serializované informace.

Souhrn

Migrace na 64bitovou verzi se blíží a Microsoft pracuje na tom, aby přechod z 32bitových spravovaných aplikací na 64bitovou verzi byl co nejjednodušší.

Je ale nereálné předpokládat, že v 64bitovém prostředí stačí spustit 32bitový kód a bez pohledu na to, co migrujete.

Jak už bylo zmíněno dříve, pokud máte 100% bezpečný typ spravovaného kódu, pak opravdu stačí, když ho zkopírujete na 64bitovou platformu a úspěšně ho spustíte v 64bitovém CLR.

Je ale více než pravděpodobné, že spravovaná aplikace bude zapojená do některého z následujících nebo všech následujících akcí:

  • Vyvolání rozhraní API platformy prostřednictvím volání p/invoke
  • Vyvolání objektů COM
  • Použití nebezpečného kódu
  • Použití zařazování jako mechanismu pro sdílení informací
  • Použití serializace jako způsob zachování stavu

Bez ohledu na to, kterou z těchto věcí vaše aplikace dělá, bude důležité udělat domácí úkol a prozkoumat, co váš kód dělá a jaké máte závislosti. Jakmile uděláte tento domácí úkol, budete se muset podívat na své volby, abyste mohli udělat některou z následujících nebo všech následujících věcí:

  • Migrujte kód beze změn.
  • Proveďte změny kódu tak, aby správně zpracovával 64bitové ukazatele.
  • Při poskytování 64bitových verzí svých produktů spolupracujte s jinými dodavateli atd.
  • Proveďte změny logiky pro zpracování zařazování nebo serializace.

Může se stát, že se rozhodnete nemigrovat spravovaný kód na 64bitovou verzi. V takovém případě máte možnost označit sestavení tak, aby zavaděč Windows mohl při spuštění udělat správnou věc. Mějte na paměti, že podřízené závislosti mají přímý dopad na celou aplikaci.

Fxcop

Měli byste také vědět o dostupných nástrojích, které vám s migrací pomůžou.

Dnes má Microsoft nástroj s názvem FxCop, což je nástroj pro analýzu kódu, který kontroluje, zda sestavení kódu spravovaného rozhraní .NET splňují pokyny k návrhu rozhraní Microsoft .NET Framework. Používá analýzu grafu reflexe, analyzátoru MSIL a volání ke kontrole více než 200 vad sestavení v následujících oblastech: zásady vytváření názvů, návrh knihovny, lokalizace, zabezpečení a výkon. FxCop obsahuje grafické uživatelské rozhraní a verze nástroje pro příkazový řádek a také sadu SDK pro vytváření vlastních pravidel. Další informace najdete na webu FxCop . Společnost Microsoft vyvíjí další pravidla FxCop, která vám poskytnou informace, které vám pomůžou při migraci.

K dispozici jsou také funkce spravované knihovny, které vám za běhu pomůžou určit, v jakém prostředí běžíte.

  • System.IntPtr.Size – určuje, jestli používáte 32bitovou nebo 64bitovou verzi.
  • System.Reflection.Module.GetPEKind – k programovému dotazování .exe nebo .dll zjistit, jestli má běžet jenom na konkrétní platformě nebo pod wow64.

Neexistuje žádný konkrétní soubor postupů pro řešení všech výzev, na které byste mohli narazit. Cílem tohoto dokumentu white paper je zvýšit vaše povědomí o těchto výzvách a představit vám možné alternativy.