Utilizzare API con C++/WinRTConsume APIs with C++/WinRT

Questo argomento descrive come utilizzare le API C++/WinRT, che siano parte di Windows, vengano implementate da un fornitore di componenti di terze parti o dall'utente stesso.This topic shows how to consume C++/WinRT APIs, whether they're part of Windows, implemented by a third-party component vendor, or implemented by yourself.

Se l'API si trova in uno spazio dei nomi WindowsIf the API is in a Windows namespace

Questo è il caso più comune di utilizzo di un'API Windows Runtime.This is the most common case in which you'll consume a Windows Runtime API. Per ogni tipo in uno spazio dei nomi Windows definito nei metadati, C++/WinRT definisce un equivalente C++ (chiamato il tipo proiettato).For every type in a Windows namespace defined in metadata, C++/WinRT defines a C++-friendly equivalent (called the projected type). Un tipo proiettato ha lo stesso nome completo del tipo Windows, ma viene posizionato nello spazio dei nomi winrt C++ tramite la sintassi C++.A projected type has the same fully-qualified name as the Windows type, but it's placed in the C++ winrt namespace using C++ syntax. Ad esempio, la classe Windows::Foundation::Uri viene proiettata in C++/WinRT come winrt::Windows::Foundation::Uri.For example, Windows::Foundation::Uri is projected into C++/WinRT as winrt::Windows::Foundation::Uri.

Ecco un semplice esempio di codice.Here's a simple code example. Se vuoi copiare e incollare i seguenti esempi di codice direttamente nel file di codice sorgente principale di un progetto Applicazione console Windows (C++/WinRT) , imposta prima di tutto Senza intestazioni precompilate nelle proprietà del progetto.If you want to copy-paste the following code examples directly into the main source code file of a Windows Console Application (C++/WinRT) project, then first set Not Using Precompiled Headers in project properties.

// 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");
}

L'intestazione inclusa winrt/Windows.Foundation.h fa parte dell'SDK, disponibile all'interno della cartella %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\.The included header winrt/Windows.Foundation.h is part of the SDK, found inside the folder %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\. Le intestazioni in tale cartella contengono tipi di spazi dei nomi Windows proiettati in C++/WinRT.The headers in that folder contain Windows namespace types projected into C++/WinRT. In questo esempio winrt/Windows.Foundation.h contiene winrt::Windows::Foundation::Uri, ovvero il tipo proiettato per la classe di runtime Windows::Foundation::Uri.In this example, winrt/Windows.Foundation.h contains winrt::Windows::Foundation::Uri, which is the projected type for the runtime class Windows::Foundation::Uri.

Suggerimento

Ogni volta che desideri usare un tipo da uno spazio dei nomi di Windows, includi l'intestazione C++/WinRT corrispondente nello spazio dei nomi.Whenever you want to use a type from a Windows namespace, include the C++/WinRT header corresponding to that namespace. Le direttive using namespace sono facoltative, ma utili.The using namespace directives are optional, but convenient.

Nell'esempio di codice precedente dopo l'inizializzazione di C++/WinRT, eseguiamo l'allocazione di gruppo del tipo proiettato winrt::Windows::Foundation::Uri tramite uno dei costruttori documentati pubblicamente (Uri(String) , in questo esempio).In the code example above, after initializing C++/WinRT, we stack-allocate a value of the winrt::Windows::Foundation::Uri projected type via one of its publicly documented constructors (Uri(String), in this example). Per questo caso d'uso, che è il più comune, è in genere tutto ciò che è necessario fare.For this, the most common use case, that's typically all you have to do. Dopo aver ottenuto il valore di un tipo proiettato C++/WinRT, è possibile utilizzarlo come se fosse un'istanza del tipo Windows Runtime effettivo, poiché dispone degli stessi membri.Once you have a C++/WinRT projected type value, you can treat it as if it were an instance of the actual Windows Runtime type, since it has all the same members.

In realtà, tale valore proiettato è un proxy. Si tratta in pratica di un puntatore intelligente di un oggetto di supporto.In fact, that projected value is a proxy; it's essentially just a smart pointer to a backing object. I costruttori del valore proiettato chiamano RoActivateInstance per creare un'istanza della classe Windows Runtime di supporto (Windows.Foundation.Uri, in questo caso) e archiviare l'interfaccia predefinita dell'oggetto all'interno del nuovo valore proiettato.The projected value's constructor(s) call RoActivateInstance to create an instance of the backing Windows Runtime class (Windows.Foundation.Uri, in this case), and store that object's default interface inside the new projected value. Come illustrato di seguito, le chiamate ai membri del valore proiettato delegano, tramite il puntatore intelligente, all'oggetto di supporto, ovvero dove avvengono le modifiche dello stato.As illustrated below, your calls to the projected value's members actually delegate, via the smart pointer, to the backing object; which is where state changes occur.

