Aracılığıyla paylaş


32 bit Yönetilen Kodu 64 bit'e Geçirme

 

Microsoft Corporation

Mayıs 2005'de güncelleştirildi

Aşağıdakiler cihazlar için geçerlidir:
   Microsoft .NET
   Microsoft .NET Framework 2.0

Özet: 32 bit yönetilen uygulamaları 64 bit'e geçirmenin neleri içerdiğini, geçişi etkileyebilecek sorunları ve size yardımcı olabilecek araçları öğrenin. (17 yazdırılan sayfa)

İçindekiler

Giriş
32 bit Ortamda Yönetilen Kod
64 bit Ortam için CLR girin
Geçiş ve Platform Çağırma
Geçiş ve COM Birlikte Çalışabilirliği
Geçiş ve Güvenli Olmayan Kod
Geçiş ve Hazırlama
Geçiş ve Serileştirme
Özet

Giriş

Bu teknik incelemede şu konular ele alınmaktadır:

  • Yönetilen uygulamaların 32 bitten 64 bit'e geçirilmesine nelerin dahil olduğu
  • Geçişi etkileyebilecek sorunlar
  • Size yardımcı olacak araçlar

Bu bilgilerin açıklayıcı olması amaçlanmamıştır; bunun yerine, 64 bit'e geçiş işlemi sırasında sorunlara karşı duyarlı olan farklı alanları tanımanız amaçlanmıştır. Bu noktada izleyebileceğiniz ve kodunuzun 64 bit üzerinde çalışacağının kesin bir "yemek kitabı" yoktur. Bu teknik incelemede yer alan bilgiler, farklı sorunlar ve gözden geçirilmesi gerekenler hakkında sizi bilgilendirecektir.

Yakında göreceğiniz gibi, yönetilen derlemeniz %100 tür güvenli kod değilse, 64 bit'e geçişle ilgili sorunlarınızı belirlemek için uygulamanızı ve bağımlılıklarını gözden geçirmeniz gerekir. Sonraki bölümlerde okuyacağınız öğelerin çoğu programlama değişiklikleriyle ele alınabiliyor. Ayrıca, her ikisinde de çalışmasını istiyorsanız, hem 32 bit hem de 64 bit ortamlarda doğru şekilde çalışması için kodunuzu güncelleştirmek için zaman ayırmanız gerekir.

Microsoft .NET, bilgileri, kişileri, sistemleri ve cihazları bağlamak için kullanılan bir dizi yazılım teknolojisidir. 2002'deki 1.0 sürümünden bu yana kuruluşlar dağıtımını başardı. İster şirket içinde, ister bağımsız yazılım satıcıları (ISV) tarafından veya bir kombinasyonla olsun NET tabanlı çözümler. 32 bit ortamın sınırlarını zorlayan çeşitli .NET uygulamaları vardır. Bu zorluklar arasında daha gerçek adreslenebilir bellek gereksinimi ve artan kayan nokta performansı gereksinimi yer alır ancak bunlarla sınırlı değildir. x64 ve Itanium, kayan nokta işlemleri için x86'dan daha iyi performans sunar. Ancak, x64 veya Itanium'da elde ettiğiniz sonuçların x86'da elde ettiğiniz sonuçlardan farklı olması da mümkündür. 64 bit platform, bu sorunların giderilmesine yardımcı olmayı amaçlar.

.NET Framework sürüm 2.0'ın yayımlanmasıyla birlikte, Microsoft x64 ve Itanium 64 bit platformlarında çalışan yönetilen kod desteği içerir.

Yönetilen kod, .NET Ortak Dil Çalışma Zamanı'nın (CLR) aşağıdakiler dahil olmak üzere bir dizi temel hizmet sağlamasına izin vermek için yeterli bilgi sağlayan "koddur":

  • Meta veriler aracılığıyla kod ve verilerin kendi kendine açıklaması
  • Yığınla yürüyüş
  • Güvenlik
  • Atık toplama
  • Tam Zamanında derleme

Yönetilen koda ek olarak, geçiş sorunlarını incelerken anlaşılması önemli olan birkaç tanım daha vardır.

Yönetilen Veriler— yönetilen yığında ayrılan ve çöp toplama yoluyla toplanan veriler.

Derleme— CLR'nin bir uygulamanın içeriğini tam olarak anlamasını ve uygulama tarafından tanımlanan sürüm oluşturma ve bağımlılık kurallarını zorlamasını sağlayan dağıtım birimi.

Güvenli kod yazın: yalnızca yönetilen verileri kullanan ve onaylanamaz veri türleri veya desteklenmeyen veri türü dönüştürme/zorlama işlemleri (başka bir deyişle, ayrım yapılmayan birleşimler veya yapı/arabirim işaretçileri) içermeyen kod. C#, Visual Basic .NET ve /clr:safe ile derlenen Visual C++ kodu tür güvenli kodu oluşturur.

Güvenli Olmayan Kod: İşaretçileri bildirme ve işaretçiler üzerinde çalışma, işaretçiler ve integral türleri arasında dönüştürmeler gerçekleştirme ve değişkenlerin adresini alma gibi alt düzey işlemleri gerçekleştirmesine izin verilen kod. Bu tür işlemler, temel alınan işletim sistemiyle birlikte çalışabilir, belleğe eşlenmiş bir cihaza erişir veya zaman açısından kritik bir algoritma uygular. Yerel kod güvenli değildir.

