Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a témakör bemutatja, hogyan használhatja fel a C++/WinRT API-kat, függetlenül attól, hogy azok a Windows részei, egy külső gyártó által implementált vagy saját maga által implementált api-k.
Fontos
Annak érdekében, hogy a jelen témakörben szereplő kódpéldák rövidek és könnyen kipróbálhatók legyenek, reprodukálhatja őket egy új Windows konzolalkalmazási (C++/WinRT) projekt létrehozásával és a kód másolásával. Azonban nem használhat tetszőleges egyéni (harmadik féltől származó) Windows-futtatókörnyezet típusokat egy ilyen csomagolatlan alkalmazásból. Így csak Windows-típusokat használhat.
Ha egyéni (harmadik féltől származó) Windows-futtatókörnyezet-típusokat szeretne használni egy konzolalkalmazásból, meg kell adnia az alkalmazásnak egy csomagdentitást, hogy az feloldhassa a felhasznált egyéni típusok regisztrációját. További információ: Windows Application Packaging Project.
Másik lehetőségként hozzon létre egy új projektet a C++-hoz készült Blank App, Packaged (WinUI 3 in Desktop) vagy a Windows-futtatókörnyezet-összetevő (C++/WinRT) projektsablonból. Ezek az alkalmazástípusok már rendelkeznek csomagidentitással.
Ha az API egy Windows névtérben van
Ez a leggyakoribb eset, amikor egy Windows-futtatókörnyezet API-t fog használni. A metaadatokban definiált Windows névtér minden típusához a C++/WinRT egy C++-felhasználóbarát megfelelőt (az úgynevezett előrejelzett típust) határoz meg. Az előrejelzett típusnak ugyanaz a teljes neve, mint a Windows típusnak, de a C++ winrt névtérben van elhelyezve C++ szintaxissal. Például Windows::Foundation::Uri a C++/WinRT-ben winrt::Windows::Foundation::Uri alakban képeződik le.
Íme egy egyszerű példa a kódra. Ha a következő kódpéldákat közvetlenül egy Windows Konzolalkalmazás (C++/WinRT) projekt fő forráskódfájljába szeretné beilleszteni, először állítsa be a Nem előre összeállított fejléceket a projekttulajdonságokban.
// 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");
}
A belefoglalt fejléc winrt/Windows.Foundation.h az SDK része, amely a mappában %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\található. A mappában lévő fejlécek Windows C++/WinRT-be vetített névtértípusokat tartalmaznak. Ebben a példában a(z) winrt/Windows.Foundation.h a winrt::Windows::Foundation::Uri elemet tartalmazza, amely a Windows::Foundation::Uri futtatókörnyezeti osztály leképezett típusa.
Tipp
Ha Windows névtérből szeretne típust használni, adja meg az adott névtérnek megfelelő C++/WinRT fejlécet. Az using namespace irányelvek nem kötelezőek, de kényelmesek.
A fenti kódpéldában a C++/WinRT inicializálása után a winrt::Windows::Foundation::Uri által előrejelzett típus értékét az egyik nyilvánosan dokumentált konstruktoron (Uri(Sztring) keresztül foglaljuk le ebben a példában). Ehhez, a leggyakoribb használati esethez, általában csak ennyit kell tennie. Ha már rendelkezik C++/WinRT-előrejelzett típusértékmel, úgy kezelheti, mintha a tényleges Windows-futtatókörnyezet típusú példány lenne, mivel az összes taggal rendelkezik.
Az előre jelzett érték valójában proxy; ez lényegében csak egy intelligens mutató egy háttérobjektumhoz. A kivetített érték konstruktora(i) meghívják a RoActivateInstance-t a háttérrendszeri Windows-futtatókörnyezet osztály (Windows) egy példányának létrehozásához. Foundation.Uri, ebben az esetben), és tárolja az objektum alapértelmezett felületét az új előre jelzett értéken belül. Ahogy alább látható, a projektált érték tagjain végzett hívások valójában az intelligens mutatón keresztül a háttérobjektumhoz delegálódnak; itt történnek az állapotváltozások.
Amikor a contosoUri érték kikerül a hatókörből, megsemmisül, és elengedi az alapértelmezett felületre mutató hivatkozását. Ha ez a hivatkozás az utolsó hivatkozás a mögöttes Windows-futtatókörnyezet Windows.Foundation.Uri objektumra, a mögöttes objektum is megsemmisül.
Tipp
A leképezett típus egy Windows-futtatókörnyezet típust burkoló elem, amely annak API-jainak használatát szolgálja. A kivetített felület például egy Windows-futtatókörnyezet felület burkolója.
C++/WinRT-vetítés fejlécei
A C++/WinRT-ből származó Windows névtér API-k felhasználásához a mappából származó %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt fejléceket kell tartalmaznia. Minden használt névtérnek megfelelő fejléceket kell tartalmaznia.
Például a Windows::Security::Titkosítás::Tanúsítványok névterében a megfelelő C++/WinRT típusdefiníciók találhatók.winrt/Windows.Security.Cryptography.Certificates.h A fejlécet is beleértve hozzáférést biztosít a Windows::Security::Cryptography::Certificates névtér összes típusához.
Előfordulhat, hogy egy névtérfejléc a kapcsolódó névtérfejlécek egyes részeit tartalmazza, de nem szabad erre a megvalósítási részletre támaszkodnia. Explicit módon adja meg a használt névterek fejléceit.
A Tanúsítvány::GetCertificateBlob metódus például egy Windows::Storage::Streams::IBuffer interfészt ad vissza.
A Certificate::GetCertificateBlob metódus meghívása előtt bele kell foglalnia a winrt/Windows.Storage.Streams.h névtérhez tartozó fejlécfájlt, hogy fogadni tudja, és műveleteket tudjon végezni a visszaadott Windows::Storage::Streams::IBuffer objektumon.
A buildelési hibák gyakori forrása, ha elfelejti belefoglalni a szükséges névtérfejléceket, mielőtt típusokat használ az adott névtérben.
Tagok elérése az objektumon, a felületen vagy az ABI-n keresztül
A C++/WinRT-vetítéssel egy Windows-futtatókörnyezet osztály futtatókörnyezeti ábrázolása nem több, mint az alapul szolgáló ABI-interfészek. Az Ön kényelme érdekében azonban a szerző által tervezett módon kódozhatja az osztályokat. Egy UriToString metódusát például úgy hívhatja meg, mintha az az osztály egyik metódusa lenne (valójában a borítók alatt ez egy metódus a külön IStringable felületen).
WINRT_ASSERT egy makródefiníció, és _ASSERTE kifejezésre bontódik ki.
Uri contosoUri{ L"http://www.contoso.com" };
WINRT_ASSERT(contosoUri.ToString() == L"http://www.contoso.com/"); // QueryInterface is called at this point.
Ez a kényelem a megfelelő felület lekérdezésével érhető el. De ön mindig kézben tarthatja az irányítást. Dönthet úgy, hogy feláldoz valamennyit ebből a kényelemből némi teljesítménynyereségért az IStringable felület saját maga általi lekérésével és közvetlen használatával. Az alábbi kódpéldában futtatáskor (egyszeri lekérdezéssel) tényleges IStringable interfészmutatót szerezhet be. Ezután a ToString hívása közvetlen, és elkerüli a QueryInterface további hívását.
...
IStringable stringable = contosoUri; // One-off QueryInterface.
WINRT_ASSERT(stringable.ToString() == L"http://www.contoso.com/");
Ezt a technikát akkor választhatja, ha tudja, hogy ugyanazon a felületen több metódust is meghív.
Egyébként, ha ABI-szinten szeretne hozzáférni a tagokhoz, akkor megteheti. Az alábbi kódpéldában látható, hogyan, és további részletek és kódpéldák találhatók a C++/WinRT és az ABI közötti Interopban.
#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.
}
Késleltetett inicializálás
A C++/WinRT rendszerben minden előrejelzett típushoz speciális C++/WinRT std::nullptr_t konstruktor tartozik. A kivételével az összes előre jelzett típusú konstruktor – beleértve az alapértelmezett konstruktort is – létrehoz egy háttérrendszerbeli Windows-futtatókörnyezet objektumot, és intelligens mutatót ad hozzá. Ez a szabály tehát mindenhol érvényes, ahol az alapértelmezett konstruktort használják, például nem inicializált helyi változókat, nem inicializált globális változókat és nem inicializált tagváltozókat.
Ha viszont egy előrejelzett típusú változót szeretne létrehozni anélkül, hogy létrehozna egy háttérrendszeri Windows-futtatókörnyezet objektumot (így későbbre késleltetheti a munkát), akkor ezt megteheti. Deklarálja a változót vagy mezőt a speciális C++/WinRT std::nullptr_t konstruktor használatával (amelyet a C++/WinRT-vetítés minden futtatókörnyezeti osztályba injektál). Ezt a speciális konstruktort az alábbi kód példában m_gamerPicBuffer használjuk.
#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();
}
Az std::nullptr_t konstruktor kivételével a kivetített típus összes konstruktora létrehoz egy háttérrendszeri Windows-futtatókörnyezet objektumot. Az std::nullptr_t konstruktor lényegében egy no-op. Azt várja, hogy a kivetített objektum inicializálva legyen egy későbbi időpontban. Tehát, hogy egy futtatókörnyezeti osztály rendelkezik-e alapértelmezett konstruktorsal, használhatja ezt a technikát a hatékony késleltetett inicializáláshoz.
Ez a szempont más helyeket is érint, ahol az alapértelmezett konstruktort használja, például vektorokban és térképekben. Tekintse meg ezt a kódpéldát, amelyhez egy Blank App, Packaged (WinUI 3 in Desktop) for C++ projektre lesz szüksége.
std::map<int, TextBlock> lookup;
lookup[2] = value;
A hozzárendelés létrehoz egy új TextBlock-ot, majd azonnal felülírja azt a következővel value: . Itt a megoldás.
std::map<int, TextBlock> lookup;
lookup.insert_or_assign(2, value);
Lásd még : Hogyan hat az alapértelmezett konstruktor a gyűjteményekre.
Ne késleltesse véletlenül az inicializálást
Ügyeljen arra, hogy véletlenül ne hívja meg az std::nullptr_t konstruktort. A fordító konfliktusfeloldása azt részesíti előnyben a gyári konstruktorokkal szemben. Vegyük például ezt a két futtatókörnyezeti osztálydefiníciót.
// GiftBox.idl
runtimeclass GiftBox
{
GiftBox();
}
// Gift.idl
runtimeclass Gift
{
Gift(GiftBox giftBox); // You can create a gift inside a box.
}
Tegyük fel, hogy olyan ajándékot szeretnénk létrehozni, amely nem egy dobozon belül van (egy ajándék , amely egy nem inicializált Ajándékdobozsal van létrehozva). Először nézzük meg, hogy mi a rossz módszer erre. Tudjuk, hogy van egy Gift konstruktor, amely paraméterként egy GiftBox objektumot vesz át. Ha azonban kísértést érzünk arra, hogy null GiftBox értéket adjunk át (a Gift konstruktort egységes inicializálással meghívva, ahogyan azt alább is tesszük), akkor nem azt az eredményt kapjuk, amit szeretnénk.
// 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) };
Amit itt kap, az egy nem inicializált ajándék. Nem kap ajándékot egy nem inicializált GiftBox esetén. Ez a helyes módszer.
// 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 }) };
A helytelen példában a(z) nullptr literál átadása a késleltetett inicializálást végző konstruktort választja. A gyári konstruktor javára történő megoldáshoz a paraméter típusának Ajándékdoboznak kell lennie. Továbbra is lehetősége van arra, hogy egy explicit módon késleltetett inicializálású GiftBox elemet adjon át, ahogy az a megfelelő példában is látható.
A következő példa azért is helyes, mert a paraméter GiftBox típusú, és nem std::nullptr_t.
GiftBox giftBox{ nullptr };
Gift gift{ giftBox }; // Calls factory constructor.
Csak akkor merül fel a kétértelműség, ha egy nullptr literálist adsz át.
Ne végezzen véletlenül másolatkonstrukciót.
Ez a figyelmeztetés hasonló a fenti Ne inicializáljon késleltetve véletlenül című szakaszban ismertetetthez.
A késleltetett inicializáló konstruktor mellett a C++/WinRT-vetület egy példánykonstruktort is injektál minden futtatókörnyezeti osztályba. Ez egy egyparaméteres konstruktor, amely ugyanazt a típust fogadja el, mint a létrehozott objektum. Az eredményként kapott intelligens mutató ugyanarra a háttérrendszeri Windows-futtatókörnyezet objektumra mutat, mint amelyet a konstruktorparaméter mutat. Az eredmény két intelligens mutatóobjektum, amely ugyanarra a háttérobjektumra mutat.
Íme egy futtatókörnyezeti osztálydefiníció, amelyet a kód példáiban fogunk használni.
// GiftBox.idl
runtimeclass GiftBox
{
GiftBox(GiftBox biggerBox); // You can place a box inside a bigger box.
}
Tegyük fel, hogy egy ajándékdobozt szeretnénk létrehozni egy nagyobb GiftBoxban.
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) };
Ennek helyes módja az aktiválási gyár explicit meghívása.
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) };
Ha az API egy Windows-futtatókörnyezet összetevőben van implementálva
Ez a szakasz arra vonatkozik, hogy saját maga hozta létre az összetevőt, vagy egy szállítótól származik.
Note
A C++/WinRT Visual Studio bővítmény (VSIX) és a NuGet-csomag telepítésével és használatával kapcsolatos információkért (amelyek együttesen nyújtanak projektsablont és buildtámogatást) lásd Visual Studio C++/WinRT támogatását.
Az alkalmazásprojektben hivatkozzon az Windows-futtatókörnyezet összetevő Windows-futtatókörnyezet metaadatfájljára(.winmd) és buildjére. A buildelés során az cppwinrt.exe eszköz létrehoz egy szabványos C++ kódtárat, amely teljes mértékben leírja az összetevő API-felületét vagy projektjeit. Más szóval a létrehozott kódtár tartalmazza az összetevő tervezett típusait.
Ezután ugyanúgy, mint egy Windows névtértípus esetében, egy fejlécet is belefoglal, és az egyik konstruktoron keresztül hozza létre a tervezett típust. Az alkalmazásprojekt indítási kódja regisztrálja a futtatókörnyezeti osztályt, és a tervezett típus konstruktora meghívja a RoActivateInstance-t , hogy aktiválja a futtatókörnyezeti osztályt a hivatkozott összetevőből.
#include <winrt/ThermometerWRC.h>
struct App : AppT<App>
{
ThermometerWRC::Thermometer thermometer;
...
};
További részletekért, kódért és a Windows-futtatókörnyezet összetevőben implementált API-k felhasználásának útmutatójáért tekintse meg Windows-futtatókörnyezet C++/WinRT és Author eseményekkel rendelkező összetevőket a C++/WinRT-ben.
Ha az API implementálva van a fogyasztó projektben
Az ebben a szakaszban szereplő kódpéldát az XAML-vezérlők témaköréből vettük, amely egy C++/WinRT tulajdonsághoz kötődik. Ebben a témakörben további részleteket, kódot és bemutatót talál egy olyan futtatókörnyezeti osztály használatáról, amely ugyanabban a projektben van implementálva, amely azt használja.
Az XAML felhasználói felületén használt típusnak futtatókörnyezeti osztálynak kell lennie, még akkor is, ha ugyanabban a projektben van, mint az XAML. Ebben a forgatókönyvben egy előrejelzett típust hoz létre a futtatókörnyezeti osztály Windows-futtatókörnyezet metaadataiból (.winmd). Itt is megad egy fejlécfájlt, de ezután választhat a futtatókörnyezeti osztály példányának létrehozására szolgáló C++/WinRT 1.0-s vagy 2.0-s módszer között. Az 1.0-s verziójú metódus winrt::make; a 2.0-s verziójú metódust egységes szerkezetnek nevezzük. Nézzük meg őket egyenként.
Összeállítás winrt használatával::make
Kezdjük az alapértelmezett (C++/WinRT 1.0-s verzió) metódussal, mert érdemes legalább ezt a mintát ismerni. A tervezett típust az std::nullptr_t konstruktoron keresztül kell létrehoznia. Ez a konstruktor nem végez inicializálást, ezért a winrt::make helper függvényen keresztül a következő értékeket kell hozzárendelnie a példányhoz, átadva a szükséges konstruktorargumentumokat. A felhasználó kóddal azonos projektben implementált futtatókörnyezeti osztályt nem kell regisztrálni, és nem kell példányosítani Windows-futtatókörnyezet/COM aktiválással.
A teljes útmutatóért lásd: XAML-vezérlők; kötés C++/WinRT-tulajdonsághoz. Ez a szakasz az útmutatóból származó kivonatokat mutatja be.
// 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>();
...
}
Egységes szerkezet
A C++/WinRT 2.0-s és újabb verziójával elérhető egy optimalizált építési forma, amely egységes szerkezetként ismert (lásd a híreket és a változásokat a C++/WinRT 2.0-s verziójában).
Lásd: XAML-vezérlők; kötése C++/WinRT-tulajdonsághoz a teljes útmutatóért. Ez a szakasz az útmutatóból származó kivonatokat mutatja be.
Ha a winrt::make helyett egységes szerkezetet szeretne használni, aktiválási gyárra lesz szüksége. Ennek létrehozására jó módszer, ha hozzáad egy konstruktort az IDL-hez.
// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
MainPage();
BookstoreViewModel MainViewModel{ get; };
}
}
Ezután csak egy lépésben MainPage.h deklarálja és inicializálja m_mainViewModel , ahogy az alább látható.
// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
...
private:
Bookstore::BookstoreViewModel m_mainViewModel;
...
};
}
...
Ezután a MainPage konstruktorban MainPage.cppnincs szükség a kódra m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.
Az egységes építésről és a kód példáiról további információt az egységes építés és a közvetlen megvalósítási hozzáférés engedélyezése című témakörben talál.
Leképezett típusok és interfészek példányosítása és visszaadása
Íme egy példa arra, hogy az előre jelzett típusok és felületek milyenek lehetnek a fogyasztó projektben. Ne feledje, hogy egy előrejelzett típus (például a jelen példában szereplő) eszköz által generált, és nem olyan típus, amelyet saját maga készít.
struct MyRuntimeClass : MyProject::IMyRuntimeClass, impl::require<MyRuntimeClass,
Windows::Foundation::IStringable, Windows::Foundation::IClosable>
A MyRuntimeClass egy előrejelzett típus; az előre jelzett felületek közé tartozik az IMyRuntimeClass, az IStringable és az IClosable. Ez a témakör a kivetített típusok példányosításának különböző módjait mutatja be. Íme egy emlékeztető és összegzés, amely példaként a MyRuntimeClassot használja.
// 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>();
- Elérheti a kivetített típus összes interfészének tagjait.
- Egy előrejelzett típust visszaadhat egy hívónak.
- A tervezett típusok és felületek a winrt::Windows::Foundation::IUnknown függvényből származnak. Így meghívhatja az IUnknown::as függvényt egy kivetített típuson vagy felületen, hogy más kivetített felületeket kérdezzen le, amelyeket aztán either használhat, vagy visszaadhat a hívónak. A tagfüggvény a QueryInterface-hez hasonlóan működik.
void f(MyProject::MyRuntimeClass const& myrc)
{
myrc.ToString();
myrc.Close();
IClosable iclosable = myrc.as<IClosable>();
iclosable.Close();
}
Aktiválási gyárak
A C++/WinRT-objektum létrehozásának kényelmes, közvetlen módja a következő.
using namespace winrt::Windows::Globalization::NumberFormatting;
...
CurrencyFormatter currency{ L"USD" };
Előfordulhat azonban, hogy az aktiválási gyárat saját maga szeretné létrehozni, majd az ön kényelme érdekében objektumokat hoz létre belőle. Az alábbi példák bemutatják, hogyan használhatja a winrt::get_activation_factory függvénysablont.
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");
A fenti két példában szereplő osztályok egy Windows névtérből származó típusok. Ebben a következő példában a ThermometerWRC::Thermometer egy egyéni típus, amely egy Windows-futtatókörnyezet összetevőben van implementálva.
auto factory = winrt::get_activation_factory<ThermometerWRC::Thermometer>();
ThermometerWRC::Thermometer thermometer = factory.ActivateInstance<ThermometerWRC::Thermometer>();
Tag- és típuskétértelműségek
Ha egy tagfüggvény neve megegyezik egy típus nevével, kétértelműség áll fenn. A C++ tagfüggvényekben a nem minősített névkeresés szabályai miatt a névterekben való keresés előtt az osztályban kell keresnie. A helyettesítési hiba nem hiba (SFINAE) szabály nem alkalmazható (a függvénysablonok túlterhelésének feloldása során érvényes). Ha tehát az osztályon belüli névnek nincs értelme, akkor a fordító nem keresi a jobb egyezést – egyszerűen hibát jelez.
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>() };
}
}
A fentiekben a fordító úgy értelmezi, hogy a FrameworkElement.Style() elemet (ami a C++/WinRT-ben tagfüggvény) adja át a(z) IUnknown::as sablonparamétereként. A megoldás arra kényszeríti a nevet, hogy a Style típusként értelmezze.
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>();
}
}
A nem minősített név keresésére speciális kivétel érvényes abban az esetben, ha a nevet :: követi; ilyenkor figyelmen kívül hagyja a függvényeket, változókat és enumerációs értékeket. Ez lehetővé teszi, hogy ilyen dolgokat csináljon.
struct MyPage : Page
{
void DoSomething()
{
Visibility(Visibility::Collapsed); // No ambiguity here (special exception).
}
}
A(z) Visibility() hívás a(z) UIElement.Visibility tagfüggvény nevére oldódik fel. A paraméter Visibility::Collapsed azonban követi a következő szót Visibility::, így a metódus neve figyelmen kívül lesz hagyva, és a fordító megkeresi az enum osztályt.
Fontos API-k
- QueryInterface függvény
- RoActivateInstance függvény
- Windows::Foundation::Uri osztály
- winrt::get_activation_factory függvénysablon
- winrt::make függvénysablon
- winrt::Windows::Foundation::IUnknown struct
Kapcsolódó témakörök
Windows developer