Il tipo Windows::Foundation::Uri proiettato

Quando il valore contosoUri non rientra nell'ambito, viene distrutto e rilascia il relativo riferimento all'interfaccia predefinita.When the contosoUri value falls out of scope, it destructs, and releases its reference to the default interface. Se si tratta dell'ultimo riferimento per l'oggetto Windows.Foundation.Uri Windows Runtime di supporto, viene distrutto anche l'oggetto di supporto.If that reference is the last reference to the backing Windows Runtime Windows.Foundation.Uri object, the backing object destructs as well.

Suggerimento

Un tipo proiettato è un wrapper su una classe di runtime con lo scopo di usare le relative API.A projected type is a wrapper over a runtime class for purposes of consuming its APIs. Un'interfaccia proiettata è un wrapper su un'interfaccia di Windows Runtime.A projected interface is a wrapper over a Windows Runtime interface.

Intestazioni di proiezione C++/WinRTC++/WinRT projection headers

Per l'utilizzo delle API dello spazio dei nomi Windows da C++/WinRT, includi le intestazioni della cartella %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt.To consume Windows namespace APIs from C++/WinRT, you include headers from the %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt folder. È comune per un tipo di uno spazio dei nomi subordinato fare riferimento ai tipi nello spazio dei nomi padre immediato.It's common for a type in a subordinate namespace to reference types in its immediate parent namespace. Di conseguenza, ogni intestazione di proiezione C++/WinRT include automaticamente il file di intestazione dello spazio dei nomi padre. Non dovrai pertanto includerlo in modo esplicito,Consequently, each C++/WinRT projection header automatically includes its parent namespace header file; so you don't need to explicitly include it. ma se lo farai, non verrà restituito alcun errore.Although, if you do, there will be no error.

Ad esempio, per lo spazio dei nomi Windows::Security::Cryptography::Certificates, le definizioni dei tipi C++/WinRT equivalenti si trovano in winrt/Windows.Security.Cryptography.Certificates.h.For example, for the Windows::Security::Cryptography::Certificates namespace, the equivalent C++/WinRT type definitions reside in winrt/Windows.Security.Cryptography.Certificates.h. I tipi in Windows::Security::Cryptography::Certificates richiedono tipi nello spazio dei nomi Windows::Security::Cryptography padre e i tipi in tale spazio dei nomi potrebbero richiedere un proprio elemento padre, ovvero Windows::Security.Types in Windows::Security::Cryptography::Certificates require types in the parent Windows::Security::Cryptography namespace; and types in that namespace could require types in its own parent, Windows::Security.

Pertanto, quando si include winrt/Windows.Security.Cryptography.Certificates.h, questo file include a sua volta winrt/Windows.Security.Cryptography.h e winrt/Windows.Security.Cryptography.h include winrt/Windows.Security.h.So, when you include winrt/Windows.Security.Cryptography.Certificates.h, that file in turn includes winrt/Windows.Security.Cryptography.h; and winrt/Windows.Security.Cryptography.h includes winrt/Windows.Security.h. Qui si interrompe il percorso, poiché non è presente alcun winrt/Windows.h.That's where the trail stops, since there is no winrt/Windows.h. Questo processo di inclusione transitiva si arresta in corrispondenza dello spazio dei nomi di secondo livello.This transitive inclusion process stops at the second-level namespace.

Questo processo include in modo transitivo i file di intestazione che forniscono le dichiarazioni e le implementazioni necessarie per le classi definite negli spazi dei nomi padre.This process transitively includes the header files that provide the necessary declarations and implementations for the classes defined in parent namespaces.

Un membro di un tipo in uno spazio dei nomi può fare riferimento a uno o più tipi in altri spazi dei nomi non correlati.A member of a type in one namespace can reference one or more types in other, unrelated, namespaces. Per riuscire a compilare correttamente queste definizioni di membro, il compilatore deve visualizzare le dichiarazioni di tipo per la chiusura di tutti questi tipi.In order for the compiler to compile these member definitions successfully, the compiler needs to see the type declarations for the closure of all these types. Di conseguenza, ogni intestazione di proiezione C++/WinRT include le intestazioni dello spazio dei nomi di cui ha bisogno per dichiarare tutti i tipi dipendenti.Consequently, each C++/WinRT projection header includes the namespace headers it needs to declare any dependent types. A differenza degli spazi dei nomi padre, questo processo non esegue il pull delle implementazioni per i tipi a cui viene fatto riferimento.Unlike for parent namespaces, this process does not pull in the implementations for referenced types.