32 bit Ortamda Yönetilen Kod

Yönetilen kodu 64 bit ortama geçirmeyle ilgili karmaşıklıkları anlamak için, yönetilen kodun 32 bit bir ortamda nasıl yürütülür gözden geçirelim.

Yürütülmek üzere yönetilen veya yönetilmeyen bir uygulama seçildiğinde, Windows yükleyicisi çağrılır ve uygulamanın nasıl yüklenip yürütüleceklerine karar vermekle sorumludur. Bu işlemin bir bölümü, CLR'nin gerekli olup olmadığını belirlemek için yürütülebilir dosyanın taşınabilir yürütme (PE) üst bilgisinin içine göz atmayı içerir. Tahmin etmiş olabileceğiniz gibi PE'de yönetilen kodu gösteren bayraklar vardır. Bu durumda, Windows yükleyici yönetilen uygulamayı yükleyip yürütmekle sorumlu olan CLR'yi başlatır. (Yürütülecek CLR sürümünü belirleme, AppDomain 'korumalı alanı' ayarlama gibi birçok adım söz konusu olduğundan, bu işlemin basitleştirilmiş bir açıklamasıdır.)

Birlikte çalışabilirlik

Yönetilen uygulama çalışırken, CLR birlikte çalışabilirlik özellikleri aracılığıyla yerel API'ler (Win32 API dahil) ve COM nesneleriyle etkileşimde bulunabilir (uygun güvenlik izinlerini varsayarak). Yerel platform API'sini çağırma, COM isteğinde bulunma veya yapı hazırlama gibi işlemler, 32 bitlik bir ortamda tamamen çalıştırıldığında geliştirici, veri türü boyutlarını ve veri hizalamasını düşünmek zorunda kalmaktan yalıtılır.

64 bit'e geçişi göz önünde bulundurarak uygulamanızın hangi bağımlılıklara sahip olduğunu araştırmak çok önemlidir.

64 bit Ortam için CLR girin

Yönetilen kodun 32 bit ortamla tutarlı 64 bit ortamda yürütülmesi için .NET ekibi Itanium ve x64 64 bit sistemleri için Ortak Dil Çalışma Zamanı'nı (CLR) geliştirdi. CLR,.NET dillerinden herhangi birinde yazılan kodun 32 bit ortamında olduğu gibi birlikte çalışabilmesini sağlamak için Ortak Dil Altyapısı (CLI) ve Ortak Dil Türü Sistemi kurallarına kesinlikle uymak zorunda kaldı. Ayrıca, 64 bit ortam için de taşıması ve/veya geliştirmesi gereken diğer parçaların listesi aşağıdadır:

  • Temel sınıf kitaplıkları (System.*)
  • Tam Zamanında derleyici
  • Hata ayıklama desteği
  • .NET Framework SDK'sı

64 bit yönetilen kod desteği

.NET Framework sürüm 2.0, çalışan Itanium ve x64 64 bit işlemcileri destekler:

  • Windows Server 2003 SP1
  • Gelecekteki Windows 64 bit istemci sürümleri

(Windows 2000'de .NET Framework sürüm 2.0'ı yükleyemezsiniz. 1.0 ve 1.1 .NET Framework sürümleri kullanılarak üretilen çıkış dosyaları, 64 bit işletim sisteminde WOW64 altında çalıştırılır.)

.NET Framework sürüm 2.0'ı 64 bit platforma yüklerken, yönetilen kodunuzu 64 bit modunda yürütmek için gerekli tüm altyapıyı yüklemekle kalmaz, yönetilen kodunuzun Windows üzerinde Windows alt sisteminde veya WoW64 (32 bit modunda) çalıştırılması için gerekli altyapıyı da yüklersiniz.

Basit bir 64 bit geçiş

%100 tür güvenli kod olan bir .NET uygulaması düşünün. Bu senaryoda, 32 bit makinenizde çalıştırdığınız .NET yürütülebilir dosyanızı alıp 64 bit sisteme taşımak ve başarıyla çalıştırılmasını sağlamak mümkündür. Bu neden işe yaramaktadır? Derleme %100 tür güvenli olduğundan yerel kod veya COM nesnelerine bağımlılık olmadığını ve uygulamanın tamamen CLR'nin denetimi altında çalıştığı anlamına gelen 'güvenli olmayan' bir kod olmadığını biliyoruz. CLR, Tam zamanında (JIT) derleme sonucu oluşturulan ikili kodun 32 bit ile 64 bit arasında farklı olacağını garanti ederken, yürütülen kodun her ikisinin de aynı olacağını garanti eder. (Windows 2000'de .NET Framework sürüm 2.0'ı yükleyemezsiniz. 1.0 ve 1.1 .NET Framework sürümleri kullanılarak üretilen çıkış dosyaları, 64 bit işletim sisteminde WOW64 altında çalıştırılır.)

Gerçekte, önceki senaryo yönetilen uygulamayı yükleme açısından biraz daha karmaşıktır. Önceki bölümde açıklandığı gibi, Windows yükleyicisi uygulamayı nasıl yükleyip yürüteceklerine karar vermekle sorumludur. Ancak, 32 bit ortamdan farklı olarak, 64 bit Windows platformunda çalışmak, uygulamanın yerel 64 bit modunda veya WoW64'te yürütülebileceği iki (2) ortam olduğu anlamına gelir.

