C++/WinRT ile Windows Çalışma Zamanı API'leri yazma ve kullanma hakkında sahip olabileceğiniz soruların yanıtları.
Önemli
C++/WinRT hakkında sürüm notları için bkz. C++/WinRT 2.0'da Haberler ve değişiklikler.
Note
Sorunuz gördüğünüz bir hata iletisiyle ilgiliyse C++/WinRT Sorunlarını Giderme konusuna da bakın.
C++/WinRT örnek uygulamalarını nerede bulabilirim?
C++/WinRT projemi Windows SDK'nın daha sonraki bir sürümüne nasıl yeniden hedeflerim?
C++/WinRT 2.0'a geçtiğime göre yeni projem neden derlenemiyor?
Tüm değişiklikler (son değişiklikler dahil) için bkz. C++/WinRT 2.0'da Haberler ve değişiklikler. Örneğin, bir Windows Çalışma Zamanı koleksiyonu üzerinde aralık tabanlı for kullanıyorsanız, artık #include <winrt/Windows.Foundation.Collections.h> yapmanız gerekir.
Yeni projem neden derlenemiyor? Visual Studio 2017 (sürüm 15.8.0 veya üzeri) ve SDK sürüm 17134 kullanıyorum
Visual Studio 2017’yi (sürüm 15.8.0 veya üzeri) kullanıyorsanız ve Windows SDK’nin 10.0.17134.0 sürümünü (Windows 10, sürüm 1803) hedefliyorsanız, yeni oluşturulmuş bir C++/WinRT projesi "error C3861: 'from_abi': identifier not found" hatasıyla karşılaşabilir ve base.h dosyasından kaynaklanan diğer hatalar nedeniyle derlenemeyebilir. Çözüm, Windows SDK'sının daha sonraki (daha uyumlu) bir sürümünü hedeflemek veya proje özelliği C/C++>Dil>Uyumluluğu modunu ayarlamaktır: Hayır (ayrıca proje özelliği C/C++>Ek Seçenekler'in altında /permissive- görünüyorsa, silin).
"C++/WinRT VSIX artık proje derleme desteği sağlamıyor." derleme hatasını nasıl çözebilirim? Lütfen Microsoft.Windows.CppWinRT NuGet paketine bir proje referansı ekleyin"?
Microsoft.Windows.CppWinRT NuGet paketini projenize yükleyin. Ayrıntılar için bkz. VSIX uzantısının önceki sürümleri.
NuGet paketindeki derleme desteğini nasıl özelleştirebilirim?
C++/WinRT derleme desteği (props/targets), Microsoft.Windows.CppWinRT NuGet paketindeki readme dosyasında belgelenmiştir.
C++/WinRT Visual Studio Uzantısı (VSIX) için gereksinimler nelerdir?
VSIX uzantısının 1.0.190128.4 sürümü ve üzeri için bkz. C++/WinRT desteği Visual Studio. Diğer sürümler için bkz. VSIX uzantısının önceki sürümleri.
Çalışma zamanı sınıfı nedir?
Çalışma zamanı sınıfı, genellikle yürütülebilir sınırlar boyunca modern COM arabirimleri aracılığıyla etkinleştirilebilen ve kullanılabilen bir türdür. Ancak, bir çalışma zamanı sınıfı bunu uygulayan derleme birimi içinde de kullanılabilir. Arabirim Tanım Dili'nde (IDL) bir çalışma zamanı sınıfı bildirirsiniz ve bunu C++/WinRT kullanarak standart C++ dilinde uygulayabilirsiniz.
Öngörülen tür ve uygulama türü ne anlama gelir?
Yalnızca bir Windows Çalışma Zamanı sınıfı (çalışma zamanı sınıfı) kullanıyorsanız, yalnızca öngörülen türlerle ilgilenirsiniz. C++/WinRT bir dil projeksiyonu olduğundan, yansıtılan türler C++/WinRT ile C++'a yansıtılan Windows Çalışma Zamanı yüzeyinin bir parçasıdır. Daha fazla ayrıntı için bkz . C++/WinRT ile API'leri kullanma.
Uygulama türü bir çalışma zamanı sınıfının uygulamasını içerdiğinden, yalnızca çalışma zamanı sınıfını uygulayan projede kullanılabilir. Çalışma zamanı sınıfları (Windows Çalışma Zamanı bileşen projesi veya XAML kullanıcı arabirimi kullanan bir proje) uygulayan bir projede çalışırken, çalışma zamanı sınıfı için uygulama türünüz ile C++/WinRT'ye yansıtılan çalışma zamanı sınıfını temsil eden öngörülen tür arasındaki ayrım konusunda rahat olmanız önemlidir. Diğer ayrıntılar için bkz. C++/WinRT ile API yazma.
Çalışma zamanı sınıfımın IDL'sinde bir oluşturucu bildirmem gerekiyor mu?
Yalnızca çalışma zamanı sınıfı, onu uygulayan derleme biriminin dışından kullanılmak üzere tasarlanmışsa (Windows Çalışma Zamanı istemci uygulamaları tarafından genel kullanıma sunulan bir Windows Çalışma Zamanı bileşenidir). IDL’de kurucu(lar) bildirmenin amacı ve sonuçlarına ilişkin tüm ayrıntılar için bkz. Çalışma zamanı sınıfı kurucuları.
Derleyici neden "C3779: consume_Something: 'auto' döndüren işlev tanımlanmadan önce kullanılamaz" hatası veriyor?
İlgili ad alanı başlık dosyasını önce eklemeden bir Windows Çalışma Zamanı nesnesi kullanıyorsunuz. API'nin ad alanının adını taşıyan başlık dosyasını ekleyin ve yeniden oluşturun. Daha fazla bilgi için bkz. C++/WinRT projeksiyon üst bilgileri.
Bağlayıcı neden bana "LNK2019: Çözülmemiş dış simge" hatası veriyor?
Çözümlenmemiş simge RoInitialize gibi Windows Çalışma Zamanı ücretsiz bir işlevse, projenizdeki WindowsApp.lib şemsiye kitaplığını açıkça bağlamanız gerekir. C++/WinRT projeksiyonu, bu ücretsiz (üye olmayan) işlevlerden ve giriş noktalarından bazılarına bağlıdır. Uygulamanız için C++/WinRT Visual Studio Uzantısı (VSIX) proje şablonlarından birini kullanıyorsanız, WindowsApp.lib sizin için otomatik olarak bağlanır. Aksi takdirde, proje bağlantısı ayarlarını kullanarak ekleyebilir veya bunu kaynak koduna yapabilirsiniz.
#pragma comment(lib, "windowsapp")
Alternatif statik bağlantı kitaplığı yerine WindowsApp.lib'i bağlayarak yapabileceğiniz bağlayıcı hatalarını çözmeniz önemlidir, aksi takdirde uygulamanız Visual Studio ve Microsoft Store tarafından kullanılan Windows Uygulaması Sertifika Seti testlerini geçirmez gönderimleri doğrulamak için (bunun sonucunda uygulamanızın Microsoft Store başarıyla alınması mümkün olmayacaktır).
Çözümlenmemiş simge bir oluşturucuysa, oluşturulmuş sınıfın ad alanı üst bilgi dosyasını eklemeyi unutmuş olabilirsiniz. Sınıfın ad alanıyla aynı adı taşıyan üst bilgi dosyasını ekleyin ve yeniden derleyin. Daha fazla bilgi için bkz. C++/WinRT projeksiyon üst bilgileri.
Neden "sınıf kayıtlı değil" hatasını alıyorum?
Bu durumda belirti şu şekildedir: çalışma zamanı sınıfı oluştururken veya statik bir üyeye erişirken, çalışma zamanında HRESULT değeri REGDB_E_CLASSNOTREGISTERED olan bir özel durumun oluşturulduğunu görürsünüz.
Bunun bir nedeni, Windows Çalışma Zamanı bileşeninizin yüklenememe olabilir. Bileşenin Windows Çalışma Zamanı meta veri dosyasının (.winmd), aynı zamanda projenin adı ve kök ad alanının adı olan bileşen ikili dosyasıyla (.dll) aynı ada sahip olduğundan emin olun. Ayrıca, Windows Çalışma Zamanı meta verilerinin ve ikili dosyanın derleme işlemi tarafından bunları kullanan uygulamanın Appx klasörüne doğru şekilde kopyalandığından emin olun. Ayrıca, kullanan uygulamanın AppxManifest.xml öğesinin (bu da Appx klasöründedir) etkinleştirilebilir sınıfı ve ikili adını doğru şekilde bildiren bir <InProcessServer> öğesi içerdiğini doğrulayın.
Tek biçimli oluşturma Bu hata, yerel olarak uygulanan bir çalışma zamanı sınıfının örneğini, yansıtılan türün oluşturucularından herhangi birini (std::nullptr_t oluşturucusu dışında) kullanarak oluşturmaya çalışırsanız da ortaya çıkabilir. Bunu yapmak için genellikle tekdüzen yapı olarak adlandırılan C++/WinRT 2.0 özelliği gerekir. Bu özelliği kabul etmek istiyorsanız, daha fazla bilgi ve kod örnekleri için bkz. Tekdüzen oluşturma ve doğrudan uygulama erişimini kabul etme.
Yerel olarak uyguladığınız çalışma zamanı sınıflarınızın tek tip oluşturma gerektirmeyen bir şekilde örneğini oluşturmak için bkz. XAML denetimleri; C++/WinRT özelliğine bağlama.
Windows::Foundation::IClosable öğesini uygulamalı mıyım ve öyleyse bunu nasıl yapmalıyım?
Yıkıcısında kaynakları serbest bırakan bir çalışma zamanı sınıfınız varsa ve bu çalışma zamanı sınıfı, uygulandığı derleme biriminin dışından kullanılmak üzere tasarlanmışsa (yani, Windows Çalışma Zamanı istemci uygulamaları tarafından genel olarak kullanılmak üzere tasarlanmış bir Windows Çalışma Zamanı bileşeniyse), deterministik sonlandırmayı desteklemeyen diller tarafından da kullanılabilmesini sağlamak için IClosable öğesini de uygulamanızı öneririz. Yıkıcı, IClosable::Close veya her ikisi de çağrılsa da kaynaklarınızın serbest olduğundan emin olun. IClosable::Close isteğe bağlı olarak birkaç kez çağrılabilir.
Kullandığım çalışma zamanı sınıfları için IClosable::Close çağrısı yapmam gerekiyor mu?
IClosable , belirlenimci sonlandırması olmayan dilleri desteklemek için mevcuttur. Bu nedenle, genel olarak, C++/WinRT'den IClosable::Close çağrısı yapmanız gerekmez. Ancak bu genel kuralın özel durumlarını göz önünde bulundurun.
- Kapatma yarışları veya yarı ölümcül kucaklamalar içeren çok nadir durumlar vardır, burada IClosable::Close çağrısı yapmanız gerekir. Örneğin, Windows.UI.Composition türlerini kullanıyorsanız, işi C++/WinRT sarmalayıcısının yok edilmesine bırakmak yerine nesneleri belirli bir sırayla elden çıkarmak isteyebileceğiniz durumlarla karşılaşabilirsiniz.
- Bir nesneye ait son kalan referansa sahip olduğunuzu garanti edemiyorsanız (çünkü onu, bir referansı tutuyor olabilecek başka API'lere ilettiniz), IClosable::Close çağırmak iyi bir fikirdir.
- Emin olmadığınızda, sarmalayıcının yok edilirken bunu çağırmasını beklemek yerine IClosable::Close yöntemini manuel olarak çağırmak daha güvenlidir.
Dolayısıyla, son referansa sahip olduğunuzu biliyorsanız, sarmalayıcının yıkıcısının işi yapmasına izin verebilirsiniz. Son referans ortadan kalkmadan önce kapatmanız gerekiyorsa, Close çağrısını yapmanız gerekir. İstisna güvenliği sağlamak için, Close işlemini bir resource-acquisition-is-initialization (RAII) türü içinde gerçekleştirmelisiniz (böylece stack açılırken kapatma gerçekleşir). C++/WinRT'nin unique_close sarmalayıcısı yoktur, ancak kendi sarmalayıcınızı oluşturabilirsiniz.
C++/WinRT ile derlemek için LLVM/Clang kullanabilir miyim?
C++/WinRT için LLVM ve Clang araç zincirini desteklemiyoruz, ancak C++/WinRT standartlarına uygunluğunu doğrulamak için şirket içinde kullanıyoruz. Örneğin, şirket içinde yaptıklarımıza öykünmek istiyorsanız aşağıda açıklanan gibi bir deneme deneyebilirsiniz.
LLVM İndirme Sayfasına gidin, LLVM 6.0.0>Önceden Oluşturulmuş İkili Dosyaları İndir'i arayın ve Windows (64 bit) için Clang'i indirin. Yükleme sırasında, bir komut isteminden çağırabilmeniz için LLVM'yi PATH sistem değişkenine eklemeyi tercih edin. Bu deneyin amaçları açısından, karşılaşırsanız "MSBuild araç kümeleri dizini bulunamadı" ve/veya "MSVC tümleştirme kurulumu başarısız oldu" hatalarını yok sayabilirsiniz. LLVM/Clang'yi çağırmanın çeşitli yolları vardır; Aşağıdaki örnekte yalnızca bir yol gösterilmektedir.
C:\ExperimentWithLLVMClang>type main.cpp
// main.cpp
#pragma comment(lib, "windowsapp")
#pragma comment(lib, "ole32")
#include <winrt/Windows.Foundation.h>
#include <stdio.h>
#include <iostream>
using namespace winrt;
int main()
{
winrt::init_apartment();
Windows::Foundation::Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
std::wcout << rssFeedUri.Domain().c_str() << std::endl;
}
C:\ExperimentWithLLVMClang>clang-cl main.cpp /EHsc /I ..\.. -Xclang -std=c++17 -Xclang -Wno-delete-non-virtual-dtor -o app.exe
C:\ExperimentWithLLVMClang>app
windows.com
C++/WinRT, C++17 standardının özelliklerini kullandığından, bu desteği almak için gereken derleyici bayraklarını kullanmanız gerekir; bu tür bayraklar bir derleyiciden diğerine farklılık gösterir.
Visual Studio, C++/WinRT için desteklediğimiz ve önerdiğimiz geliştirme aracıdır. Bkz. C++/WinRT için Visual Studio desteği.
Salt okunur bir özellik için oluşturulan implementasyon işlevi neden const niteleyicisine sahip değil?
MIDL 3.0'da salt okunur bir özellik bildirdiğinizde, cppwinrt.exe aracının sizin için const ile nitelenmiş bir uygulama işlevi oluşturmasını bekleyebilirsiniz (const bir işlev, this işaretçisini const olarak ele alır).
Mümkün olan her yerde const kullanmanızı kesinlikle öneririz, ancak cppwinrt.exe aracın kendisi hangi uygulama işlevlerinin mümkün olduğunca sabit olabileceği ve hangilerinin kullanılamayabileceği konusunda mantık yürütmeye çalışmaz. Bu örnekte olduğu gibi uygulama işlevlerinizden herhangi birini sabit hale getirebilirsiniz.
struct MyStringable : winrt::implements<MyStringable, winrt::Windows::Foundation::IStringable>
{
winrt::hstring ToString() const
{
return L"MyStringable";
}
};
Uygulamadaki bir nesne durumunu değiştirmeniz gerektiğine karar vermeniz durumunda const bu niteleyiciyi kaldırabilirsiniz. Ancak üye fonksiyonlarınızın her birini ya const ya da non-const olarak tanımlayın, ikisini birden değil. Başka bir deyişle, const üzerinde bir uygulama işlevi için aşırı yükleme yapmayın.
Uygulama işlevlerinizin yanı sıra, const'ın resme girdiği başka bir yer de Windows Çalışma Zamanı işlev projeksiyonlarındadır. Bu kodu göz önünde bulundurun.
int main()
{
winrt::Windows::Foundation::IStringable s{ winrt::make<MyStringable>() };
auto result{ s.ToString() };
}
Yukarıdaki ToString çağrısı için, Visual Studio’daki Bildirime Git komutu, Windows Çalışma Zamanı IStringable::ToString öğesinin C++/WinRT’ye izdüşümünün şöyle göründüğünü gösterir.
winrt::hstring ToString() const;
Projeksiyon üzerindeki fonksiyonlar, bunların uygulamasını nasıl nitelendirirseniz nitelendirin, const'tur. Arka planda, yansıtma uygulama ikili arabirimini (ABI) çağırır; bu da esasen bir COM arabirim işaretçisi üzerinden yapılan bir çağrıdır. Öngörülen ToString'in etkileşimde olduğu tek durum, COM arabirim işaretçisidir; ve kesinlikle bu işaretçiyi değiştirmesine gerek yoktur, bu nedenle işlev sabittir. Bu, çağrı yaptığınız IStringable referansıyla ilgili hiçbir şeyi değiştirmeyeceğine dair size güvence verir ve bir IStringable'a yönelik const referansla bile ToString’i çağırabilmenizi sağlar.
Bu örneklerin const C++/WinRT projeksiyonlarının ve uygulamalarının uygulama ayrıntıları olduğunu ve bunların sizin yararınıza kod hijyeni oluşturduğunu anlayın. COM veya Windows Çalışma Zamanı ABI'de (üye işlevleri için) const diye bir şey yoktur.
C++/WinRT ikili dosyalarının kod boyutunu azaltmaya yönelik önerileriniz var mı?
Windows Çalışma Zamanı nesnelerle çalışırken, aşağıda gösterilen kodlama deseninden kaçınmanız gerekir çünkü bu, oluşturulması gerekenden daha fazla ikili koda neden olarak uygulamanız üzerinde olumsuz bir etkiye sahip olabilir.
anobject.b().c().d();
anobject.b().c().e();
anobject.b().c().f();
Windows Çalışma Zamanı dünyasında, derleyici bir dolaylı ('.') aracılığıyla çağrılan her yöntemin değerini c() veya arabirimlerini önbelleğe alamaz. Müdahale etmezseniz, bu daha fazla sanal çağrıya ve referans sayımı ek yüküne yol açar. Yukarıdaki desen, kesinlikle gerekenin iki katı kadar kodu kolayca oluşturabilir. Bunun yerine, mümkün olan her yerde aşağıda gösterilen deseni tercih edin. Çok daha az kod oluşturur ve çalışma süresi performansınızı önemli ölçüde artırabilir.
auto a{ anobject.b().c() };
a.d();
a.e();
a.f();
Yukarıda gösterilen önerilen desen yalnızca C++/WinRT için değil tüm Windows Çalışma Zamanı dil projeksiyonları için geçerlidir.
Bir dizeyi bir türe nasıl dönüştürebilirim (örneğin gezinti için)?
Gezinti görünümü kod örneğinin (çoğunlukla C# dilindedir) sonunda, bunun nasıl yapıldığını gösteren bir C++/WinRT kod parçacığı vardır.
GetCurrentTime ve/veya TRY ile belirsizlikleri nasıl çözebilirim?
Üst bilgi dosyası winrt/Windows.UI.Xaml.Media.Animation.hGetCurrentTime adlı bir yöntem bildirirken windows.h (aracılığıyla winbase.h) GetCurrentTime adlı bir makro tanımlar. Bu ikisi çakıştığında, C++ derleyicisi "hata C4002: GetCurrentTime işlev benzeri makro çağrısı için çok fazla bağımsız değişken" üretir.
Benzer şekilde, winrt/Windows.Globalization.hTRY adlı bir yöntem bildirirken afx.hTRY adlı bir makro tanımlar. Bunlar çakıştığında, C++ derleyicisi "hata C2334: '{' öncesinde beklenmeyen belirteçler; görünen işlev gövdesi atlanıyor".
Bir veya iki sorunu çözmek için bunu yapabilirsiniz.
#pragma push_macro("GetCurrentTime")
#pragma push_macro("TRY")
#undef GetCurrentTime
#undef TRY
#include <winrt/include_your_cppwinrt_headers_here.h>
#include <winrt/include_your_cppwinrt_headers_here.h>
#pragma pop_macro("TRY")
#pragma pop_macro("GetCurrentTime")
Sembol yüklemeyi nasıl hızlandırebilirim?
Visual Studio'da, Araçlar>Seçenekler>Hata Ayıklama>Simgeler> bölümünde Yalnızca belirtilen modülleri yükle seçeneğini işaretleyin. Ardından yığın listesinde DLL'lere sağ tıklayabilir ve modülleri tek tek yükleyebilirsiniz.
Note
Bu konu sorunuzu yanıtlamadıysa, Visual Studio C++ geliştirici topluluğunu ziyaret ederek veya Stack Overflow'da etiketini kullanarakc++-winrt yardım bulabilirsiniz.