Importante

Se desideri usare effettivamente un tipo (creare un'istanza, chiamare metodi e così via) dichiarato in uno spazio dei nomi non correlato, dovrai includere il file di intestazione dello spazio dei nomi appropriato per tale tipo.When you want to actually use a type (instantiate, call methods, etc.) declared in an unrelated namespace, you must include the appropriate namespace header file for that type. Vengono incluse automaticamente solo le dichiarazioni, non le implementazioni.Only declarations, not implementations, are automatically included.

Ad esempio, se includi solo winrt/Windows.Security.Cryptography.Certificates.h, viene eseguito il pull in delle dichiarazioni da tali spazi dei nomi (e così via, in modo transitivo).For example, if you only include winrt/Windows.Security.Cryptography.Certificates.h, then that causes declarations to be pulled in from these namespaces (and so on, transitively).

  • Windows.FoundationWindows.Foundation
  • Windows.Foundation.CollectionsWindows.Foundation.Collections
  • Windows.NetworkingWindows.Networking
  • Windows.Storage.StreamsWindows.Storage.Streams
  • Windows.Security.CryptographyWindows.Security.Cryptography

In altre parole, alcune API sono dichiarate in anticipo in un'intestazione che hai incluso.In other words, some APIs are forward-declared in a header that you've included. Ma le relative definizioni si trovano in un'intestazione che non hai ancora incluso.But their definitions are in a header that you haven't yet included. Se in seguito chiami Windows::Foundation::Uri::RawUri, riceverai pertanto un errore del linker che indica che il membro non è definito.So, if you then call Windows::Foundation::Uri::RawUri, then you'll receive a linker error indicating that the member is undefined. La soluzione consiste nell'usare #include <winrt/Windows.Foundation.h> in modo esplicito.The solution is to explicitly #include <winrt/Windows.Foundation.h>. In generale, quando ricevi un errore del linker come questo, includi l'intestazione specificata per lo spazio dei nomi dell'API ed esegui di nuovo la ricompilazione.In general, when you see a linker error such as this, include the header named for the API's namespace, and rebuild.

Accesso ai membri tramite l'oggetto, un'interfaccia o l'ABIAccessing members via the object, via an interface, or via the ABI

Con la proiezione C++/WinRT la rappresentazione di runtime di una classe di Windows Runtime è costituita esclusivamente dalle interfacce ABI sottostanti.With the C++/WinRT projection, the runtime representation of a Windows Runtime class is no more than the underlying ABI interfaces. Tuttavia, per praticità, puoi scrivere codice per le classi nel modo previsto dal relativo autore.But, for your convenience, you can code against classes in the way that their author intended. Ad esempio, puoi chiamare il metodo ToString di un Uri come se fosse un metodo della classe (in realtà, si tratta di un metodo dell'interfaccia IStringable separata).For example, you can call the ToString method of a Uri as if that were a method of the class (in fact, under the covers, it's a method on the separate IStringable interface).

WINRT_ASSERT è una definizione di macro e si espande in ASSERTE.WINRT_ASSERT is a macro definition, and it expands to _ASSERTE.

Uri contosoUri{ L"http://www.contoso.com" };
WINRT_ASSERT(contosoUri.ToString() == L"http://www.contoso.com/"); // QueryInterface is called at this point.

Questo vantaggio viene ottenuto tramite una query per l'interfaccia appropriata.This convenience is achieved via a query for the appropriate interface. Ma sei sempre tu che hai il controllo.But you're always in control. Puoi scegliere di rinunciare a una parte di tale vantaggio a favore di un leggero aumento delle prestazioni, recuperando manualmente l'interfaccia IStringable e utilizzandola direttamente.You can opt to give away a little of that convenience for a little performance by retrieving the IStringable interface yourself and using it directly. Nell'esempio di codice riportato di seguito, ottieni un puntatore di interfaccia IStringable effettivo in fase di esecuzione (tramite una query monouso).In the code example below, you obtain an actual IStringable interface pointer at run time (via a one-time query). La chiamata a ToString viene quindi diretta e impedisce eventuali ulteriori chiamate a QueryInterface.After that, your call to ToString is direct, and avoids any further call to QueryInterface.

...
IStringable stringable = contosoUri; // One-off QueryInterface.
WINRT_ASSERT(stringable.ToString() == L"http://www.contoso.com/");

Puoi scegliere questa tecnica se sai che chiamerai diversi metodi sulla stessa interfaccia.You might choose this technique if you know you'll be calling several methods on the same interface.

In alcuni casi, puoi accedere ai membri a livello di ABI, se lo desideri.Incidentally, if you do want to access members at the ABI level then you can. L'esempio di codice seguente mostra come fare. Ulteriori dettagli ed esempi di codice sono inoltre disponibili in Interoperabilità tra C++/WinRT e ABI.The code example below shows how, and there are more details and code examples in Interop between C++/WinRT and the 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.
}