Windows yükleyicisi artık PE üst bilgisinde bulduklarına bağlı olarak karar vermek zorunda. Tahmin edebileceğiniz gibi, yönetilen kodda bu işleme yardımcı olan ayarlanabilir bayraklar vardır. (Pe'de ayarları görüntülemek için bkz. corflags.exe.) Aşağıdaki liste, PE'de bulunan ve karar alma sürecine yardımcı olan bilgileri temsil eder.

  • 64 bit— geliştiricinin derlemeyi özel olarak 64 bitlik bir işlemi hedefleyerek oluşturduğunu belirtir.
  • 32 bit— geliştiricinin derlemeyi özellikle 32 bit işlemi hedefleyen bir derleme oluşturduğunu belirtir. Bu örnekte derleme WoW64'te çalıştırılır.
  • Agnostic—geliştiricinin visual studio 2005 derlemesini "Whidbey" kod adıyla oluşturduğunu belirtir. veya sonraki araçlar ve derlemenin 64 bit veya 32 bit modunda çalışabileceği. Bu durumda, 64 bit Windows yükleyicisi derlemeyi 64 bit olarak çalıştırır.
  • Eski— derlemeyi oluşturan araçların "pre-Whidbey" olduğunu belirtir. Bu durumda derleme WoW64'te çalıştırılır.

Not PE'de, Derlemenin belirli bir mimari için hedeflenip hedeflenmediğini Windows yükleyicisine bildiren bilgiler de vardır. Bu ek bilgiler, belirli bir mimari için hedeflenen derlemelerin farklı bir mimariye yüklenmemesini sağlar.

C#, Visual Basic .NET ve C++ Whidbey derleyicileri PE üst bilgisinde uygun bayrakları ayarlamanıza olanak tanır. Örneğin, C# ve THIRD bir /platform:{anycpu, x86, Itanium, x64} derleyici seçeneğine sahiptir.

Not Derleme derlendikten sonra derlemenin PE üst bilgisindeki bayrakları değiştirmek teknik olarak mümkün olsa da, Microsoft bunu yapmanızı önermez.

Bu bayrakların yönetilen bir derlemede nasıl ayarlandığını merak ediyorsanız, .NET Framework SDK'sında sağlanan ILDASM yardımcı programını çalıştırabilirsiniz. Aşağıdaki çizimde "eski" bir uygulama gösterilmektedir.

Bir derlemeyi Win64 olarak işaretleyen bir geliştiricinin, uygulamanın tüm bağımlılıklarının 64 bit modunda yürütüleceğini belirlediğini unutmayın. 64 bitlik bir işlem, işlemde 32 bit bileşeni kullanamaz (ve 32 bit işlem işlemdeki 64 bit bileşeni yükleyemez). Sistemin derlemeyi 64 bitlik bir işleme yükleyebilmesinin otomatik olarak doğru yürütüleceği anlamına gelmez.

Bu nedenle, %100 tür güvenli yönetilen koddan oluşan bir uygulamanın 64 bitlik bir platforma kopyalanıp (veya xcopy ile dağıtılabilir) ve JIT ile 64 bit modunda .NET ile başarıyla çalıştırılabildiğini biliyoruz.

Ancak genellikle ideal olmayan ve bizi geçişle ilgili sorunların farkındalığını artırmak için bu makalenin ana odağına getiren durumlar görürüz.

%100 tür güvenli olmayan ve .NET altında 64 bit'te başarıyla çalıştırılabilen bir uygulamanız olabilir. Aşağıdaki bölümlerde ele alınan olası sorunları göz önünde bulundurarak uygulamanıza dikkatle bakmanız ve 64 bit'te başarılı bir şekilde çalıştırılıp çalıştırılamayacağınızı saptamanız önemlidir.

Geçiş ve Platform Çağırma

.NET'in platform çağırma (veya p/invoke) özelliklerini kullanmak, yönetilmeyen veya yerel koda çağrı yapan yönetilen kodu ifade eder. Tipik bir senaryoda bu yerel kod, sistemin (Windows API'si vb.), uygulamanızın bir parçası veya üçüncü taraf kitaplığının bir parçası olan dinamik bağlantı kitaplığıdır (DLL).

Yönetilmeyen kodun kullanılması açıkça 64 bit'e geçişte sorun olacağı anlamına gelmez; bunun yerine, ek araştırma gerektiğinin bir göstergesi olarak düşünülmelidir.

Windows'da veri türleri

Her uygulamanın ve her işletim sisteminin bir soyut veri modeli vardır. Birçok uygulama bu veri modelini açıkça kullanıma sunmaz, ancak model uygulama kodunun yazıldığı yolda yol gösterir. 32 bit programlama modelinde (ILP32 modeli olarak bilinir), tamsayı, uzun ve işaretçi veri türleri 32 bit uzunluğundadır. Geliştiricilerin çoğu bu modeli farkında olmadan kullandı.

64 bit Microsoft Windows'ta, veri türü boyutlarında eşlik varsayımı geçersizdir. Çoğu uygulamanın artan boyuta ihtiyacı olmadığından, tüm veri türlerinin 64 bit uzunluğunda olması yer kaybına neden olur. Ancak, uygulamaların 64 bit verilere yönelik işaretçilere ve seçilen durumlarda 64 bit veri türlerine sahip olmaları gerekir. Bu önemli noktalar, Windows ekibinin LLP64 (veya P64) adlı soyut bir veri modeli seçmesine neden oldu. LLP64 veri modelinde yalnızca işaretçiler 64 bit'e genişler; diğer tüm temel veri türleri (tamsayı ve uzun) 32 bit uzunluğunda kalır.

