Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Topik ini menunjukkan cara menggunakan API C++/WinRT, baik itu bagian dari Windows, diimplementasikan oleh vendor komponen pihak ketiga, atau diimplementasikan sendiri.
Important
Sehingga contoh kode dalam topik ini singkat, dan mudah dicoba, Anda dapat mereproduksinya dengan membuat proyek Windows Console Application (C++/WinRT) baru, dan kode copy-pasting. Namun, Anda tidak dapat menggunakan jenis kustom Windows Runtime sembarang (pihak ketiga) dari aplikasi yang belum dikemas seperti itu. Anda hanya dapat menggunakan tipe Windows dengan cara itu.
Untuk menggunakan jenis Windows Runtime kustom (pihak ketiga) dari aplikasi konsol, Anda harus memberi aplikasi identitas paket sehingga dapat menyelesaikan pendaftaran jenis kustom yang digunakan. Untuk informasi selengkapnya, lihat Windows Application Packaging Project.
Atau, buat proyek baru dari templat proyek Blank App, Packaged (WinUI 3 in Desktop) untuk C++ atau Windows Runtime Component (C++/WinRT). Jenis aplikasi tersebut sudah memiliki identitas paket.
Jika API berada di namespace Windows
Ini adalah kasus paling umum di mana Anda akan menggunakan API Windows Runtime. Untuk setiap tipe dalam namespace Windows yang didefinisikan dalam metadata, C++/WinRT mendefinisikan padanan yang ramah terhadap C++ (disebut tipe terproyeksi). Jenis yang diproyeksikan memiliki nama yang sepenuhnya memenuhi syarat yang sama dengan jenis Windows, tetapi ditempatkan di namespace C++ winrt menggunakan sintaks C++. Misalnya, Windows::Foundation::Uri diproyeksikan ke dalam C++/WinRT sebagai winrt::Windows::Foundation::Uri.
Berikut adalah contoh kode sederhana. Jika Anda ingin menyalin-tempel contoh kode berikut langsung ke file kode sumber utama proyek aplikasi konsol Windows (C++/WinRT), maka pertama-tama atur Tidak Menggunakan Header yang Telah Dikompilasi sebelumnya di properti proyek.
// main.cpp
#include <winrt/Windows.Foundation.h>
using namespace winrt;
using namespace Windows::Foundation;
int main()
{
winrt::init_apartment();
Uri contosoUri{ L"http://www.contoso.com" };
Uri combinedUri = contosoUri.CombineUri(L"products");
}
Header winrt/Windows.Foundation.h yang disertakan adalah bagian dari SDK, ditemukan di dalam folder %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\. Berkas header dalam folder tersebut berisi jenis namespace Windows yang diproyeksikan ke C++/WinRT. Dalam contoh ini, winrt/Windows.Foundation.h berisi winrt::Windows::Foundation::Uri, yang merupakan jenis yang diproyeksikan untuk kelas runtime Windows::Foundation::Uri.
Tip
Setiap kali Anda ingin menggunakan jenis dari namespace Windows, sertakan header C++/WinRT yang sesuai dengan namespace tersebut. Direktif using namespace bersifat opsional, tetapi nyaman.
Dalam contoh kode di atas, setelah menginisialisasi C++/WinRT, kita mengalokasikan sebuah nilai dari tipe terproyeksi winrt::Windows::Foundation::Uri di stack melalui salah satu konstruktor publik yang terdokumentasi (Uri(String), dalam contoh ini). Untuk kasus penggunaan yang paling umum ini, biasanya hanya itu yang perlu Anda lakukan. Setelah Anda memiliki nilai tipe proyeksi C++/WinRT, Anda dapat memperlakukannya seolah-olah merupakan instans dari tipe Windows Runtime yang sebenarnya, karena memiliki semua anggota yang sama.
Faktanya, nilai yang diproyeksikan itu adalah sebuah proksi; pada dasarnya, itu hanyalah smart pointer ke objek pendukung. Konstruktor nilai yang diproyeksikan memanggil RoActivateInstance untuk membuat instans kelas Windows Runtime backing (Windows. Foundation.Uri, dalam hal ini), dan simpan antarmuka default objek tersebut di dalam nilai yang diproyeksikan baru. Seperti yang diilustrasikan di bawah ini, pemanggilan anggota nilai proyeksi oleh Anda sebenarnya diteruskan, melalui pointer cerdas, ke objek pendukung; di sanalah perubahan keadaan terjadi.
Ketika nilai contosoUri keluar dari cakupan, nilai tersebut akan didestruksi dan melepaskan referensinya ke antarmuka default. Jika referensi tersebut adalah referensi terakhir ke objek Windows.Foundation.Uri Windows Runtime pendukung, objek pendukung itu juga akan dihancurkan.
Tip
Tipe terproyeksi adalah pembungkus untuk tipe Windows Runtime agar API-nya dapat digunakan. Misalnya, antarmuka terproyeksi merupakan pembungkus untuk antarmuka Windows Runtime.
Header proyeksi C++/WinRT
Untuk menggunakan API namespace Windows dari C++/WinRT, Anda menyertakan header dari folder %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt. Anda harus menyertakan header yang sesuai dengan setiap namespace yang Anda gunakan.
Misalnya, untuk Windows::Security::Cryptography::Certificates namespace, definisi jenis C++/WinRT yang setara berada di winrt/Windows.Security.Cryptography.Certificates.h. Menyertakan header tersebut memberikan Anda akses ke semua tipe dalam namespace Windows::Security::Cryptography::Certificates.
Terkadang, satu header namespace akan menyertakan bagian header namespace terkait, tetapi Anda tidak boleh mengandalkan detail implementasi ini. Sertakan header secara eksplisit untuk namespace yang Anda gunakan.
Misalnya, metode Certificate::GetCertificateBlob mengembalikan antarmuka Windows::Storage::Streams::IBuffer.
Sebelum memanggil metode Certificate::GetCertificateBlob, Anda harus menyertakan file header namespace winrt/Windows.Storage.Streams.h untuk memastikan bahwa Anda dapat menerima dan mengoperasikan Windows::Storage::Streams::IBuffer yang dikembalikan.
Lupa menyertakan header namespace yang diperlukan sebelum menggunakan jenis di namespace tersebut adalah sumber umum kesalahan build.
Mengakses anggota melalui objek, melalui antarmuka, atau melalui ABI
Dengan proyeksi C++/WinRT, representasi runtime kelas Windows Runtime tidak lebih dari antarmuka ABI yang mendasarinya. Namun, demi kenyamanan Anda, Anda dapat menulis kode menggunakan kelas sebagaimana dimaksud oleh pembuatnya. Misalnya, Anda dapat memanggil metode ToString dari Uri seolah-olah metode itu adalah metode dari kelas tersebut (sebenarnya, di balik layar, metode itu merupakan metode pada antarmuka IStringable yang terpisah).
WINRT_ASSERT adalah definisi makro, dan meluas ke _ASSERTE.
Uri contosoUri{ L"http://www.contoso.com" };
WINRT_ASSERT(contosoUri.ToString() == L"http://www.contoso.com/"); // QueryInterface is called at this point.
Kenyamanan ini dicapai melalui kueri untuk antarmuka yang sesuai. Tapi kau selalu memegang kendali. Anda dapat memilih untuk mengorbankan sedikit kemudahan itu demi sedikit peningkatan performa dengan mengambil sendiri antarmuka IStringable dan menggunakannya secara langsung. Dalam contoh kode di bawah ini, Anda memperoleh penunjuk antarmuka IStringable yang sebenarnya saat dijalankan (melalui kueri sekali saja). Setelah itu, panggilan Anda ke ToString langsung, dan menghindari panggilan lebih lanjut ke QueryInterface.
...
IStringable stringable = contosoUri; // One-off QueryInterface.
WINRT_ASSERT(stringable.ToString() == L"http://www.contoso.com/");
Anda dapat memilih teknik ini jika Anda tahu bahwa Anda akan memanggil beberapa metode pada antarmuka yang sama.
Sebagai tambahan, jika Anda memang ingin mengakses anggota pada level ABI, Anda bisa melakukannya. Contoh kode di bawah ini menunjukkan caranya, dan ada detail lebih lanjut dan contoh kode di Interop antara C++/WinRT dan ABI.
#include <Windows.Foundation.h>
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
using namespace winrt::Windows::Foundation;
int main()
{
winrt::init_apartment();
Uri contosoUri{ L"http://www.contoso.com" };
int port{ contosoUri.Port() }; // Access the Port "property" accessor via C++/WinRT.
winrt::com_ptr<ABI::Windows::Foundation::IUriRuntimeClass> abiUri{
contosoUri.as<ABI::Windows::Foundation::IUriRuntimeClass>() };
HRESULT hr = abiUri->get_Port(&port); // Access the get_Port ABI function.
}
Inisialisasi tertunda
Di C++/WinRT, setiap jenis yang diproyeksikan memiliki konstruktor C++/WinRT std::nullptr_t khusus. Kecuali yang satu itu, semua konstruktor tipe terproyeksi—termasuk konstruktor default—menyebabkan objek Windows Runtime pendukung dibuat dan memberikan penunjuk cerdas ke objek tersebut. Jadi, aturan itu berlaku di mana saja konstruktor default digunakan, seperti variabel lokal yang tidak diinisialisasi, variabel global yang tidak diinisialisasi, dan variabel anggota yang tidak diinisialisasi.
Jika, di sisi lain, Anda ingin membuat variabel dari tipe terproyeksi tanpa sekaligus membuat objek Windows Runtime pendukungnya (sehingga Anda dapat menunda proses tersebut hingga nanti), maka Anda dapat melakukannya. Deklarasikan variabel atau bidang Anda menggunakan konstruktor khusus C++/WinRT std::nullptr_t (yang disuntikkan proyeksi C++/WinRT ke setiap kelas runtime). Kami menggunakan konstruktor khusus tersebut dengan m_gamerPicBuffer dalam contoh kode di bawah ini.
#include <winrt/Windows.Storage.Streams.h>
using namespace winrt::Windows::Storage::Streams;
#define MAX_IMAGE_SIZE 1024
struct Sample
{
void DelayedInit()
{
// Allocate the actual buffer.
m_gamerPicBuffer = Buffer(MAX_IMAGE_SIZE);
}
private:
Buffer m_gamerPicBuffer{ nullptr };
};
int main()
{
winrt::init_apartment();
Sample s;
// ...
s.DelayedInit();
}
Semua konstruktor pada tipe terproyeksi kecuali konstruktor std::nullptr_t akan membuat objek Windows Runtime pendukung. Konstruktor std::nullptr_t pada dasarnya adalah no-op. Ini mengharapkan objek yang diproyeksikan untuk diinisialisasi pada waktu berikutnya. Jadi, apakah kelas runtime memiliki konstruktor default atau tidak, Anda dapat menggunakan teknik ini untuk inisialisasi tertunda yang efisien.
Pertimbangan ini memengaruhi tempat lain di mana Anda memanggil konstruktor default, seperti di vektor dan peta. Pertimbangkan contoh kode ini, yang mengharuskan Anda menggunakan Blank App, Packaged (WinUI 3 in Desktop) untuk proyek C++.
std::map<int, TextBlock> lookup;
lookup[2] = value;
Penugasan membuat TextBlock baru, lalu segera menimpanya dengan value. Berikut obatnya.
std::map<int, TextBlock> lookup;
lookup.insert_or_assign(2, value);
Lihat juga Bagaimana konstruktor default memengaruhi koleksi.
Jangan menunda-inisialisasi secara tidak sengaja
Berhati-hatilah agar Anda tidak memanggil konstruktor std::nullptr_t secara tidak sengaja. Dalam resolusi konflik, kompilator lebih mengutamakannya daripada konstruktor pabrik. Misalnya, pertimbangkan dua definisi kelas runtime ini.
// GiftBox.idl
runtimeclass GiftBox
{
GiftBox();
}
// Gift.idl
runtimeclass Gift
{
Gift(GiftBox giftBox); // You can create a gift inside a box.
}
Katakanlah kita ingin membuat Hadiah yang tidak berada di dalam kotak (Hadiah yang dibuat dengan GiftBox yang belum diinisialisasi). Pertama, mari kita lihat cara yang salah untuk melakukan itu. Kita tahu bahwa ada konstruktor Hadiah yang menerima GiftBox. Tetapi jika kita tergoda untuk meneruskan GiftBox bernilai null (memanggil konstruktor Gift melalui uniform initialization, seperti yang kita lakukan di bawah), maka kita tidak akan mendapatkan hasil yang kita inginkan.
// These are *not* what you intended. Doing it in one of these two ways
// actually *doesn't* create the intended backing Windows Runtime Gift object;
// only an empty smart pointer.
Gift gift{ nullptr };
auto gift{ Gift(nullptr) };
Apa yang Anda dapatkan di sini adalah Hadiah yang tidak diinisialisasi. Anda tidak akan mendapatkan Hadiah dari GiftBox yang belum diinisialisasi. Berikut adalah cara yang benar untuk melakukan itu.
// Doing it in one of these two ways creates an initialized
// Gift with an uninitialized GiftBox.
Gift gift{ GiftBox{ nullptr } };
auto gift{ Gift(GiftBox{ nullptr }) };
Dalam contoh yang keliru, memberikan literal nullptr akan memilih konstruktor inisialisasi tertunda. Untuk mengatasi mendukung konstruktor pabrik, jenis parameter harus berupa GiftBox. Anda masih memiliki opsi untuk meneruskan GiftBox yang diinisialisasi secara tertunda secara eksplisit, seperti yang ditunjukkan dalam contoh yang tepat.
Contoh berikutnya ini juga benar, karena parameter memiliki jenis GiftBox, dan bukan std::nullptr_t.
GiftBox giftBox{ nullptr };
Gift gift{ giftBox }; // Calls factory constructor.
Ambiguitas hanya muncul ketika Anda meneruskan literal nullptr.
Jangan menyalin konstruksi secara tidak sengaja.
Peringatan ini serupa dengan yang dijelaskan di bagian Jangan keliru menunda inisialisasi di atas.
Selain konstruktor inisialisasi tertunda, proyeksi C++/WinRT juga menambahkan konstruktor salinan ke setiap kelas runtime. Ini adalah konstruktor parameter tunggal yang menerima jenis yang sama dengan objek yang sedang dibangun. Pointer pintar yang dihasilkan menunjuk ke objek Windows Runtime dukungan yang sama seperti yang ditunjukkan oleh parameter konstruktornya. Hasilnya adalah dua objek penunjuk cerdas yang menunjuk ke objek dasar yang sama.
Berikut adalah definisi kelas runtime yang akan kita gunakan dalam contoh kode.
// GiftBox.idl
runtimeclass GiftBox
{
GiftBox(GiftBox biggerBox); // You can place a box inside a bigger box.
}
Katakanlah kita ingin membuat GiftBox di dalam GiftBox yang lebih besar.
GiftBox bigBox{ ... };
// These are *not* what you intended. Doing it in one of these two ways
// copies bigBox's backing-object-pointer into smallBox.
// The result is that smallBox == bigBox.
GiftBox smallBox{ bigBox };
auto smallBox{ GiftBox(bigBox) };
Cara yang benar untuk melakukannya adalah dengan memanggil pabrik aktivasi secara eksplisit.
GiftBox bigBox{ ... };
// These two ways call the activation factory explicitly.
GiftBox smallBox{
winrt::get_activation_factory<GiftBox, IGiftBoxFactory>().CreateInstance(bigBox) };
auto smallBox{
winrt::get_activation_factory<GiftBox, IGiftBoxFactory>().CreateInstance(bigBox) };
Jika API diimplementasikan dalam komponen Windows Runtime
Bagian ini menerapkan apakah Anda menulis komponen sendiri, atau berasal dari vendor.
Note
Untuk informasi tentang menginstal dan menggunakan C++/WinRT Visual Studio Extension (VSIX) dan paket NuGet (yang bersama-sama menyediakan templat proyek dan dukungan build), lihat dukungan Visual Studio untuk C++/WinRT.
Dalam proyek aplikasi Anda, tambahkan referensi ke file metadata Windows Runtime (.winmd) milik komponen Windows Runtime, lalu bangun proyek. Selama proses build, alat cppwinrt.exe menghasilkan pustaka C++ standar yang mendeskripsikan—atau memproyeksikan—surface API komponen secara lengkap. Dengan kata lain, pustaka yang dihasilkan berisi jenis yang diproyeksikan untuk komponen.
Kemudian, sama seperti untuk jenis namespace Windows, Anda menyertakan header dan membuat jenis yang diproyeksikan melalui salah satu konstruktornya. Kode startup proyek aplikasi Anda mendaftarkan kelas runtime, dan konstruktor jenis yang diproyeksikan memanggil RoActivateInstance untuk mengaktifkan kelas runtime dari komponen yang direferensikan.
#include <winrt/ThermometerWRC.h>
struct App : AppT<App>
{
ThermometerWRC::Thermometer thermometer;
...
};
Untuk detail lebih lanjut, kode, dan panduan langkah demi langkah untuk menggunakan API yang diimplementasikan dalam komponen Windows Runtime, lihat Windows Runtime components with C++/WinRT dan Author events in C++/WinRT.
Jika API diimplementasikan dalam proyek konsumen
Contoh kode di bagian ini diambil dari topik kontrol XAML; ikat ke properti C++/WinRT. Lihat topik tersebut untuk detail, kode, dan panduan langkah demi langkah lebih lanjut tentang cara menggunakan kelas runtime yang diimplementasikan dalam proyek yang sama yang menggunakannya.
Jenis yang digunakan dari UI XAML harus berupa kelas runtime, meskipun jenis tersebut berada dalam proyek yang sama dengan XAML. Untuk skenario ini, Anda membuat tipe proyeksi dari metadata Windows Runtime milik kelas runtime (.winmd). Sekali lagi, Anda menyertakan header, tetapi kemudian Anda memiliki pilihan antara cara C++/WinRT versi 1.0 atau versi 2.0 untuk membangun instans kelas runtime. Metode versi 1.0 menggunakan winrt::make; metode versi 2.0 dikenal sebagai konstruksi seragam. Mari kita lihat masing-masing secara bergantian.
Membangun dengan menggunakan winrt::make
Mari kita mulai dengan metode default (C++/WinRT versi 1.0), karena ada baiknya setidaknya terbiasa dengan pola tersebut. Anda membangun tipe yang diproyeksikan melalui konstruktor std::nullptr_t miliknya. Konstruktor tersebut tidak melakukan inisialisasi apa pun, jadi Anda selanjutnya harus menetapkan nilai ke instans melalui fungsi winrt::make helper, meneruskan argumen konstruktor yang diperlukan. Kelas runtime yang diimplementasikan dalam proyek yang sama dengan kode yang menggunakannya tidak perlu didaftarkan maupun diinstansiasi melalui aktivasi Windows Runtime/COM.
Lihat kontrol XAML; ikat ke properti C++/WinRT untuk panduan lengkap. Bagian ini menunjukkan ekstrak dari panduan tersebut.
// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
BookstoreViewModel MainViewModel{ get; };
}
}
// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
...
private:
Bookstore::BookstoreViewModel m_mainViewModel{ nullptr };
};
...
// MainPage.cpp
...
#include "BookstoreViewModel.h"
MainPage::MainPage()
{
m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();
...
}
Konstruksi seragam
Dengan C++/WinRT versi 2.0 dan yang lebih baru, ada bentuk konstruksi yang dioptimalkan yang tersedia untuk Anda yang dikenal sebagai konstruksi seragam (lihat Berita, dan perubahan, di C++/WinRT 2.0).
Lihat kontrol XAML; ikat ke properti C++/WinRT untuk panduan lengkap. Bagian ini menunjukkan ekstrak dari panduan tersebut.
Untuk menggunakan konstruksi seragam alih-alih winrt::make, Anda memerlukan pabrik aktivasi. Cara yang baik untuk membuat salah satunya adalah dengan menambahkan konstruktor ke IDL Anda.
// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
MainPage();
BookstoreViewModel MainViewModel{ get; };
}
}
Kemudian, di dalam MainPage.h, deklarasikan dan inisialisasi m_mainViewModel hanya dalam satu langkah, seperti ditunjukkan di bawah ini.
// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
...
private:
Bookstore::BookstoreViewModel m_mainViewModel;
...
};
}
...
Dan kemudian, di konstruktor MainPage di MainPage.cpp, tidak perlu kode m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.
Untuk informasi selengkapnya tentang konstruksi seragam, dan contoh kode, lihat Ikut serta dalam konstruksi seragam, dan akses implementasi langsung.
Membuat instans dan mengembalikan tipe serta antarmuka proyeksi
Berikut adalah contoh tampilan jenis dan antarmuka yang diproyeksikan dalam proyek konsumsi Anda. Ingatlah bahwa tipe hasil proyeksi (seperti pada contoh ini) dibuat secara otomatis oleh alat, dan bukan sesuatu yang Anda tulis sendiri.
struct MyRuntimeClass : MyProject::IMyRuntimeClass, impl::require<MyRuntimeClass,
Windows::Foundation::IStringable, Windows::Foundation::IClosable>
MyRuntimeClass adalah jenis yang diproyeksikan; Antarmuka yang diproyeksikan termasuk IMyRuntimeClass, IStringable, dan IClosable. Topik ini menjelaskan berbagai cara untuk membuat instans dari jenis yang diproyeksikan. Berikut adalah pengingat dan ringkasan, menggunakan MyRuntimeClass sebagai contoh.
// The runtime class is implemented in another compilation unit (it's either a Windows API,
// or it's implemented in a second- or third-party component).
MyProject::MyRuntimeClass myrc1;
// The runtime class is implemented in the same compilation unit.
MyProject::MyRuntimeClass myrc2{ nullptr };
myrc2 = winrt::make<MyProject::implementation::MyRuntimeClass>();
- Anda dapat mengakses anggota dari semua antarmuka dari jenis yang diproyeksikan.
- Anda dapat mengembalikan tipe terproyeksi kepada pemanggil.
- Jenis dan antarmuka yang diproyeksikan berasal dari winrt::Windows::Foundation::IUnknown. Jadi, Anda dapat memanggil IUnknown::as pada tipe atau antarmuka terproyeksi untuk menanyakan antarmuka terproyeksi lain, yang juga dapat Anda gunakan atau kembalikan kepada pemanggil. Fungsi sebagai anggota berfungsi seperti QueryInterface.
void f(MyProject::MyRuntimeClass const& myrc)
{
myrc.ToString();
myrc.Close();
IClosable iclosable = myrc.as<IClosable>();
iclosable.Close();
}
Pabrik aktivasi
Cara langsung yang nyaman untuk membuat objek C++/WinRT adalah sebagai berikut.
using namespace winrt::Windows::Globalization::NumberFormatting;
...
CurrencyFormatter currency{ L"USD" };
Tetapi mungkin ada kalanya Anda ingin membuat pabrik aktivasi sendiri, lalu membuat objek darinya sesuai keinginan Anda. Berikut adalah beberapa contoh yang menunjukkan caranya, menggunakan templat fungsi winrt::get_activation_factory .
using namespace winrt::Windows::Globalization::NumberFormatting;
...
auto factory = winrt::get_activation_factory<CurrencyFormatter, ICurrencyFormatterFactory>();
CurrencyFormatter currency = factory.CreateCurrencyFormatterCode(L"USD");
using namespace winrt::Windows::Foundation;
...
auto factory = winrt::get_activation_factory<Uri, IUriRuntimeClassFactory>();
Uri uri = factory.CreateUri(L"http://www.contoso.com");
Kelas dalam dua contoh di atas adalah jenis dari namespace Windows. Dalam contoh berikutnya, ThermometerWRC::Thermometer adalah jenis kustom yang diimplementasikan dalam komponen Windows Runtime.
auto factory = winrt::get_activation_factory<ThermometerWRC::Thermometer>();
ThermometerWRC::Thermometer thermometer = factory.ActivateInstance<ThermometerWRC::Thermometer>();
Ambiguitas Anggota/Jenis
Ketika fungsi anggota memiliki nama yang sama dengan tipe, terjadi ambiguitas. Aturan untuk pencarian nama C++ tanpa kualifikasi dalam fungsi anggota menyebabkannya mencari di kelas sebelum mencari di namespace. Aturan kegagalan substitusi bukanlah kesalahan (SFINAE) tidak berlaku (aturan ini berlaku saat resolusi overload templat fungsi). Jadi jika nama di dalam kelas tidak masuk akal, pengkompilasi tidak terus mencari kecocokan yang lebih baik—itu hanya melaporkan kesalahan.
struct MyPage : Page
{
void DoWork()
{
// This doesn't compile. You get the error
// "'winrt::Windows::Foundation::IUnknown::as':
// no matching overloaded function found".
auto style{ Application::Current().Resources().
Lookup(L"MyStyle").as<Style>() };
}
}
Di atas, pengompilasi menganggap bahwa Anda meneruskan FrameworkElement.Style() (yang, dalam C++/WinRT, merupakan fungsi anggota) sebagai parameter templat untuk IUnknown::as. Solusinya adalah memaksa nama Style untuk ditafsirkan sebagai jenis Microsoft::UI::Xaml::Style.
struct MyPage : Page
{
void DoWork()
{
// One option is to fully-qualify it.
auto style{ Application::Current().Resources().
Lookup(L"MyStyle").as<Microsoft::UI::Xaml::Style>() };
// Another is to force it to be interpreted as a struct name.
auto style{ Application::Current().Resources().
Lookup(L"MyStyle").as<struct Style>() };
// If you have "using namespace Windows::UI;", then this is sufficient.
auto style{ Application::Current().Resources().
Lookup(L"MyStyle").as<Xaml::Style>() };
// Or you can force it to be resolved in the global namespace (into which
// you imported the Microsoft::UI::Xaml namespace when you did
// "using namespace Microsoft::UI::Xaml;".
auto style = Application::Current().Resources().
Lookup(L"MyStyle").as<::Style>();
}
}
Pencarian nama yang tidak memenuhi syarat memiliki pengecualian khusus jika nama diikuti oleh ::, dalam hal ini mengabaikan fungsi, variabel, dan nilai enum. Ini memungkinkan Anda untuk melakukan hal-hal seperti ini.
struct MyPage : Page
{
void DoSomething()
{
Visibility(Visibility::Collapsed); // No ambiguity here (special exception).
}
}
Panggilan ke Visibility() mengarah ke nama fungsi anggota UIElement.Visibility. Tetapi parameter Visibility::Collapsed mengikuti kata Visibility dengan ::, sehingga nama metode diabaikan, dan pengkompilasi menemukan kelas enum.
API penting
- Fungsi QueryInterface
- Fungsi RoActivateInstance
- kelas Windows::Foundation::Uri
- templat fungsi winrt::get_activation_factory
- winrt::buat templat fungsi
- winrt::Windows::Foundation::IUnknown struct
Topik terkait
Windows developer