Inizializzazione ritardataDelayed initialization

In C++/WinRT ogni tipo proiettato ha un costruttore std::nullptr_t speciale.In C++/WinRT, each projected type has a special C++/WinRT std::nullptr_t constructor. Ad eccezione di questo, tutti i costruttori dei tipi proiettati, incluso quello predefinito, comportano la creazione di un oggetto Windows Runtime di supporto e forniscono un puntatore intelligente a tale oggetto.With the exception of that one, all projected-type constructors—including the default constructor—cause a backing Windows Runtime object to be created, and give you a smart pointer to it. Di conseguenza, tale regola si applica a tutti i casi in cui viene usato il costruttore predefinito, ad esempio le variabili locali, globali e membro non inizializzate.So, that rule applies anywhere that the default constructor is used, such as uninitialized local variables, uninitialized global variables, and uninitialized member variables.

Se però vuoi creare una variabile di un tipo proiettato senza che venga creato un oggetto Windows Runtime di supporto, in modo da poter rinviare tale operazione a un momento successivo, puoi farlo.If, on the other hand, you want to construct a variable of a projected type without it in turn constructing a backing Windows Runtime object (so that you can delay that work until later), then you can do that. Dichiara la variabile o il campo usando il costruttore std::nullptr_t di C++/WinRT speciale, che la proiezione di C++/WinRT inserisce in ogni classe di runtime.Declare your variable or field using that special C++/WinRT std::nullptr_t constructor (which the C++/WinRT projection injects into every runtime class). Questo costruttore speciale viene usato con m_gamerPicBuffer nell'esempio di codice seguente.We use that special constructor with m_gamerPicBuffer in the code example below.

#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();
}

Tutti i costruttori sul tipo proiettato, tranne il costruttore std::nullptr_t, determinano la creazione di un oggetto Windows Runtime di supporto.All constructors on the projected type except the std::nullptr_t constructor cause a backing Windows Runtime object to be created. Il costruttore std::nullptr_t è essenzialmente una fase senza operazioniThe std::nullptr_t constructor is essentially a no-op. e si aspetta che l'oggetto proiettato venga inizializzato in un momento successivo.It expects the projected object to be initialized at a subsequent time. Pertanto, indipendentemente da se una classe di runtime dispone o meno di un costruttore predefinito, puoi usare questa tecnica per un'inizializzazione ritardata efficiente.So, whether a runtime class has a default constructor or not, you can use this technique for efficient delayed initialization.

Questa considerazione influisce sulle altre posizioni in cui richiami il costruttore predefinito, ad esempio nei vettori e nell mappe.This consideration affects other places where you're invoking the default constructor, such as in vectors and maps. Considera l'esempio di codice per cui necessiti di un progetto App vuota (C++/WinRT) .Consider this code example, for which you'll need a Blank App (C++/WinRT) project.

std::map<int, TextBlock> lookup;
lookup[2] = value;

L'assegnazione crea un nuovo TextBlock e lo sovrascrive immediatamente con value.The assignment creates a new TextBlock, and then immediately overwrites it with value. Ecco il risultato.Here's the remedy.

std::map<int, TextBlock> lookup;
lookup.insert_or_assign(2, value);

Vedi anche Effetti del costruttore predefinito sulle raccolte.Also see How the default constructor affects collections.

Non impostare l'inizializzazione ritardata per erroreDon't delay-initialize by mistake