64 bit platformlar için .NET CLR, aynı LLP64 soyut veri modelini kullanır. .NET'te, 'işaretçi' bilgilerini tutmak için özel olarak belirlenmiş, yaygın olarak bilinmeyen bir tamsayı veri türü vardır: Boyutu üzerinde çalıştığı platforma (örneğin, 32 bit veya 64 bit) bağımlı olan IntPtr . Aşağıdaki kod parçacığını göz önünde bulundurun:

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

32 bit platformda çalıştırıldığında konsolda aşağıdaki çıkışı alırsınız:

SizeOf IntPtr is: 4

64 bit platformda konsolda aşağıdaki çıkışı alırsınız:

SizeOf IntPtr is: 8

Not Çalışma zamanında 64 bitlik bir ortamda çalışıp çalışmadığınızdan emin olmak istiyorsanız, bu belirlemeyi yapmak için bir yol olarak IntPtr.Size kullanabilirsiniz.

Geçiş fikirleri

p/invoke kullanan yönetilen uygulamaları geçirirken aşağıdaki öğeleri göz önünde bulundurun:

  • DLL'nin 64 bit sürümünün kullanılabilirliği
  • Veri türlerinin kullanımı

Kullanılabilirlik

Saptanması gereken ilk şeylerden biri, uygulamanızın bağımlılığı olan yönetilmeyen kodun 64 bit için kullanılabilir olup olmadığıdır.

Bu kod şirket içinde geliştirilmişse başarı beceriniz artar. Elbette, yine de yönetilmeyen kodu test, kalite güvencesi vb. için uygun kaynaklarla birlikte 64 bit'e taşımaya yönelik kaynaklar ayırmanız gerekir. (Bu teknik inceleme geliştirme süreçleri hakkında önerilerde bulunmaz; bunun yerine kaynakların bağlantı noktası koduna görevlere ayrılması gerekebileceğini belirtmeye çalışır.)

Bu kod bir üçüncü tarafa aitse, bu üçüncü tarafın kodu 64 bit için kullanılabilir durumda olup olmadığını ve üçüncü tarafın kullanılabilir hale getirmek isteyip istemediğinizi araştırmanız gerekir.

Daha yüksek risk sorunu, üçüncü tarafın artık bu kod için destek sağlamaması veya üçüncü tarafın işi yapmaya istekli olmaması durumunda ortaya çıkar. Bu gibi durumlarda benzer işlevlere sahip kullanılabilir kitaplıklar, üçüncü tarafın müşterinin bağlantı noktasını kendisi yapmasına izin verip vermeyeceği gibi konularda ek araştırma yapılması gerekir.

Bağımlı kodun 64 bit sürümünde ek geliştirme çalışması anlamına gelebilecek arabirim imzalarının değiştirilmiş olabileceğini ve uygulamanın 32 bit ile 64 bit sürümleri arasındaki farkları çözebileceğini unutmayın.

Veri türleri

p/invoke kullanılması, .NET'te geliştirilen kodun yönetilen kodun hedeflediğini yöntemin prototipini bildirmesini gerektirir. Aşağıdaki C bildirimi göz önünde bulundurulduğunda:

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

Prototip oluşturulan yöntem örnekleri aşağıda gösterilmiştir:

[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();

Şimdi 64 bit geçiş sorunlarına göz atarak şu örnekleri gözden geçirelim:

İlk örnek, iki (2) 32 bit tamsayıdan geçen DoWork yöntemini çağırır ve 32 bitlik bir tamsayı döndürülmesini bekleriz. 64 bit platformda çalışıyor olsak da tamsayı hala 32 bittir. Bu örnekte geçiş çalışmalarımızı engellemesi gereken hiçbir şey yoktur.

İkinci örnek, kodda 64 bit'te başarılı bir şekilde çalışması için bazı değişiklikler yapılmasını gerektirir. Burada yaptığımız şey GetData yöntemini çağırmak ve bir tamsayı döndürülmeyi beklediğimizi ancak işlevin aslında bir int işaretçisi döndürdüğü durumu bildiriyor. Burada sorunumuz yatıyor: Tamsayıların 32 bit olduğunu ama 64 bit işaretçilerin 8 bayt olduğunu unutmayın. Sonuç olarak, 32 bit dünyada bir işaretçi ve tamsayı aynı uzunlukta, 4 bayt olduğu varsayılarak oldukça fazla kod yazılmıştır. 64 bit dünyada bu artık doğru değildir.

Bu son durumda, yöntem bildirimi int yerine bir IntPtr kullanacak şekilde değiştirilerek sorun çözülebilir.

public unsafe static extern IntPtr GetData();

Bu değişikliğin yapılması hem 32 bit hem de 64 bit ortamlarda çalışır. IntPtr'nin platforma özgü olduğunu unutmayın.

Yönetilen uygulamanızda p/invoke kullanmak, 64 bit platforma geçişin mümkün olmadığı anlamına gelmez. Sorun olacağı anlamına da gelmez. Bunun anlamı, yönetilen uygulamanızın sahip olduğu yönetilmeyen kod üzerindeki bağımlılıkları gözden geçirmeniz ve herhangi bir sorun olup olmadığını belirlemeniz gerektiğidir.

Geçiş ve COM Birlikte Çalışabilirliği

COM birlikte çalışabilirliği, .NET platformunun varsayılan bir özelliğidir. Platform çağrısıyla ilgili önceki tartışmada olduğu gibi, COM birlikte çalışabilirliğini kullanmak, yönetilen kodun yönetilmeyen koda çağrı yaptığı anlamına gelir. Ancak, platform çağrısından farklı olarak, COM birlikte çalışabilirliği, yönetilmeyen kodun bir COM bileşeniymiş gibi yönetilen kodu çağırabilmesi anlamına da gelir.

Bir kez daha, yönetilmeyen COM kodunun kullanılması, 64 bit'e geçişte sorun olacağı anlamına gelmez; bunun yerine, ek araştırma gerektiğinin bir göstergesi olarak düşünülmelidir.

Geçiş fikirleri

.NET Framework sürüm 2.0'ın yayımlanmasıyla birlikte mimariler arası birlikte çalışabilirliği desteklemediğini anlamak önemlidir. Daha kısa olmak gerekirse, aynı işlemde 32 bit ile 64 bit arasında COM birlikte çalışabilirliğini kullanamazsınız. Ancak, işlem dışı bir COM sunucunuz varsa 32 bit ile 64 bit arasında COM birlikte çalışabilirliğini kullanabilirsiniz. İşlem dışı bir COM sunucusu kullanamıyorsanız, programınızın 32 bit COM nesnesiyle birlikte çalışabilmesi için WoW64'te çalışmasını sağlamak için yönetilen derlemenizi Win64 veya Agnostic yerine Win32 olarak işaretlemeniz gerekir.

Aşağıda, yönetilen kodun 64 bitlik bir ortamda COM çağrıları yaptığı COM birlikte çalışabilirliğini kullanmak için dikkat edilmesi gereken farklı noktaların bir tartışması verilmiştir. Daha ayrıntılı belirtmek gerekirse:

  • DLL'nin 64 bit sürümünün kullanılabilirliği
  • Veri türlerinin kullanımı
  • Tür kitaplıkları

Kullanılabilirlik

P/invoke bölümündeki bağımlı kodun 64 bit sürümünün kullanılabilirliğiyle ilgili tartışma da bu bölümle ilgilidir.

Veri türleri

P/invoke bölümündeki bağımlı kodun 64 bit sürümünün veri türleriyle ilgili tartışma da bu bölümle ilgilidir.

Tür kitaplıkları

Derlemelerin aksine, tür kitaplıkları 'nötr' olarak işaretlenemez; Win32 veya Win64 olarak işaretlenmelidir. Ayrıca, COM'un çalıştırılacağı her ortam için tür kitaplığının kaydedilmesi gerekir. Tür kitaplığından 32 bit veya 64 bit derleme oluşturmak için tlbimp.exe kullanın.

Yönetilen uygulamanızda COM birlikte çalışabilirliğini kullanmak, 64 bit platforma geçişin mümkün olmadığı anlamına gelmez. Sorun olacağı anlamına da gelmez. Bunun anlamı, yönetilen uygulamanızın sahip olduğu bağımlılıkları gözden geçirmeniz ve herhangi bir sorun olup olmadığını belirlemeniz gerektiğidir.

Geçiş ve Güvenli Olmayan Kod

Çekirdek C# dili, işaretçileri veri türü olarak atlarken C ve C++ dilinden özellikle farklıdır. Bunun yerine, C# başvurular ve atık toplayıcı tarafından yönetilen nesneler oluşturma olanağı sağlar. Çekirdek C# dilinde başlatılmamış bir değişkene, "sarkan" işaretçiye veya bir diziyi sınırlarının ötesinde dizine alan bir ifadeye sahip olmak mümkün değildir. C ve C++ programlarını düzenli olarak rahatsız eden hataların tüm kategorileri böylece ortadan kalkar.

C veya C++ dilindeki her işaretçi türü yapısı C# dilinde karşılık gelen bir başvuru türüne sahip olsa da, işaretçi türlerine erişimin bir zorunluluk haline geldiği durumlar vardır. Örneğin, temel işletim sistemiyle birlikte çalışma, belleğe eşlenmiş bir cihaza erişme veya zaman açısından kritik bir algoritma uygulama, işaretçilere erişim olmadan mümkün veya pratik olmayabilir. C# bu ihtiyacı gidermek için güvenli olmayan kod yazma olanağı sağlar.

Güvenli olmayan kodda, işaretçileri bildirmek ve üzerinde çalışmak, işaretçiler ve integral türleri arasında dönüştürmeler gerçekleştirmek, değişkenlerin adresini almak vb. mümkündür. Bir anlamda, güvenli olmayan kod yazmak bir C# programı içinde C kodu yazmaya çok benzer.

Güvenli olmayan kod aslında hem geliştiriciler hem de kullanıcılar açısından "güvenli" bir özelliktir. Güvenli olmayan kod, değiştirici güvenli değil olarak açıkça işaretlenmelidir, böylece geliştiriciler güvenli olmayan özellikleri yanlışlıkla kullanamaz.

Geçiş fikirleri

Güvenli olmayan kodla ilgili olası sorunları tartışmak için aşağıdaki örneği inceleyelim. Yönetilen kodumuz yönetilmeyen DLL'ye çağrılar yapar. Özellikle, 100 öğe döndüren GetDataBuffer adlı bir yöntem vardır (bu örnekte sabit sayıda öğe döndürüyoruz). Bu öğelerin her biri bir tamsayı ve bir işaretçiden oluşur. Aşağıdaki örnek kod, döndürülen bu verileri işlemeden sorumlu güvenli olmayan işlevi gösteren yönetilen koddan bir alıntıdır.

[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;
}

Not Bu özel örnek, güvenli olmayan kod kullanılmadan gerçekleştirilebilirdi. Daha açık belirtmek gerekirse, kullanılabilecek hazırlama gibi başka teknikler de vardır. Ancak bu amaçla güvenli olmayan kod kullanıyoruz.

UnsafeFn, 100 öğe arasında döngü oluşturur ve tamsayı verilerini toplar. Bir veri arabelleği üzerinde ilerlerken kodun hem tamsayı hem de işaretçinin üzerine geçmesi gerekir. 32 bitlik ortamda bu kod düzgün çalışır. Ancak, daha önce de belirttiğimiz gibi, işaretçiler 64 bit ortamda 8 bayttır ve bu nedenle kod kesimi (aşağıda gösterilmiştir) düzgün çalışmaz; örneğin, bir işaretçiyi tamsayıya eşdeğer olarak ele alan ortak bir programlama tekniğinden yararlanıyor.

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

Bu kodun hem 32 bit hem de 64 bit ortamında çalışması için kodun aşağıdakine değiştirilmesi gerekir.

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

Az önce gördüğümüz gibi, güvenli olmayan kod kullanmanın gerekli olduğu örnekler vardır. Çoğu durumda, yönetilen kodun başka bir arabirime bağımlılığının bir sonucu olarak gereklidir. Güvenli olmayan kodun mevcut olma nedenlerinden bağımsız olarak, geçiş işleminin bir parçası olarak gözden geçirilmesi gerekir.

Yukarıda kullandığımız örnek nispeten basittir ve programın 64 bit olarak çalışmasını sağlama düzeltmesi oldukça basittir. Daha karmaşık olan pek çok güvenli olmayan kod örneği olduğu açıktır. Bazıları ayrıntılı inceleme ve belki de geri adım atıp yönetilen kodun kullandığı yaklaşımı yeniden düşünmek gerektirir.

Zaten okuduğunuzu yinelemek için; yönetilen uygulamanızda güvenli olmayan kod kullanmak, 64 bit platforma geçişin mümkün olmadığı anlamına gelmez. Sorun olacağı anlamına da gelmez. Bunun anlamı, yönetilen uygulamanızın sahip olduğu tüm güvenli olmayan kodu gözden geçirmeniz ve herhangi bir sorun olup olmadığını belirlemeniz gerektiğidir.

Geçiş ve Hazırlama

Hazırlama, yönetilmeyen bellek ayırma, yönetilmeyen bellek bloklarını kopyalama ve yönetilmeyen türlere dönüştürme yöntemlerinin yanı sıra yönetilmeyen kodla etkileşim kurarken kullanılan diğer çeşitli yöntemlerin bir koleksiyonunu sağlar.

Hazırlama .NET Marshal sınıfı aracılığıyla gösterilir. Visual Basic'te statik veya paylaşılan, Marshal sınıfında tanımlanan yöntemler yönetilmeyen verilerle çalışmak için gereklidir. Yönetilen ve yönetilmeyen programlama modelleri arasında köprü sağlaması gereken özel hazırlayıcılar oluşturan gelişmiş geliştiriciler genellikle tanımlanan yöntemlerin çoğunu kullanır.

Geçiş fikirleri

Hazırlama, uygulamaların 64 bit'e geçirilmesiyle ilişkili daha karmaşık zorluklardan bazılarını oluşturur. Geliştiricinin sıralama ile gerçekleştirmeye çalıştığı, yapılandırılmış bilgileri yönetilen ve yönetilmeyen koddan, koda veya koda aktarmayı denediğini göz önünde bulundurursak, sisteme yardımcı olmak için bazen düşük düzeyli bilgiler sağladığımızı görürüz.

Düzen açısından geliştirici tarafından yapılabilecek iki özel bildirim vardır; bu bildirimler genellikle kodlama özniteliklerinin kullanımıyla yapılır.

LayoutKind.Sequential

Şimdi .NET Framework SDK Yardımı'nda sağlanan tanımı gözden geçirelim:

"Nesnenin üyeleri, yönetilmeyen belleğe aktarıldığında göründükleri sırayla sırayla düzenlenir. Üyeler StructLayoutAttribute.Pack içinde belirtilen ambalaja göre düzenlenir ve bitişik olmayabilir."

Düzenin tanımlandığı sıraya özgü olduğu söylenir. Ardından, tek yapmamız gereken yönetilen ve yönetilmeyen bildirimlerin benzer olduğundan emin olmaktır. Ama paketlemenin de kritik bir bileşen olduğu söyleniyor. Bu noktada geliştiricinin açık müdahalesi olmadan varsayılan bir paket değeri olduğunu öğrenmek sizi şaşırtmaz. Önceden tahmin etmiş olabileceğiniz gibi, varsayılan paket değeri 32 bit ve 64 bit sistemler arasında aynı değildir.

Bitişik olmayan üyelerle ilgili tanımdaki deyim, varsayılan paket boyutları olduğundan, bellekte yerleştirilmiş verilerin bayt 0, bayt 1, bayt2 vb. olmaması gerçeğine başvurur. Bunun yerine, ilk üye bayt 0 olur, ancak ikinci üye 4 baytta olabilir. Sistem, makinenin yanlış hizalama sorunlarıyla uğraşmadan üyelere erişmesine izin vermek için bu varsayılan paketlemeyi yapar.

İşte paketlemeye dikkat etmemiz gereken bir alan ve aynı zamanda sistemin tercih edilen modda hareket etmesine izin vermeye çalışın.

Yönetilen kodda tanımlanan bir yapı örneği ve yönetilmeyen kodda tanımlanan ilgili yapı aşağıda verilmiştir. Bu örneğin her iki ortamda da paket değerini ayarlamayı nasıl gösterdiğine dikkat etmelisiniz.

[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

Şimdi .NET FrameworkSDK Yardımı'nda sağlanan tanımı gözden geçirelim:

"Bir nesnenin her üyesinin yönetilmeyen bellekteki tam konumu açıkça denetlenir. Her üye, alanın türü içindeki konumunu belirtmek için FieldOffsetAttribute kullanmalıdır."

Burada, geliştiricinin bilgilerin sıralanmasında yardımcı olmak için tam uzaklıklar sağlayacakları söylenmektedir. Bu nedenle, geliştiricinin FieldOffset özniteliğindeki bilgileri doğru şekilde belirtmesi önemlidir.

Peki, olası sorunlar nerede? Alan uzaklıklarının, devam eden veri üyesi boyutunun boyutu bilinerek tanımlandığına dikkat edin, tüm veri türü boyutlarının 32 bit ile 64 bit arasında eşit olmadığını unutmayın. Özellikle, işaretçiler 4 veya 8 bayt uzunluğundadır.

Artık belirli ortamları hedeflemek için yönetilen kaynak kodumuzu güncelleştirmemiz gerekebilecek bir servis talebimiz var. Aşağıdaki örnekte işaretçi içeren bir yapı gösterilmektedir. İşaretçiyi IntPtr yapmış olsak da, 64 bit'e geçerken hala bir fark vardır.

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

64 bit için, 8 yerine 12 uzaklığında başladığı için yapıdaki son veri üyesi için alan uzaklığını ayarlamamız gerekir.

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

Sıralamanın kullanımı, yönetilen ve yönetilmeyen kod arasında karmaşık birlikte çalışabilirlik gerektiğinde bir gerçektir. Bu güçlü özelliği kullanmak, 32 bit uygulamanızı 64 bit ortama geçirebileceğinizin göstergesi değildir. Ancak, hazırlamayı kullanmayla ilişkili karmaşıklıklar nedeniyle, bu, ayrıntılara dikkatli bir şekilde dikkat edilmesi gereken bir alandır.

Kodunuzun analizi, platformların her biri için ayrı ikili dosyaların gerekli olup olmadığını ve paketleme gibi sorunları çözmek için yönetilmeyen kodunuzda da değişiklik yapmanız gerekip gerekmeyeceğini gösterir.

Geçiş ve Serileştirme

Serileştirme, bir nesnenin durumunu kalıcı veya taşınabilen bir forma dönüştürme işlemidir. Serileştirmenin tamamlayıcısı, bir akışı nesneye dönüştüren seri durumdan çıkarmadır. Bu işlemler birlikte verilerin kolayca depolanmasına ve aktarılmasına olanak sağlar.

.NET Framework iki serileştirme teknolojisi vardır:

  • Bir uygulamanın farklı çağrılarını arasında bir nesne durumunu korumak için kullanışlıdır türü uygunluk, ikili serileştirme korur. Örneğin, bir nesne panoya serileştirmek tarafından farklı uygulamalar arasında paylaşabilirsiniz. Bir nesneyi akışa, diske, belleğe, ağ üzerinden vb. seri hale getirebilirsiniz. .NET Uzaktan İletişimi, nesneleri bir bilgisayardan veya uygulama etki alanından diğerine "değere göre" geçirmek için serileştirme kullanır.
  • XML serileştirme yalnızca ortak özellikler ve alanları serileştirir ve türü kalitesini korumak değil. Bu, verileri kullanan uygulamayı kısıtlamadan veri sağlamak veya kullanmak istediğinizde yararlıdır. XML açık bir standart olduğundan, Web'de veri paylaşımı için cazip bir seçimdir. SOAP de benzer şekilde açık bir standarttır ve bu da onu cazip bir seçim yapar.

Geçiş fikirleri

Serileştirmeyi düşünürken neyi başarmaya çalıştığımızı unutmamalıyız. 64 bit'e geçiş yaptığınızda aklınızda bulundurmanız gereken bir soru, serileştirilmiş bilgileri farklı platformlar arasında paylaşmayı isteyip istemediğinizdir. Başka bir deyişle, 64 bit yönetilen uygulama 32 bit yönetilen uygulama tarafından depolanan bilgileri okur (veya seri durumdan çıkaracaktır).

Yanıtınız çözümünüzün karmaşıklığının artmasına yardımcı olur.

  • Platformları hesaba eklemek için kendi serileştirme yordamlarınızı yazmak isteyebilirsiniz.
  • Her platformun kendi verilerini okumasına ve yazmasına izin verirken bilgi paylaşımını kısıtlamak isteyebilirsiniz.
  • Bazı sorunları önlemek için serileştirdiğiniz şeyi yeniden ziyaret etmek ve değişiklikler yapmak isteyebilirsiniz.

Peki tüm bu olanlardan sonra serileştirme ile ilgili dikkat edilmesi gerekenler nelerdir?

  • IntPtr, platforma bağlı olarak 4 veya 8 bayt uzunluğundadır. Bilgileri seri hale getirdiğinizde çıkışa platforma özgü veriler yazarsınız. Bu, bu bilgileri paylaşmayı denerseniz sorunlarla karşılaşabileceğiniz ve karşılaşacağınız anlamına gelir.

Önceki bölümde hazırlama ve uzaklıklarla ilgili tartışmamızı dikkate alırsanız, serileştirmenin paketleme bilgilerini nasıl ele alabileceği hakkında bir veya iki soru sorabilirsiniz. İkili serileştirme için .NET, bayt tabanlı okumaları kullanarak ve verileri doğru şekilde işleyerek seri hale getirme akışına doğru hizalanmamış erişimi dahili olarak kullanır.

Az önce gördüğümüz gibi serileştirme kullanımı 64 bit'e geçişi engellemez. XML serileştirmesi kullanıyorsanız, serileştirme işlemi sırasında yerel yönetilen türlerden ve yerel yönetilen türlere dönüştürmeniz ve platformlar arasındaki farklardan sizi yalıtmanız gerekir. İkili serileştirme kullanmak size daha zengin bir çözüm sağlar, ancak farklı platformların serileştirilmiş bilgileri nasıl paylaştığıyla ilgili kararların alınması gereken durumu oluşturur.

Özet

64 bit'e geçiş geliyor ve Microsoft, 32 bit yönetilen uygulamalardan 64 bit'e geçişi olabildiğince basit hale getirmek için çalışıyor.

Ancak, birinin 64 bitlik bir ortamda yalnızca 32 bit kod çalıştırabileceğini ve geçiş yaptığınız şeye bakmadan çalıştırılmasını sağlamak gerçekçi değildir.

Daha önce belirtildiği gibi, %100 tür güvenli yönetilen kodunuz varsa, bunu 64 bit platforma kopyalayıp 64 bit CLR altında başarıyla çalıştırabilirsiniz.

Ancak yönetilen uygulama büyük olasılıkla aşağıdakilerden biriyle veya tümüyle ilgilenecektir:

  • p/invoke aracılığıyla platform API'lerini çağırma
  • COM nesnelerini çağırma
  • Güvenli olmayan kodu kullanma
  • Bilgileri paylaşmak için bir mekanizma olarak hazırlamayı kullanma
  • Durumu kalıcı hale getirmenin bir yolu olarak serileştirme kullanma

Uygulamanızın bu işlemlerden hangisini yaptığına bakılmaksızın, ev ödevinizi yapmak ve kodunuzun ne yaptığını ve hangi bağımlılıklara sahip olduğunuzu araştırmak önemlidir. Bu ev ödevini yaptıktan sonra, aşağıdakilerden birini veya tümünü yapmak için seçimlerinize bakmanız gerekir:

  • Kodu değişiklik olmadan geçirin.
  • 64 bit işaretçileri doğru şekilde işlemek için kodunuzda değişiklikler yapın.
  • Ürünlerinin 64 bit sürümlerini sağlamak için diğer satıcılarla vb. çalışın.
  • Sıralamayı ve/veya serileştirmeyi işlemek için mantığınızda değişiklikler yapın.

Yönetilen kodu 64 bit'e geçirmemeye karar vermenizi gerektiren durumlar olabilir. Bu durumda, Windows yükleyicisinin başlangıçta doğru şeyi yapabilmesi için derlemelerinizi işaretleme seçeneğiniz vardır. Aşağı akış bağımlılıklarının uygulamanın genelini doğrudan etkilediğini unutmayın.

Fxcop

Ayrıca geçişinizde size yardımcı olacak araçlardan da haberdar olmanız gerekir.

Bugün Microsoft, .NET tarafından yönetilen kod derlemelerini Microsoft .NET Framework Tasarım Yönergeleri'ne uygunluk açısından denetleyen bir kod analizi aracı olan FxCop adlı bir ara çubuğuna sahiptir. Derlemeleri şu alanlarda 200'den fazla hata olup olmadığını incelemek için yansıma, MSIL ayrıştırma ve çağrı grafı analizini kullanır: adlandırma kuralları, kitaplık tasarımı, yerelleştirme, güvenlik ve performans. FxCop, kendi kurallarınızı oluşturmak için aracın gui ve komut satırı sürümlerinin yanı sıra bir SDK içerir. Daha fazla bilgi için FxCop Web sitesine bakın. Microsoft, geçiş çalışmalarınızda size yardımcı olacak bilgiler sağlayacak ek FxCop kuralları geliştirme sürecindedir.

Ayrıca, çalışma zamanında hangi ortamda çalıştığınızı belirlemenize yardımcı olan yönetilen kitaplık işlevleri de vardır.

  • System.IntPtr.Size— 32 bit modunda mı yoksa 64 bit modunda mı çalıştığınızı belirlemek için
  • System.Reflection.Module.GetPEKind— bir .exe veya .dll program aracılığıyla sorgulayıp yalnızca belirli bir platformda mı yoksa WOW64 altında mı çalıştırılacağını görmek için

Karşılaşabileceğiniz tüm zorlukları ele almak için belirli bir yordam kümesi yoktur. Bu teknik inceleme, bu zorluklarla ilgili farkındalığınızı artırmayı ve size olası alternatifleri sunmayı amaçlar.