Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu konu, C++/CX projenizdeki kaynak kodu C++/WinRT'deki eşdeğerine nasıl aktarabileceğinizi açıklayan serinin ilk konusudur.
Projeniz Windows Çalışma Zamanı C++ Şablon Kitaplığı (WRL) türlerini de kullanıyorsa bkz. WRL'den C++/WinRT'ye taşıma.
Taşıma stratejileri
C++/CX'ten C++/WinRT'ye taşımanın, Paralel Kalıplar Kitaplığı'ndaki (PPL) görevlerden ortak yordamlarına geçiş dışında, genellikle oldukça kolay olduğunu bilmekte fayda var. Modeller farklıdır. PPL görevleriyle coroutine'ler arasında doğal bir bire bir eşleme yoktur ve her durumda işe yarayan, kodu mekanik olarak aktarmanın basit bir yolu da yoktur. Taşımanın bu özel yönüyle ilgili yardım ve iki model arasında birlikte çalışma seçenekleriniz için bkz. Asynchrony ve C++/WinRT ile C++/CX arasında birlikte çalışma.
Geliştirme ekipleri, asenkron kodlarını taşıma işinin önündeki engeli aştıktan sonra, geri kalan taşıma işinin büyük ölçüde mekanik olduğunu sıklıkla belirtir.
Tek geçişte taşıma
Projenizin tamamını tek bir geçişte taşıma olanağınız varsa, ihtiyacınız olan bilgiler için yalnızca bu konuya ihtiyacınız olur (ve bunu izleyen birlikte çalışma konularına ihtiyacınız olmaz). C++/WinRT proje şablonlarından birini kullanarak Visual Studio'de yeni bir proje oluşturarak başlamanızı öneririz (bkz. C++/WinRT için Visual Studio destek). Ardından kaynak kod dosyalarınızı bu yeni projeye taşıyın ve C++/CX kaynak kodunun tamamını C++/WinRT'ye taşıyın.
Alternatif olarak, taşıma işini mevcut C++/CX projenizde yapmayı tercih ederseniz, buna C++/WinRT desteği eklemeniz gerekir. Bunu yapmak için izlediğiniz adımlar C++/CX projesi alma ve C++/WinRT desteği ekleme bölümünde açıklanmıştır. Taşımayı bitirdiğinizde, saf bir C++/CX projesi olan şeyi saf bir C++/WinRT projesine dönüştürmüş olacaksınız.
Note
Windows Çalışma Zamanı bileşen projeniz varsa tek bir geçişte taşıma tek seçeneğinizdir. C++ dilinde yazılmış bir Windows Çalışma Zamanı bileşeni projesi tüm C++/CX kaynak kodunu veya tüm C++/WinRT kaynak kodunu içermelidir. Bu proje türünde birlikte var olamazlar.
Projeyi aşamalı olarak taşıma
Önceki bölümde belirtildiği gibi Windows Çalışma Zamanı bileşen projeleri dışında, kod tabanınızın boyutu veya karmaşıklığı projenizi aşamalı olarak taşımayı gerekli kılıyorsa, bir süre için C++/CX ve C++/WinRT kodunun aynı projede yan yana bulunduğu bir taşıma işlemine ihtiyacınız olacaktır. Bu konuyu okumaya ek olarak, C++/WinRT ile C++/CX arasında birlikte çalışabilirlik ve Zaman uyumsuzluk ve C++/WinRT ile C++/CX arasında birlikte çalışabilirlik konularına da bakın. Bu konular, iki dil projeksiyonu arasında birlikte çalışma hakkında bilgi ve kod örnekleri sağlar.
Bir projeyi aşamalı taşıma işlemine hazırlamak için bir seçenek C++/CX projenize C++/WinRT desteği eklemektir. Bunu yapmak için izlediğiniz adımlar C++/CX projesi alma ve C++/WinRT desteği ekleme bölümünde açıklanmıştır. Daha sonra oradan aşamalı olarak bağlantı noktası oluşturabilirsiniz.
Bir diğer seçenek de C++/WinRT proje şablonlarından birini kullanarak Visual Studio'de yeni bir proje oluşturmaktır (bkz. C++/WinRT için Visual Studio destek). Ardından bu projeye C++/CX desteği ekleyin. Bunu yapmak için izlediğiniz adımlar C++/WinRT projesi alma ve C++/CX desteği ekleme bölümünde açıklanmıştır. Ardından kaynak kodunuzu bu koda taşımaya ve C++/CX kaynak kodunun bir kısmını C++/WinRT'ye taşımaya başlayabilirsiniz.
Her iki durumda da C++/WinRT kodunuz ve henüz taşımadığınız C++/CX kodları arasında birlikte çalışırsınız (her iki yolla da).
Note
Hem C++/CX hem de Windows SDK'sı kök ad alanı Windows türleri bildirir. C++/WinRT'ye aktarılmış bir Windows türü, Windows türüyle aynı tam nitelikli ada sahiptir, ancak C++ winrt ad alanında bulunur. Bu ayrı ad alanları, C++/CX'ten C++/WinRT'ye kendi hızınızda taşımanıza olanak sağlar.
XAML projesini aşamalı olarak taşıma
Önemli
XAML kullanan bir proje için, herhangi bir zamanda tüm XAML sayfa türlerinizin tamamen C++/CX veya tamamen C++/WinRT olması gerekir. Aynı proje içinde, XAML sayfa türlerinin dışında da (modellerinizde, görünüm modellerinizde ve başka yerlerde) C++/CX ile C++/WinRT’yi birlikte kullanmaya devam edebilirsiniz.
Bu senaryoda, önerdiğimiz iş akışı yeni bir C++/WinRT projesi oluşturmak ve kaynak kodu ve işaretlemeyi C++/CX projesinden kopyalamaktır. Tüm XAML sayfa türleriniz C++/WinRT olduğu sürece, Project>Yeni Öğe Ekle... ile yeni XAML sayfaları ekleyebilirsiniz.>Visual C++>Boş Sayfa (C++/WinRT).
Alternatif olarak, bir Windows Çalışma Zamanı bileşeni (WRC) kullanarak XAML C++/CX projesindeki kodu taşıma işleminin dışında tutabilirsiniz.
- Yeni bir C++/CX WRC projesi oluşturabilir, bu projeye olabildiğince çok C++/CX kodu taşıyabilir ve ardından XAML projesini C++/WinRT olarak değiştirebilirsiniz.
- Ya da yeni bir C++/WinRT WRC projesi oluşturabilir, XAML projesini C++/CX olarak bırakabilir ve C++/CX'i C++/WinRT'ye taşımaya başlayabilir ve sonuçta elde edilen kodu XAML projesinden ve bileşen projesine taşımaya başlayabilirsiniz.
- Aynı çözüm içinde bir C++/WinRT bileşen projesinin yanı sıra bir C++/CX bileşen projeniz de olabilir, her ikisine de uygulama projenizden başvurabilir ve bir projeden diğerine aşamalı olarak bağlantı noktası sağlayabilirsiniz. Yine, aynı projede iki dil projeksiyonunun kullanımıyla ilgili daha fazla bilgi için C++/WinRT ve C++/CX Arasında Birlikte Çalışabilirlik konusuna bakın.
C++/CX projesini C++/WinRT'ye taşımanın ilk adımları
Taşıma stratejiniz ne olursa olsun (tek geçişte taşıma veya aşamalı olarak taşıma), ilk adımınız projenizi taşımaya hazırlamaktır. İşte, işe başlayacağınız proje türü ve bunun nasıl kurulacağı açısından Taşıma Stratejileri bölümünde anlattıklarımızın özeti.
- Tek seferde taşıma. C++/WinRT proje şablonlarından birini kullanarak Visual Studio'de yeni bir proje oluşturun. C++/CX projenizdeki dosyaları bu yeni projeye taşıyın ve C++/CX kaynak kodunu taşıyın.
- XAML olmayan bir projeyi aşamalı olarak taşıma. C++/CX projenize C++/WinRT desteği eklemeyi seçebilir (bkz. Bir C++/CX projesine C++/WinRT desteği ekleme) ve geçişi kademeli olarak yapabilirsiniz. Ya da yeni bir C++/WinRT projesi oluşturup buna C++/CX desteği eklemeyi seçebilirsiniz (bkz. Bir C++/WinRT projesine C++/CX desteği ekleme); dosyaları taşıyıp geçişi kademeli olarak yapabilirsiniz.
- XAML projesini aşamalı olarak taşıma. Yeni bir C++/WinRT projesi oluşturun, dosyaları taşıyın ve geçişi aşamalı olarak gerçekleştirin. Herhangi bir zamanda XAML sayfa türleriniz tüm C ++/WinRT veya tüm C++/CX olmalıdır.
Bu konunun geri kalanı hangi taşıma stratejisini seçerseniz seçin geçerlidir. Kaynak kodu C++/CX'ten C++/WinRT'ye taşımayla ilgili teknik ayrıntıları içeren bir katalog içerir. Kademeli olarak taşıyorsanız, büyük olasılıkla C++/WinRT ile C++/CX arasında birlikte çalışma ve Zaman uyumsuzluk ve C++/WinRT ile C++/CX arasında birlikte çalışma konularına da göz atmak isteyeceksiniz.
Dosya adlandırma kuralları
XAML işaretleme dosyaları
| Dosya kaynağı | C++/CX | C++/WinRT |
|---|---|---|
| Geliştirici XAML dosyaları | MyPage.xaml MyPage.xaml.h MyPage.xaml.cpp |
MyPage.xaml MyPage.h MyPage.cpp MyPage.idl (aşağıya bakın) |
| Oluşturulan XAML dosyaları | MyPage.xaml.g.h MyPage.xaml.g.hpp |
MyPage.xaml.g.h MyPage.xaml.g.hpp MyPage.g.h |
C++/WinRT'nin, .xaml öğesini *.h ve *.cpp dosya adlarından kaldırdığını unutmayın.
C++/WinRT, Midl dosyası (.idl) olarak ek bir geliştirici dosyası ekler. C++/CX bu dosyayı arka planda otomatik olarak oluşturur ve tüm public ve protected üyeleri buna ekler. C++/WinRT'de dosyayı kendiniz ekler ve yazarsınız. Daha fazla ayrıntı, kod örnekleri ve IDL yazma yönergeleri için bkz. XAML denetimleri; C++/WinRT özelliğine bağlama.
Ayrıca bkz. Çalışma zamanı sınıflarını Midl dosyalarına ayırma (.idl)
Çalışma zamanı sınıfları
C++/CX, üst bilgi dosyalarınızın adlarına kısıtlama getirmez; Özellikle küçük sınıflar için birden çok çalışma zamanı sınıf tanımını tek bir üst bilgi dosyasına yerleştirmek yaygın bir durumdır. Ancak C++/WinRT, her çalışma zamanı sınıfının sınıf adından sonra adlandırılmış kendi üst bilgi dosyasına sahip olmasını gerektirir.
| C++/CX | C++/WinRT |
|---|---|
Common.href class A { ... }ref class B { ... } |
Common.idlruntimeclass A { ... }runtimeclass B { ... } |
A.hnamespace implements {struct A { ... };} |
|
B.hnamespace implements {struct B { ... };} |
C++/CX'te daha az yaygın (ancak hala yasal), XAML özel denetimleri için farklı adlandırılmış üst bilgi dosyaları kullanmaktır. Sınıf adıyla eşleşecek şekilde bu üst bilgi dosyasını yeniden adlandırmanız gerekir.
| C++/CX | C++/WinRT |
|---|---|
A.xaml<Page x:Class="LongNameForA" ...> |
A.xaml<Page x:Class="LongNameForA" ...> |
A.hpartial ref class LongNameForA { ... } |
LongNameForA.hnamespace implements {struct LongNameForA { ... };} |
Üst bilgi dosyası gereksinimleri
C++/CX, .winmd dosyalarından başlık dosyalarını dahili olarak otomatik oluşturduğu için herhangi bir özel başlık dosyası eklemenizi gerektirmez. C++/CX'te, adıyla kullandığınız ad alanları için using yönergelerini kullanmak yaygındır.
using namespace Windows::Media::Playback;
String^ NameOfFirstVideoTrack(MediaPlaybackItem^ item)
{
return item->VideoTracks->GetAt(0)->Name;
}
yönergesi using namespace Windows::Media::Playback , ad alanı ön eki olmadan yazmamıza MediaPlaybackItem olanak tanır.
Windows.Media.Core ad alanına da değindik, çünkü item->VideoTracks->GetAt(0), bir Windows.Media.Core.VideoTrack döndürür. Ancak VideoTrack adını herhangi bir yere yazmamız gerekmedi, bu nedenle bir using Windows.Media.Core yönergeye ihtiyacımız yoktu.
Ancak C++/WinRT, adını açıkça belirtmeseniz bile kullandığınız her ad alanına karşılık gelen bir başlık dosyasını dahil etmenizi gerektirir.
#include <winrt/Windows.Media.Playback.h>
#include <winrt/Windows.Media.Core.h> // !!This is important!!
using namespace winrt;
using namespace Windows::Media::Playback;
winrt::hstring NameOfFirstVideoTrack(MediaPlaybackItem const& item)
{
return item.VideoTracks().GetAt(0).Name();
}
Öte yandan MediaPlaybackItem.AudioTracksChanged olayı TypedEventHandler<MediaPlaybackItem türünde olsa da Windows. Foundation.Collections.IVectorChangedEventArgs>, bu olayı kullanmadığımız için eklememiz winrt/Windows.Foundation.Collections.h gerekmez.
C++/WinRT, ayrıca XAML biçimlendirmesinde kullanılan ad alanları için başlık dosyalarını eklemenizi gerektirir.
<!-- MainPage.xaml -->
<Rectangle Height="400"/>
Rectangle sınıfını kullanmak için bu include ifadesini eklemeniz gerekir.
// MainPage.h
#include <winrt/Microsoft.UI.Xaml.Shapes.h>
Bir başlık dosyasını unutursanız her şey sorunsuz derlenir, ancak consume_ sınıfları eksik olduğu için bağlayıcı hataları alırsınız.
Parametre aktarımı
C++/CX kaynak kodu yazarken, C++/CX türlerini işlev parametreleri olarak hat (^) referansları biçiminde geçirirsiniz.
void LogPresenceRecord(PresenceRecord^ record);
C++/WinRT'de, zaman uyumlu işlevler için varsayılan olarak parametreleri kullanmanız const& gerekir. Bu, kopyaları ve birbirine kenetlenmiş ek yükü önler. Ancak eş yordamlarınız değere göre yakalamalarını sağlamak ve yaşam süresi sorunlarını önlemek için değer geçişi kullanmalıdır (daha fazla ayrıntı için bkz. C++/WinRT ile eşzamanlılık ve zaman uyumsuz işlemler).
void LogPresenceRecord(PresenceRecord const& record);
IASyncAction LogPresenceRecordAsync(PresenceRecord const record);
Bir C++/WinRT nesnesi, özünde, temelindeki Windows Çalışma Zamanı nesnesine yönelik bir arabirim işaretçisi tutan bir değerdir. C++/WinRT nesnesini kopyaladığınızda, derleyici kapsüllenmiş arabirim işaretçisini kopyalayarak başvuru sayısını artırır. Kopyanın nihai yok edilmesi, başvuru sayısının azalmasını içerir. Bu nedenle, yalnızca gerektiğinde kopyalama ek yüküne katlanın.
Değişken ve alan referansları
C++/CX kaynak kodu yazarken, Windows Çalışma Zamanı nesnelerine başvurmak için şapka (^) değişkenlerini ve bir şapka değişkeninin başvurusunu çözümlemek için ok (->) işlecini kullanırsınız.
IVectorView<User^>^ userList = User::Users;
if (userList != nullptr)
{
for (UINT32 iUser = 0; iUser < userList->Size; ++iUser)
...
Eşdeğer C++/WinRT koduna taşıma yaparken, şapkaları kaldırarak ve ok işlecini (->) nokta işleci (.) olarak değiştirerek uzun bir yol elde edebilirsiniz. C++/WinRT öngörülen türler değerdir ve işaretçi değildir.
IVectorView<User> userList = User::Users();
if (userList != nullptr)
{
for (UINT32 iUser = 0; iUser < userList.Size(); ++iUser)
...
Bir C++/CX hat başvurusunun varsayılan oluşturucusu, onu null ile başlatır. Burada, doğru türde ancak başlatılmamış bir değişken/alan oluşturduğumuz bir C++/CX kod örneği verilmiştir. Başka bir deyişle, başlangıçta bir TextBlock referansı içermez; daha sonra bir referans atamayı amaçlıyoruz.
TextBlock^ textBlock;
class MyClass
{
TextBlock^ textBlock;
};
C++/WinRT'deki eşdeğeri için bkz. Gecikmeli başlatma.
Özellikler
C++/CX dil uzantıları özellikler kavramını içerir. C++/CX kaynak kodu yazarken, bir özelliğe sanki bir alanmış gibi erişebilirsiniz. Standart C++ özelliği kavramına sahip olmadığından, C++/WinRT'de get ve set işlevlerini çağırırsınız.
Aşağıdaki örneklerde XboxUserId, UserState, PresenceDeviceRecords ve Size özelliklerinin tümü yer alır.
Bir özelliğin değerini alma
C++/CX'te özellik değerini şu şekilde alabilirsiniz.
void Sample::LogPresenceRecord(PresenceRecord^ record)
{
auto id = record->XboxUserId;
auto state = record->UserState;
auto size = record->PresenceDeviceRecords->Size;
}
Eşdeğer C++/WinRT kaynak kodu, özelliğiyle aynı ada sahip ancak parametresiz bir işlevi çağırır.
void Sample::LogPresenceRecord(PresenceRecord const& record)
{
auto id = record.XboxUserId();
auto state = record.UserState();
auto size = record.PresenceDeviceRecords().Size();
}
PresenceDeviceRecords işlevinin size işlevi olan bir Windows Çalışma Zamanı nesnesi döndürdüğünü unutmayın. Döndürülen nesne aynı zamanda C++/WinRT tarafından yansıtılan bir tür olduğundan, Size'ı çağırmak için nokta işlecini kullanarak referansını çözüyoruz.
Özelliği yeni bir değere ayarlama
Bir özelliği yeni bir değere ayarlamak benzer bir desen izler. İlk olarak, C++/CX içinde.
record->UserState = newValue;
C++/WinRT’de aynı şeyi yapmak için, özellikle aynı adı taşıyan bir işlevi çağırır ve ona bir argüman verirsiniz.
record.UserState(newValue);
Sınıfın örneğini oluşturma
C++/CX nesnesiyle, genellikle şapka (^) referansı olarak bilinen, ona yönelik bir tanıtıcı üzerinden çalışırsınız. Anahtar sözcüğü aracılığıyla ref new yeni bir nesne oluşturursunuz ve bu da çalışma zamanı sınıfının yeni bir örneğini etkinleştirmek için RoActivateInstance'ı çağırır.
using namespace Windows::Storage::Streams;
class Sample
{
private:
Buffer^ m_gamerPicBuffer = ref new Buffer(MAX_IMAGE_SIZE);
};
C++/WinRT nesnesi bir değerdir; bunu yığında veya bir nesnenin alanı olarak ayırabilirsiniz. Bir C++/WinRT nesnesi oluşturmak için aslaref new (ve new da) kullanmazsınız. Arka planda RoActivateInstance hala çağrılmaya devam ediyor.
using namespace winrt::Windows::Storage::Streams;
struct Sample
{
private:
Buffer m_gamerPicBuffer{ MAX_IMAGE_SIZE };
};
Bir kaynağın başlatılması pahalıysa, başlatmayı gerçekten gerekli olana kadar geciktirmek yaygın bir durumdur. Daha önce de belirtildiği gibi, bir C++/CX şapka başvurusu için varsayılan oluşturucu bunu null olarak başlatır.
using namespace Windows::Storage::Streams;
class Sample
{
public:
void DelayedInit()
{
// Allocate the actual buffer.
m_gamerPicBuffer = ref new Buffer(MAX_IMAGE_SIZE);
}
private:
Buffer^ m_gamerPicBuffer;
};
Aynı kod C++/WinRT'ye taşınabilir. std::nullptr_t oluşturucusunun kullanımına dikkat edin. Bu oluşturucu hakkında daha fazla bilgi için bkz. Gecikmeli başlatma.
using namespace winrt::Windows::Storage::Streams;
struct Sample
{
void DelayedInit()
{
// Allocate the actual buffer.
m_gamerPicBuffer = Buffer(MAX_IMAGE_SIZE);
}
private:
Buffer m_gamerPicBuffer{ nullptr };
};
Varsayılan oluşturucu koleksiyonları nasıl etkiler?
C++ koleksiyon türleri, istenmeyen nesne yapısına neden olabilecek varsayılan oluşturucuyu kullanır.
| Scenario | C++/CX | C++/WinRT (yanlış) | C++/WinRT (doğru) |
|---|---|---|---|
| Başlangıçta boş olan yerel değişken | TextBox^ textBox; |
TextBox textBox; // Creates a TextBox! |
TextBox textBox{ nullptr }; |
| Üye değişkeni, başlangıçta boş | class C {TextBox^ textBox;}; |
class C {TextBox textBox; // Creates a TextBox!}; |
class C {TextBox textbox{ nullptr };}; |
| Genel değişken, başlangıçta boş | TextBox^ g_textBox; |
TextBox g_textBox; // Creates a TextBox! |
TextBox g_textBox{ nullptr }; |
| Boş referansların vektörü | std::vector<TextBox^> boxes(10); |
// Creates 10 TextBox objects!std::vector<TextBox> boxes(10); |
std::vector<TextBox> boxes(10, nullptr); |
| Haritada değer ayarlama | std::map<int, TextBox^> boxes;boxes[2] = value; |
std::map<int, TextBox> boxes;// Creates a TextBox at 2,// then overwrites it!boxes[2] = value; |
std::map<int, TextBox> boxes;boxes.insert_or_assign(2, value); |
| Boş referanslar dizisi | TextBox^ boxes[2]; |
// Creates 2 TextBox objects!TextBox boxes[2]; |
TextBox boxes[2] = { nullptr, nullptr }; |
| Eşleştir | std::pair<TextBox^, String^> p; |
// Creates a TextBox!std::pair<TextBox, String> p; |
std::pair<TextBox, String> p{ nullptr, nullptr }; |
Boş referans koleksiyonları hakkında daha fazla bilgi
C++/CX içinde bir Platform::Array^ (bkz. Platform::Array^ taşıma) varsa, bunu dizi olarak bırakmak yerine C++/WinRT'de bir std::vector'e (hatta herhangi bir bitişik kapsayıcıya) taşımayı tercih edebilirsiniz. std::vector seçeneğini belirlemenin avantajları vardır.
Örneğin, boş başvurulardan oluşan sabit boyutlu bir vektör oluşturmak için kısaltma olsa da (yukarıdaki tabloya bakın), boş başvuru dizisi oluşturmak için böyle bir kısaltma yoktur. Bir dizideki her öğe için nullptr ifadesini tekrarlamanız gerekir. Çok az öğeniz varsa, ek değerler varsayılan olarak oluşturulacaktır.
Bir vektörü, başlatma sırasında boş referanslarla doldurabilirsiniz (yukarıdaki tabloda olduğu gibi) veya başlatmadan sonra bunun gibi bir kodla boş referanslarla doldurabilirsiniz.
std::vector<TextBox> boxes(10); // 10 default-constructed TextBoxes.
boxes.resize(10, nullptr); // 10 empty references.
std::map örneği hakkında daha fazla bilgi
[]
std::map için alt simge işleci şöyle davranır.
- Anahtar eşlemde bulunursa, üzerine yazabileceğiniz mevcut değere bir referans döndürün.
- Anahtar haritada bulunamazsa, haritada anahtardan (taşınabilirse taşındıysa) ve varsayılan olarak derlenmiş bir değerden oluşan yeni bir giriş oluşturun ve değere bir başvuru döndürün (daha sonra üzerine yazabilirsiniz).
Başka bir deyişle, [] işleç her zaman haritada bir girdi oluşturur. Bu, C#, Java ve JavaScript'ten farklıdır.
Temel çalışma zamanı sınıfından türetilmiş bir sınıfa dönüştürme
Türetilmiş türde bir nesneye başvurduğunu bildiğiniz bir tabana başvuru olması yaygın bir durumdır. C++/CX'te, taban sınıfa başvuruyu türetilmiş sınıfa başvuruya dynamic_castdönüştürmek için kullanırsınız.
dynamic_cast yalnızca QueryInterface'e yapılan gizli bir çağrıdır. Burada tipik bir örnek verilmiştir; bağımlılık özelliği değiştirilmiş olayı işlip DependencyObject'ten bağımlılık özelliğinin sahibi olan gerçek türe geri döndürmek istiyorsunuz.
void BgLabelControl::OnLabelChanged(Microsoft::UI::Xaml::DependencyObject^ d, Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs^ e)
{
BgLabelControl^ theControl{ dynamic_cast<BgLabelControl^>(d) };
if (theControl != nullptr)
{
// succeeded ...
}
}
Eşdeğer C++/WinRT kodu, değerini dynamic_cast kapsülleyen IUnknown::try_as işlevine yapılan bir çağrıyla değiştirir. Ayrıca, bunun yerine IUnknown::as çağırma seçeneğiniz de vardır; bu, gerekli arabirimin (istediğiniz türün varsayılan arabiriminin) sorgulanması sonucunda döndürülmemesi durumunda bir özel durum oluşturur. İşte bir C++/WinRT kod örneği.
void BgLabelControl::OnLabelChanged(Microsoft::UI::Xaml::DependencyObject const& d, Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const& e)
{
if (BgLabelControlApp::BgLabelControl theControl{ d.try_as<BgLabelControlApp::BgLabelControl>() })
{
// succeeded ...
}
try
{
BgLabelControlApp::BgLabelControl theControl{ d.as<BgLabelControlApp::BgLabelControl>() };
// succeeded ...
}
catch (winrt::hresult_no_interface const&)
{
// failed ...
}
}
Türetilmiş sınıflar
Çalışma zamanı sınıfından türetmek için temel sınıfın birleştirilebilir olması gerekir. C++/CX, sınıflarınızı birleştirilebilir hale getirmek için herhangi bir özel adım atmanızı gerektirmez, ancak C++/WinRT yapar. Sınıfınızın temel sınıf olarak kullanılabilir olmasını istediğinizi belirtmek için korumasız anahtar sözcüğünü kullanırsınız.
unsealed runtimeclass BasePage : Microsoft.UI.Xaml.Controls.Page
{
...
}
runtimeclass DerivedPage : BasePage
{
...
}
Uygulama üst bilgisi sınıfınızda, türetilmiş sınıf için otomatik olarak oluşturulan üst bilgiyi eklemeden önce temel sınıf üst bilgi dosyasını eklemeniz gerekir. Aksi takdirde "Bu türün ifade olarak geçersiz kullanımı" gibi hatalar alırsınız.
// DerivedPage.h
#include "BasePage.h" // This comes first.
#include "DerivedPage.g.h" // Otherwise this header file will produce an error.
namespace winrt::MyNamespace::implementation
{
struct DerivedPage : DerivedPageT<DerivedPage>
{
...
}
}
Bir temsilci kullanarak olay işleme
Burada, bu örnekte temsilci olarak lambda işlevini kullanarak C++/CX içinde bir olayı işlemeye yönelik tipik bir örnek verilmiştır.
auto token = myButton->Click += ref new RoutedEventHandler([=](Platform::Object^ sender, RoutedEventArgs^ args)
{
// Handle the event.
// Note: locals are captured by value, not reference, since this handler is delayed.
});
Bu, C++/WinRT'deki eşdeğerdir.
auto token = myButton().Click([=](IInspectable const& sender, RoutedEventArgs const& args)
{
// Handle the event.
// Note: locals are captured by value, not reference, since this handler is delayed.
});
Lambda işlevi yerine, temsilcinizi bağımsız bir işlev ya da bir üye işlev işaretçisi olarak gerçekleştirmeyi seçebilirsiniz. Daha fazla bilgi için bkz . C++/WinRT'de temsilcileri kullanarak olayları işleme.
Olayların ve temsilcilerin dahili olarak kullanıldığı (ikili dosyalar arasında değil) bir C++/CX kod tabanından geçiş yapıyorsanız, winrt::delegate bu deseni C++/WinRT içinde yeniden oluşturmanıza yardımcı olur. Ayrıca bkz. Proje içinde parametreli temsilciler, basit sinyaller ve geri çağırmalar.
Temsilciyi iptal etme
C++/CX'te önceki olay kaydını iptal etmek için işlecini -= kullanırsınız.
myButton->Click -= token;
Bu, C++/WinRT'deki eşdeğerdir.
myButton().Click(token);
Daha fazla bilgi ve seçenek için bkz. Kayıtlı temsilciyi iptal etme.
Kutulama ve kutu açma
C++/CX, skaler değerleri otomatik olarak nesnelere dönüştürür. C++/WinRT, winrt::box_value işlevini açıkça çağırmanızı gerektirir. Her iki dil de kutudan çıkarmayı açıkça belirtmenizi gerektirir. Bkz. C++/WinRT ile kutulama ve kutu açma.
Aşağıdaki tablolarda bu tanımları kullanacağız.
| C++/CX | C++/WinRT |
|---|---|
int i; |
int i; |
String^ s; |
winrt::hstring s; |
Object^ o; |
IInspectable o; |
| Operation | C++/CX | C++/WinRT |
|---|---|---|
| Boks | o = 1;o = "string"; |
o = box_value(1);o = box_value(L"string"); |
| Kutudan çıkarma | i = (int)o;s = (String^)o; |
i = unbox_value<int>(o);s = unbox_value<winrt::hstring>(o); |
C++/CX ve C# bir değer türüne null işaretçisini kaldırmaya çalışırsanız özel durumlar oluşturur. C++/WinRT bunu programlama hatası sayar ve çöker. C++/WinRT'de winrt::unbox_value_or işlevini kullanarak nesnenin sandığınız türde olmadığı bir durumla ilgilenmek isteyebilirsiniz.
| Scenario | C++/CX | C++/WinRT |
|---|---|---|
| Bilinen bir tamsayının kutudan çıkarılması | i = (int)o; |
i = unbox_value<int>(o); |
| o null ise | Platform::NullReferenceException |
Çökme |
| o, kutulanmış bir int değilse | Platform::InvalidCastException |
Çökme |
| int’in kutusunu aç, null ise yedeği kullan; başka bir şeyse çök | i = o ? (int)o : fallback; |
i = o ? unbox_value<int>(o) : fallback; |
| Mümkünse int kutusunu aç; diğer her şey için geri dönüş kullan | auto box = dynamic_cast<IBox<int>^>(o);i = box ? box->Value : fallback; |
i = unbox_value_or<int>(o, fallback); |
Dizeyi kutulama ve kutulama
Dize, bazı yönlerden bir değer türü ve diğer şekillerde bir başvuru türüdür. C++/CX ve C++/WinRT dizeleri farklı şekilde ele alır.
ABI türü HSTRING, başvuru sayısı tutulan bir dizenin işaretçisidir. Ancak IInspectable'dan türetilmez, bu nedenle teknik olarak bir nesne değildir. Ayrıca, null HSTRING boş dizeyi temsil eder. IInspectable'dan türetilmeyen öğelerin kutulanması, bunları bir IReference<T> içine sarmalayarak yapılır ve Windows Çalışma Zamanı PropertyValue nesnesi biçiminde standart bir uygulama sağlar (özel türler PropertyType::OtherType olarak bildirilir).
C++/CX, bir Windows Çalışma Zamanı dizesini başvuru türü olarak temsil ederken C++/WinRT, bir dizeyi değer türü olarak sunar. Bu, kutulanmış null dizenin oraya nasıl girdiğinize bağlı olarak farklı gösterimleri olabileceği anlamına gelir.
Ayrıca, C++/CX null bir String^ başvurusunu çözümlemenize olanak tanır; bu durumda "" dizesi gibi davranır.
| Behavior | C++/CX | C++/WinRT |
|---|---|---|
| Bildirim | Object^ o;String^ s; |
IInspectable o;hstring s; |
| Dize türü kategorisi | Referans türü | Değer türü |
| null HSTRING olarak yansıtılır | (String^)nullptr |
hstring{} |
Null ve "" özdeş mi? |
Yes | Yes |
| Null değerinin geçerliliği | s = nullptr;s->Length == 0 (geçerli) |
s = hstring{};s.size() == 0 (geçerli) |
| Nesneye null dize atarsanız | o = (String^)nullptr;o == nullptr |
o = box_value(hstring{});o != nullptr |
"" nesneye atarsanız |
o = "";o == nullptr |
o = box_value(hstring{L""});o != nullptr |
Temel kutulama ve kutu açma.
| Operation | C++/CX | C++/WinRT |
|---|---|---|
| Dizeyi kutu içine al | o = s;Boş dize nullptr'a dönüşür. |
o = box_value(s);Boş dize null olmayan nesneye dönüşür. |
| Bilinen bir dizeyi kutudan çıkarma | s = (String^)o;Null nesne boş dizeye dönüşür. Dize değilse InvalidCastException oluşur. |
s = unbox_value<hstring>(o);Null nesne çöküyor. Dize değilse çöküyor. |
| Olası bir dizenin kutusunu kaldırma | s = dynamic_cast<String^>(o);Null değerler veya dize olmayan değerler boş dizeye dönüştürülür. |
s = unbox_value_or<hstring>(o, fallback);Null veya string olmayan değer, varsayılan değer olarak kullanılır. Boş dize korunur. |
Eşzamanlılık ve asenkron işlemler
Parallel Patterns Library (PPL) (örneğin concurrency::task) C++/CX şapka başvurularına destek verecek şekilde güncellendi.
C++/WinRT için, bunun yerine coroutines co_await kullanmalısınız. Daha fazla bilgi ve kod örnekleri için bkz. C++/WinRT ile eşzamanlılık ve zaman uyumsuz işlemler.
XAML biçimlendirmesinden nesneleri kullanma
C++/CX projesinde, XAML işaretlemesindeki özel üyeleri ve adlandırılmış öğeleri kullanabilirsiniz. Ancak C++/WinRT'de, XAML {x:Bind} işaretleme uzantısı kullanılarak kullanılan tüm varlıklar IDL'de genel kullanıma sunulmalıdır.
Ayrıca, Boolean’a bağlandığında C++/CX’te true veya false görüntülenir, ancak C++/WinRT’de Windows.Foundation.IReference`1<Boolean> gösterilir.
Daha fazla bilgi ve kod örnekleri için, İşaretlemeden nesneleri kullanma bölümüne bakın.
C++/CX Platform türlerini C++/WinRT türlerine eşleme
C++/CX , Platform ad alanında çeşitli veri türleri sağlar. Bu türler standart C++ değildir, bu nedenle bunları yalnızca Windows Çalışma Zamanı dil uzantılarını etkinleştirdiğinizde kullanabilirsiniz (Visual Studio proje özelliği C/C++>Genel>Kullanım Windows Çalışma Zamanı Uzantısı>Evet (/ZW)). Aşağıdaki tablo , Platform türlerinden C++/WinRT'deki eşdeğerlerine taşımanıza yardımcı olur. Bunu yaptıktan sonra, C++/WinRT standart C++ olduğundan seçeneği kapatabilirsiniz /ZW .
| C++/CX | C++/WinRT |
|---|---|
| Platform::Agile^ | winrt::agile_ref |
| Platform::Array^ | Bkz. Port Platform::Array^ |
| Platform::Exception^ | winrt::hresult_error |
| Platform::InvalidArgumentException^ | winrt::hresult_invalid_argument |
| Platform::Object^ | winrt::Windows::Foundation::IInspectable |
| Platform::String^ | winrt::hstring |
Platform::Agile^ öğesini winrt::agile_ref'e taşı
C++/CX içindeki Platform::Agile^ türü, herhangi bir iş parçacığından erişilebilen bir Windows Çalışma Zamanı sınıfını temsil eder. C++/WinRT eşdeğeri winrt::agile_ref'dir.
C++/CX içinde.
Platform::Agile<Windows::UI::Core::CoreWindow> m_window;
C++/WinRT'de (WinUI 3, CoreWindow yerine Microsoft::UI::Xaml::Window kullanır).
winrt::agile_ref<Microsoft::UI::Xaml::Window> m_window;
Taşımak Platform::Array^
C++/CX'in dizi kullanmanızı gerektirdiği durumlarda, C++/WinRT bitişik kapsayıcıları kullanmanıza olanak tanır. Bkz. Varsayılan oluşturucunun koleksiyonları nasıl etkilediği; buradan std::vector'ün neden iyi bir seçim olduğunu anlayabilirsiniz.
Dolayısıyla, C++/CX'te bir Platform::Array^ varsa, taşıma seçenekleriniz arasında bir başlatıcı listesi, std::array veya std::vector kullanmak yer alır. Daha fazla bilgi ve kod örnekleri için bkz. Standart başlatıcı listeleri ve Standart diziler ve vektörler.
Platform::Exception^ öğesini winrt::hresult_error öğesine taşı
Platform::Exception^ türü, bir Windows Çalışma Zamanı API'si S_OK HRESULT olmayan bir değer döndürdüğünde C++/CX biçiminde oluşturulur. C++/WinRT eşdeğeri winrt::hresult_error'dir.
C++/WinRT’ye port etmek için, Platform::Exception^ kullanan tüm kodu winrt::hresult_error kullanacak şekilde değiştirin.
C++/CX içinde.
catch (Platform::Exception^ ex)
C++/WinRT'de.
catch (winrt::hresult_error const& ex)
C++/WinRT bu özel durum sınıflarını sağlar.
| Özel durum türü | Temel sınıf | HRESULT |
|---|---|---|
| winrt::hresult_error | çağır hresult_error::to_abi | |
| winrt::hresult_access_denied | winrt::hresult_error | E_ACCESSDENIED |
| winrt::hresult_canceled | winrt::hresult_error | ERROR_CANCELLED |
| winrt::hresult_changed_state | winrt::hresult_error | E_CHANGED_STATE |
| winrt::hresult_class_not_available | winrt::hresult_error | CLASS_E_CLASSNOTAVAILABLE |
| winrt::hresult_illegal_delegate_assignment | winrt::hresult_error | E_ILLEGAL_DELEGATE_ASSIGNMENT |
| winrt::hresult_illegal_method_call | winrt::hresult_error | E_ILLEGAL_METHOD_CALL |
| winrt::hresult_illegal_state_change | winrt::hresult_error | E_ILLEGAL_STATE_CHANGE |
| winrt::hresult_invalid_argument | winrt::hresult_error | E_INVALIDARG |
| winrt::hresult_no_interface | winrt::hresult_error | E_NOINTERFACE |
| winrt::hresult_not_implemented | winrt::hresult_error | E_NOTIMPL |
| winrt::hresult_out_of_bounds | winrt::hresult_error | E_BOUNDS |
| winrt::hresult_wrong_thread | winrt::hresult_error | RPC_E_WRONG_THREAD |
Her sınıfın ( hresult_error temel sınıfı aracılığıyla) hatanın HRESULT değerini döndüren bir to_abi işlevi ve bu HRESULT'un dize gösterimini döndüren bir ileti işlevi sağladığını unutmayın.
C++/CX'te özel durum oluşturma örneği aşağıda verilmiştır.
throw ref new Platform::InvalidArgumentException(L"A valid User is required");
Ve C++/WinRT'deki karşılığı.
throw winrt::hresult_invalid_argument{ L"A valid User is required" };
Platform::Object^ öğesini winrt::Windows::Foundation::IInspectable öğesine taşıma
Tüm C++/WinRT türleri gibi winrt::Windows::Foundation::IInspectable bir değer türüdür. Bu tür bir değişkeni null olarak şu şekilde başlatabilirsiniz.
winrt::Windows::Foundation::IInspectable var{ nullptr };
Platform::String^ öğesini winrt::hstring öğesine taşıma
Platform::String^ Windows Çalışma Zamanı HSTRING ABI türüyle eşdeğerdir. C++/WinRT için eşdeğer winrt::hstring'dir. Ancak C++/WinRT ile, Windows Çalışma Zamanı API’lerini std::wstring gibi C++ Standart Kitaplığı geniş karakterli dize türlerini ve/veya geniş karakterli dize sabitlerini kullanarak çağırabilirsiniz. Diğer ayrıntılar ve kod örnekleri için bkz. C++/WinRT'de dize işleme.
C++/CX ile Platform::String::D ata özelliğine erişerek dizeyi C stili const wchar_t* dizisi olarak alabilirsiniz (örneğin, std::wcout dizinine geçirmek için).
auto var{ titleRecord->TitleName->Data() };
Aynı işlemi C++/WinRT ile yapmak için hstring::c_str işlevini kullanarak std::wstring'den yapabileceğiniz gibi null sonlandırılan C stili bir dize sürümü alabilirsiniz.
auto var{ titleRecord.TitleName().c_str() };
Dizeleri alan veya döndüren API'leri uygulama söz konusu olduğunda, genellikle platform::String^ kullanan herhangi bir C++/CX kodunu winrt::hstring kullanacak şekilde değiştirirsiniz.
Burada bir dize alan bir C++/CX API örneği verilmiş.
void LogWrapLine(Platform::String^ str);
C++/WinRT için bu API'nin MIDL 3.0'da böyle olduğunu bildirebilirsiniz.
// LogType.idl
void LogWrapLine(String str);
C++/WinRT araç zinciri sizin için buna benzer bir kaynak kodu oluşturur.
void LogWrapLine(winrt::hstring const& str);
ToString()
C++/CX türleri Object::ToString yöntemini sağlar.
int i{ 2 };
auto s{ i.ToString() }; // s is a Platform::String^ with value L"2".
C++/WinRT bu tesisi doğrudan sağlamaz, ancak alternatiflere dönebilirsiniz.
int i{ 2 };
auto s{ std::to_wstring(i) }; // s is a std::wstring with value L"2".
C++/WinRT sınırlı sayıda tür için winrt::to_hstring'i de destekler. Dizeleştirmek istediğiniz ek türler için aşırı yüklemeler eklemeniz gerekir.
| Language | int'i dizgeye dönüştür | enum'u dizeye dönüştürme |
|---|---|---|
| C++/CX | String^ result = "hello, " + intValue.ToString(); |
String^ result = "status: " + status.ToString(); |
| C++/WinRT | hstring result = L"hello, " + to_hstring(intValue); |
// must define overload (see below)hstring result = L"status: " + to_hstring(status); |
Bir enum’u dizeye dönüştürme söz konusu olduğunda, winrt::to_hstring gerçeklemesini sağlamanız gerekir.
namespace winrt
{
hstring to_hstring(StatusEnum status)
{
switch (status)
{
case StatusEnum::Success: return L"Success";
case StatusEnum::AccessDenied: return L"AccessDenied";
case StatusEnum::DisabledByPolicy: return L"DisabledByPolicy";
default: return to_hstring(static_cast<int>(status));
}
}
}
Bu dizeleştirmeler genellikle veri bağlama tarafından örtük olarak kullanılır.
<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>
Bu bağlamalar, ilişkili özelliğin winrt::to_hstring işlemini gerçekleştirir. İkinci örnekte ( StatusEnum) kendi winrt::to_hstring aşırı yüklemesini sağlamanız gerekir, aksi takdirde derleyici hatası alırsınız.
Dize oluşturma
C++/CX ve C++/WinRT, dize oluşturma için standart std::wstringstream değerini erteler .
| Operation | C++/CX | C++/WinRT |
|---|---|---|
| Dize ekleme, null değerleri koruma | stream.print(s->Data(), s->Length); |
stream << std::wstring_view{ s }; |
| Dize ekle, ilk nullta durdur | stream << s->Data(); |
stream << s.c_str(); |
| Sonucu ayıklama | ws = stream.str(); |
ws = stream.str(); |
Diğer örnekler
Aşağıdaki örneklerde ws , std::wstring türünde bir değişkendir. Ayrıca, C++/CX 8 bit dizeden Platform::String oluşturabilirken, C++/WinRT bunu yapmaz.
| Operation | C++/CX | C++/WinRT |
|---|---|---|
| Sabit değerden dize oluştur | String^ s = "hello";String^ s = L"hello"; |
// winrt::hstring s{ "hello" }; // Doesn't compilewinrt::hstring s{ L"hello" }; |
| std::wstring'den dönüştürme, null değerleri koruma | String^ s = ref new String(ws.c_str(),(uint32_t)ws.size()); |
winrt::hstring s{ ws };s = winrt::hstring(ws);// s = ws; // Doesn't compile |
| std::wstring'den dönüştür, ilk nullta durdur | String^ s = ref new String(ws.c_str()); |
winrt::hstring s{ ws.c_str() };s = winrt::hstring(ws.c_str());// s = ws.c_str(); // Doesn't compile |
| Null değerleri koruyarak std::wstring'e dönüştürün | std::wstring ws{ s->Data(), s->Length };ws = std::wstring(s>Data(), s->Length); |
std::wstring ws{ s };ws = s; |
| std::wstring'e dönüştür, ilk nullta durdur | std::wstring ws{ s->Data() };ws = s->Data(); |
std::wstring ws{ s.c_str() };ws = s.c_str(); |
| Sabit değeri metoda geçirin | Method("hello");Method(L"hello"); |
// Method("hello"); // Doesn't compileMethod(L"hello"); |
| std::wstring'i yönteme geçirme | Method(ref new String(ws.c_str(),(uint32_t)ws.size()); // Stops on first null |
Method(ws);// param::winrt::hstring accepts std::wstring_view |
Önemli API'ler
İlgili konular
Note
Birçok C++/WinRT konusu UWP belgelerinden bu bölüme geçirilmeye çalışılmaktadır. Geçiş tamamlanana kadar, aşağıdaki listede yer alan bağlantılar UWP belgeleri bölümüne yol açabilir. C++/WinRT dil projeksiyonu hem UWP hem de WinUI 3 uygulamaları için aynıdır, böylece içerik her iki bağlamda da geçerlidir. UWP'ye özgü desenler (uygulama yaşam döngüsü veya Windows.UI ad alanı API'leri gibi) bu makalelerde açıkça not edilir.
- C++/CX
- C++/WinRT'de olay oluşturma
- C++/WinRT ile eşzamanlılık ve eşzamansız işlemler
- C++/WinRT ile API'leri kullanma
- C++/WinRT'de temsilcileri kullanarak olayları işleme
- C++/WinRT ve C++/CX arasında birlikte çalışma
- Zaman uyumsuzluk ve C++/WinRT ile C++/CX arasında birlikte çalışabilirlik
- Microsoft Arabirim Tanımlama Dili 3.0 başvurusu
- WRL'den C++/WinRT'ye gitme
- C++/WinRT'de dize işleme
Windows developer