Presta attenzione a non richiamare il costruttore std::nullptr_t per errore.Be careful that you don't invoke the std::nullptr_t constructor by mistake. La risoluzione dei conflitti del compilatore lo preferisce a discapito dei costruttori di factory.The compiler's conflict resolution favors it over the factory constructors. Ad esempio, prendi in considerazione queste due definizioni di classe di runtime.For example, consider these two runtime class definitions.

// GiftBox.idl
runtimeclass GiftBox
{
    GiftBox();
}

// Gift.idl
runtimeclass Gift
{
    Gift(GiftBox giftBox); // You can create a gift inside a box.
}

Supponi di voler creare un oggetto Gift che non si trova all'interno di una scatola, ovvero un oggetto Gift creato con un oggetto GiftBox non inizializzato.Let's say that we want to construct a Gift that isn't inside a box (a Gift that's constructed with an uninitialized GiftBox). Prima di tutto, esaminiamo il modo non corretto di eseguire questa operazione.First, let's look at the wrong way to do that. Sappiamo che esiste un costruttore Gift che accetta un oggetto GiftBox.We know that there'a Gift constructor that takes a GiftBox. Anche se è possibile passare un oggetto GiftBox Null (richiamando il costruttore Gift tramite inizializzazione uniforme, come verrà illustrato più avanti) non si otterrebbe il risultato desiderato.But if we're tempted to pass a null GiftBox (invoking the Gift constructor via uniform initialization, as we do below), then we won't get the result we want.

// 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) };

In questo modo, otteniamo un oggetto Gift non inizializzato,What you get here is an uninitialized Gift. ma non un oggetto Gift con GiftBox non inizializzato.You don't get a Gift with an uninitialized GiftBox. Ecco invece il modo corretto per eseguire questa operazione.Here's the correct way to do that.

// 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 }) };

Nell'esempio non corretto, il passaggio di un valore letterale nullptr si risolve a favore del costruttore con inizializzazione ritardata.In the incorrect example, passing a nullptr literal resolves in favor of the delay-initializing constructor. Per favorire il costruttore di factory, il tipo del parametro deve essere GiftBox.To resolve in favor of the factory constructor, the type of the parameter must be a GiftBox. Hai comunque sempre la possibilità di passare un oggetto GiftBox con esplicita inizializzazione ritardata, come illustrato nell'esempio corretto.You still have the option to pass an explicitly delay-initializing GiftBox, as shown in the correct example.

Anche l'esempio seguente è corretto perché il parametro è di tipo GiftBox e non std::nullptr_t.This next example is also correct, because the parameter has type GiftBox, and not std::nullptr_t.

GiftBox giftBox{ nullptr };
Gift gift{ giftBox }; // Calls factory constructor.

Il problema di ambiguità si presenta solo quando passi un valore letterale nullptr.It's only when you pass a nullptr literal that the ambiguity arises.

Non usare un costruttore di copia per erroreDon't copy-construct by mistake.

Questo avvertimento è simile a quello descritto nella precedente sezione Non impostare l'inizializzazione ritardata per errore.This caution is similar to the one described in the Don't delay-initialize by mistake section above.

Oltre al costruttore con inizializzazione ritardata, la proiezione C++/WinRT inserisce un costruttore di copia in ogni classe di runtime.In addition to the delay-initializing constructor, the C++/WinRT projection also injects a copy constructor into every runtime class. È un costruttore con parametro singolo che accetta lo stesso tipo dell'oggetto in fase di costruzione.It's a single-parameter constructor that accepts the same type as the object being constructed. Il puntatore intelligente risultante punta allo stesso oggetto Windows Runtime di supporto a cui punta il parametro del costruttore.The resulting smart pointer points to the same backing Windows Runtime object as that pointed to by its constructor parameter. Come risultato abbiamo quindi due oggetti puntatore intelligente che puntano allo stesso oggetto di supporto.The result is two smart pointer objects pointing to the same backing object.

Ecco una definizione di classe di runtime che useremo negli esempi di codice.Here's a runtime class definition that we'll use in the code examples.

// GiftBox.idl
runtimeclass GiftBox
{
    GiftBox(GiftBox biggerBox); // You can place a box inside a bigger box.
}

Supponiamo di voler creare un oggetto GiftBox all'interno di un GiftBox più grande.Let's say that we want to construct a GiftBox inside a larger GiftBox.

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

Il modo corretto per eseguire questa operazione è quello di chiamare in modo esplicito la factory di attivazione.The correct way to do it is to call the activation factory explicitly.

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

Se l'API è implementata in un componente Windows RuntimeIf the API is implemented in a Windows Runtime component

Questa sezione si applica se il componente è stato creato da te o proviene da un fornitore.This section applies whether you authored the component yourself, or it came from a vendor.

Nota

Per informazioni sull'installazione e sull'uso dell'Estensione C++/WinRT per Visual Studio (VSIX) e del pacchetto NuGet (che insieme forniscono il modello di progetto e il supporto della compilazione), vedi Supporto di Visual Studio per C++/WinRT.For info about installing and using the C++/WinRT Visual Studio Extension (VSIX) and the NuGet package (which together provide project template and build support), see Visual Studio support for C++/WinRT.

Nel progetto di applicazione fai riferimento al file di metadati Windows Runtime (.winmd) del componente Windows Runtime ed esegui la compilazione.In your application project, reference the Windows Runtime component's Windows Runtime metadata (.winmd) file, and build. Durante la compilazione, lo strumento cppwinrt.exe genera una libreria C++ standard che descrive completamente o proietta la superficie dell'API per il componente.During the build, the cppwinrt.exe tool generates a standard C++ library that fully describes—or projects—the API surface for the component. In altre parole, la libreria generata contiene i tipi proiettati per il componente.In other words, the generated library contains the projected types for the component.

Quindi, come per un tipo di spazio dei nomi di Windows, includi un'intestazione e costruisci il tipo proiettato tramite uno dei relativi costruttori.Then, just as for a Windows namespace type, you include a header and construct the projected type via one of its constructors. Il codice di avvio del progetto di applicazione registra la classe di runtime e il costruttore del tipo proiettato chiama RoActivateInstance per attivare la classe di runtime dal componente a cui viene fatto riferimento.Your application project's startup code registers the runtime class, and the projected type's constructor calls RoActivateInstance to activate the runtime class from the referenced component.

#include <winrt/ThermometerWRC.h>

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    ThermometerWRC::Thermometer thermometer;
    ...
};

Per altre informazioni, codice e una procedura dettagliata sull'utilizzo di API implementate in un componente Windows Runtime, vedere Componenti Windows Runtime con C++/WinRT e Creare eventi in CC++/WinRT.For more details, code, and a walkthrough of consuming APIs implemented in a Windows Runtime component, see Windows Runtime components with C++/WinRT and Author events in C++/WinRT.

Se l'API è implementata nel progetto di usoIf the API is implemented in the consuming project

L'esempio di codice in questa sezione è tratto dall'argomento Controlli XAML, binding a una proprietà C++/WinRT.The code example in this section is taken from the topic XAML controls; bind to a C++/WinRT property. Per altre informazioni, esempi di codice e una procedura dettagliata per l'uso di una classe di runtime implementata nello stesso progetto d'uso, vedere questo argomento.See that topic for more details, code, and a walkthrough of consuming a runtime class that's implemented in the same project that consumes it.

Un tipo usato dall'interfaccia utente XAML deve essere una classe di runtime, anche se è nello stesso progetto del codice XAML.A type that's consumed from XAML UI must be a runtime class, even if it's in the same project as the XAML. Per questo scenario, genera un tipo proiettato dai metadati Windows Runtime (.winmd) della classe di runtime.For this scenario, you generate a projected type from the runtime class's Windows Runtime metadata (.winmd). Anche in questo caso, è necessario includere un'intestazione, ma è possibile scegliere tra la versione 1.0 o 2.0 di C++/WinRT per costruire l'istanza della classe di runtime.Again, you include a header, but then you have a choice between the C++/WinRT version 1.0 or version 2.0 ways of constructing the instance of the runtime class. Il metodo della versione 1.0 usa winrt::make. Il metodo della versione 2.0 è noto come costruzione uniforme.The version 1.0 method uses winrt::make; the version 2.0 method is known as uniform construction. Verranno esaminati entrambi.Let's look at each in turn.

Costruzione tramite winrt::makeConstructing by using winrt::make

Viene descritto innanzitutto il metodo predefinito (C++/WinRT versione 1.0), perché è consigliabile avere familiarità almeno con questo modello.Let's start with the default (C++/WinRT version 1.0) method, because it's a good idea to be at least familiar with that pattern. Viene creato il tipo proiettato tramite il relativo costruttore std::nullptr_t.You construct the projected type via its std::nullptr_t constructor. Questo costruttore non esegue alcuna inizializzazione, devi pertanto assegnare un valore all'istanza tramite la funzione helper winrt::make, passando gli argomenti del costruttore necessari.That constructor doesn't perform any initialization, so you must next assign a value to the instance via the winrt::make helper function, passing any necessary constructor arguments. Una classe di runtime implementata nello stesso progetto del codice che la usa non deve necessariamente essere registrata, né deve esserne creata un'istanza tramite l'attivazione di Windows Runtime/COM.A runtime class implemented in the same project as the consuming code doesn't need to be registered, nor instantiated via Windows Runtime/COM activation.

Per una procedura dettagliata completa, vedere Controlli XAML, binding a una proprietà C++/WinRT.See XAML controls; bind to a C++/WinRT property for a full walkthrough. Questa sezione descrive gli estratti della procedura dettagliata.This section shows extracts from that walkthrough.

// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
    runtimeclass MainPage : Windows.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>();
    ...
}

Costruzione uniformeUniform construction

Con C++/WinRT versione 2.0 e successive, è disponibile un modulo di costruzione ottimizzato, noto come costruzione uniforme. Vedere Funzionalità nuove e aggiornate di C++/WinRT 2.0.With C++/WinRT version 2.0 and later, there's an optimized form of construction available to you known as uniform construction (see News, and changes, in C++/WinRT 2.0).

Per una procedura dettagliata completa, vedere Controlli XAML, binding a una proprietà C++/WinRT.See XAML controls; bind to a C++/WinRT property for a full walkthrough. Questa sezione descrive gli estratti della procedura dettagliata.This section shows extracts from that walkthrough.

Per usare la costruzione uniforme invece di winrt::make, sarà necessaria una factory di attivazione.To use uniform construction instead of winrt::make, you'll need an activation factory. Un metodo efficace per generarne una consiste nell'aggiungere un costruttore all'IDL.A good way to generate one is to add a constructor to your IDL.

// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        BookstoreViewModel MainViewModel{ get; };
    }
}

Quindi in MainPage.h dichiarare e inizializzare m_mainViewModel in un solo passaggio, come illustrato di seguito.Then, in MainPage.h declare and initialize m_mainViewModel in just one step, as shown below.

// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
    ...
    private:
        Bookstore::BookstoreViewModel m_mainViewModel;
        ...
    };
}
...

Nel costruttore MainPage in MainPage.cpp non è quindi necessario il codice m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.And then, in the MainPage constructor in MainPage.cpp, there's no need for the code m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.

Per altre informazioni sulla costruzione uniforme ed esempi di codice, vedere Acconsentire esplicitamente alla costruzione uniforme e all'accesso diretto all'implementazione.For more info about uniform construction, and code examples, see Opt in to uniform construction, and direct implementation access.

Creazione di istanze e restituzione di interfacce e tipi proiettatiInstantiating and returning projected types and interfaces

Ecco un esempio del possibile aspetto di interfacce e tipi proiettati nel tuo progetto di uso.Here's an example of what projected types and interfaces might look like in your consuming project. Tieni presente che un tipo proiettato (come quello analizzato in questo esempio), viene generato da strumenti e non creato manualmente.Remember that a projected type (such as the one in this example), is tool-generated, and is not something that you'd author yourself.

struct MyRuntimeClass : MyProject::IMyRuntimeClass, impl::require<MyRuntimeClass,
    Windows::Foundation::IStringable, Windows::Foundation::IClosable>

MyRuntimeClass è un tipo proiettato. Le interfacce proiettate includono IMyRuntimeClass, IStringable e IClosable .MyRuntimeClass is a projected type; projected interfaces include IMyRuntimeClass, IStringable, and IClosable. In questo argomento sono stati descritti i diversi modi per creare un'istanza di un tipo proiettato.This topic has shown the different ways in which you can instantiate a projected type. Di seguito sono riportati un promemoria e un riepilogo, utilizzando MyRuntimeClass come esempio.Here's a reminder and summary, using MyRuntimeClass as an example.

// 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>();
  • Puoi accedere ai membri di tutte le interfacce di un tipo proiettato.You can access the members of all of the interfaces of a projected type.
  • Puoi restituire un tipo proiettato a un chiamante.You can return a projected type to a caller.
  • Le interfacce e i tipi proiettati derivano da winrt::Windows::Foundation::IUnknown.Projected types and interfaces derive from winrt::Windows::Foundation::IUnknown. Puoi pertanto chiamare IUnknown::as su un tipo proiettato o un'interfaccia proiettata per eseguire una query su altre interfacce proiettate, che potrai usare o restituire al chiamante.So, you can call IUnknown::as on a projected type or interface to query for other projected interfaces, which you can also either use or return to a caller. La funzione membro as agisce in modo analogo a QueryInterface.The as member function works like QueryInterface.
void f(MyProject::MyRuntimeClass const& myrc)
{
    myrc.ToString();
    myrc.Close();
    IClosable iclosable = myrc.as<IClosable>();
    iclosable.Close();
}

Factory di attivazioneActivation factories

Di seguito viene riportato il conveniente metodo diretto per creare un oggetto C++/WinRT.The convenient, direct way to create a C++/WinRT object is as follows.

using namespace winrt::Windows::Globalization::NumberFormatting;
...
CurrencyFormatter currency{ L"USD" };

In alcuni casi, potresti tuttavia voler creare manualmente la factory di attivazione e usarla per creare oggetti in base alle tue esigenze.But there may be times that you'll want to create the activation factory yourself, and then create objects from it at your convenience. Ecco alcuni esempi che mostrano come eseguire tale operazione, usando il modello di funzione winrt::get_activation_factory.Here are some examples showing you how, using the winrt::get_activation_factory function template.

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");

Le classi nei due esempi precedenti sono tipi di uno spazio dei nomi Windows.The classes in the two examples above are types from a Windows namespace. Nell'esempio seguente ThermometerWRC::Thermometer è un tipo personalizzato implementato in un componente Windows Runtime.In this next example, ThermometerWRC::Thermometer is a custom type implemented in a Windows Runtime component.

auto factory = winrt::get_activation_factory<ThermometerWRC::Thermometer>();
ThermometerWRC::Thermometer thermometer = factory.ActivateInstance<ThermometerWRC::Thermometer>();

Ambiguità tra membri e tipiMember/Type ambiguities

Quando una funzione membro ha lo stesso nome di un tipo, è presente un'ambiguità.When a member function has the same name as a type, there's ambiguity. Le regole per la ricerca di nomi C++ non qualificati nelle funzioni membro danno priorità alla ricerca nella classe rispetto a quella negli spazi dei nomi.The rules for C++ unqualified name lookup in member functions cause it to search the class before searching in namespaces. La regola in base alla quale la mancata sostituzione non è un errore (SFINAE) non è applicabile (si applica durante la risoluzione dell'overload dei modelli di funzione).The substitution failure is not an error (SFINAE) rule doesn't apply (it applies during overload resolution of function templates). Se quindi il nome all'interno della classe non ha senso, il compilatore non continua a cercare una corrispondenza migliore, ma si limita a segnalare un errore.So if the name inside the class doesn't make sense, then the compiler doesn't keep looking for a better match—it simply reports an error.

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

Nell'esempio precedente il compilatore pensa che stai passando FrameworkElement.Style() (una funzione membro in C++/WinRT) come parametro di modello a IUnknown::as.Above, the compiler thinks that you're passing FrameworkElement.Style() (which, in C++/WinRT, is a member function) as the template parameter to IUnknown::as. La soluzione consiste nel forzare l'interpretazione di Style come tipo Windows::UI::Xaml::Style.The solution is to force the name Style to be interpreted as the type Windows::UI::Xaml::Style.

struct MyPage : Page
{
    void DoWork()
    {
        // One option is to fully-qualify it.
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<Windows::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 Windows::UI::Xaml namespace when you did
        // "using namespace Windows::UI::Xaml;".
        auto style = Application::Current().Resources().
            Lookup(L"MyStyle").as<::Style>();
    }
}

La ricerca di nomi non qualificati presenta un'eccezione speciale quando il nome è seguito da ::, nel qual caso ignora funzioni, variabili e valori enum.Unqualified name lookup has a special exception in the case that the name is followed by ::, in which case it ignores functions, variables, and enum values. Ciò consente di eseguire operazioni come questa.This allows you to do things like this.

struct MyPage : Page
{
    void DoSomething()
    {
        Visibility(Visibility::Collapsed); // No ambiguity here (special exception).
    }
}

La chiamata a Visibility() viene risolta nel nome della funzione membro UIElement.Visibility.The call to Visibility() resolves to the UIElement.Visibility member function name. Il parametro Visibility::Collapsed segue tuttavia la parola Visibility con :: e quindi il nome del metodo viene ignorato e il compilatore trova la classe enum.But the parameter Visibility::Collapsed follows the word Visibility with ::, and so the method name is ignored, and the compiler finds the enum class.

API importantiImportant APIs