Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este tema se muestra cómo consumir API de C++/WinRT, tanto si forman parte de Windows, como si son implementadas por un proveedor de componentes de terceros o implementadas por usted mismo.
Important
Para que los ejemplos de código de este tema sean breves y fáciles de probar, puedes reproducirlos creando un nuevo proyecto de aplicación de consola de Windows (C++/WinRT) y copiando y pegando el código. Sin embargo, no puede consumir tipos de Windows Runtime personalizados arbitrarios (de terceros) desde una aplicación sin empaquetar como esa. Solo se pueden consumir tipos de Windows de esa forma.
Para consumir tipos personalizados de Windows Runtime (de terceros) desde una aplicación de consola, tendrá que proporcionar a la aplicación una identidad de paquete para que pueda resolver el registro de los tipos personalizados usados. Para obtener más información, consulta Windows application packaging Project.
Como alternativa, crea un nuevo proyecto a partir de la plantilla de proyecto Aplicación en blanco, empaquetada (WinUI 3 de escritorio) para C++ o de la plantilla Componente de Windows Runtime (C++/WinRT). Esos tipos de aplicación ya tienen una identidad de paquete.
Si la API está en un espacio de nombres de Windows
Este es el caso más común en el que consumirá una API de Windows Runtime. Para cada tipo de un espacio de nombres de Windows definido en metadatos, C++/WinRT define un equivalente descriptivo de C++(denominado tipo proyectado). Un tipo proyectado tiene el mismo nombre completo que el tipo de Windows, pero se coloca en el espacio de nombres winrt de C++ mediante la sintaxis de C++. Por ejemplo, Windows::Foundation::Uri se proyecta en C++/WinRT como winrt::Windows::Foundation::Uri.
Este es un ejemplo de código sencillo. Si desea copiar y pegar los ejemplos de código siguientes directamente en el archivo de código fuente principal de un proyecto de aplicación de consola de Windows (C++/WinRT), establezca primero No usar encabezados precompilados en las propiedades del proyecto.
// 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");
}
El encabezado winrt/Windows.Foundation.h incluido forma parte del SDK, que se encuentra dentro de la carpeta %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\. Los encabezados de esa carpeta contienen tipos de espacio de nombres de Windows proyectados a C++/WinRT. En este ejemplo, winrt/Windows.Foundation.h contiene winrt::Windows::Foundation::Uri, que es el tipo proyectado para la clase en tiempo de ejecución Windows::Foundation::Uri.
Tip
Siempre que quiera usar un tipo de un espacio de nombres de Windows, incluya el encabezado C++/WinRT correspondiente a ese espacio de nombres. Las using namespace directivas son opcionales, pero convenientes.
En el ejemplo de código anterior, después de inicializar C++/WinRT, asignamos en la pila un valor del tipo proyectado winrt::Windows::Foundation::Uri mediante uno de sus constructores públicos documentados (Uri(String), en este ejemplo). Para este, que es el caso de uso más común, normalmente eso es todo lo que hay que hacer. Una vez que tenga un valor de tipo proyectado de C++/WinRT, puede tratarlo como si fuera una instancia del tipo de Windows Runtime real, ya que tiene todos los mismos miembros.
De hecho, ese valor proyectado es un proxy; es esencialmente solo un puntero inteligente a un objeto subyacente. Los constructores del valor proyectado llaman a RoActivateInstance para crear una instancia de la clase de Windows Runtime de respaldo (Windows. Foundation.Uri, en este caso) y almacenan la interfaz predeterminada del objeto dentro del nuevo valor proyectado. Como se muestra a continuación, las llamadas a los miembros del valor proyectado en realidad se delegan, a través del puntero inteligente, al objeto subyacente; que es donde se producen los cambios de estado.
Cuando el contosoUri valor está fuera del ámbito, se destructiza y libera su referencia a la interfaz predeterminada. Si esa referencia es la última referencia al objeto Windows.Foundation.Uri subyacente de Windows Runtime, el objeto subyacente también se destruye.
Tip
Un tipo proyectado es una encapsulación de un tipo de Windows Runtime para consumir sus API. Por ejemplo, una interfaz proyectada es un encapsulado de una interfaz de Windows Runtime.
Encabezados de proyección de C++/WinRT
Para consumir las API del espacio de nombres de Windows desde C++/WinRT, se incluyen encabezados de la carpeta %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt. Debe incluir los encabezados correspondientes a cada espacio de nombres que use.
Por ejemplo, para el espacio de nombres Windows::Security::Cryptography::Certificates, las definiciones de tipos de C++/WinRT equivalentes residen en winrt/Windows.Security.Cryptography.Certificates.h. Incluir ese encabezado proporciona acceso a todos los tipos del espacio de nombres Windows::Security::Cryptography::Certificates.
A veces, un archivo de cabecera de un espacio de nombres incluye partes de los archivos de cabecera de espacios de nombres relacionados, pero no deberías confiar en este detalle de implementación. Incluya explícitamente los encabezados de los espacios de nombres que use.
Por ejemplo, el método Certificate::GetCertificateBlob devuelve una interfaz Windows::Storage::Streams::IBuffer.
Antes de llamar al método Certificate::GetCertificateBlob, debe incluir el archivo de encabezado del espacio de nombres winrt/Windows.Storage.Streams.h para poder recibir y trabajar con el Windows::Storage::Streams::IBuffer devuelto.
Olvidar incluir los encabezados de espacio de nombres necesarios antes de usar tipos en ese espacio de nombres es un origen común de errores de compilación.
Acceso a los miembros a través del objeto, a través de una interfaz o a través de la ABI
Con la proyección de C++/WinRT, la representación en tiempo de ejecución de una clase Windows Runtime no es más que las interfaces ABI subyacentes. Pero, para su comodidad, puede codificar contra las clases de la manera en que su autor pretendía. Por ejemplo, puede llamar al método ToString de un URI como si fuera un método de la clase (de hecho, en segundo plano, es un método en la interfaz IStringable independiente).
WINRT_ASSERT es una definición de macro y se expande a _ASSERTE.
Uri contosoUri{ L"http://www.contoso.com" };
WINRT_ASSERT(contosoUri.ToString() == L"http://www.contoso.com/"); // QueryInterface is called at this point.
Esta comodidad se logra a través de una consulta para la interfaz adecuada. Pero siempre estás en control. Puede optar por renunciar a parte de esa comodidad a cambio de un poco más de rendimiento obteniendo usted mismo la interfaz IStringable y usándola directamente. En el ejemplo de código siguiente, obtendrá un puntero de interfaz IStringable real en tiempo de ejecución (a través de una consulta única). Después, la llamada a ToString es directa y evita cualquier llamada adicional a QueryInterface.
...
IStringable stringable = contosoUri; // One-off QueryInterface.
WINRT_ASSERT(stringable.ToString() == L"http://www.contoso.com/");
Puede elegir esta técnica si sabe que va a llamar a varios métodos en la misma interfaz.
Por cierto, si realmente quiere acceder a los miembros a nivel de ABI, puede hacerlo. En el ejemplo de código siguiente se muestra cómo y hay más detalles y ejemplos de código en Interoperabilidad entre C++/WinRT y 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.
}
Inicialización retrasada
En C++/WinRT, cada tipo proyectado tiene un constructor std::nullptr_t de C++/WinRT especial. Salvo ese, todos los constructores proyectados, incluido el constructor predeterminado, provocan la creación de un objeto subyacente de Windows Runtime y le proporcionan un puntero inteligente. Por lo tanto, esa regla se aplica en cualquier lugar en el que se use el constructor predeterminado, como variables locales sin inicializar, variables globales sin inicializar y variables de miembro no inicializadas.
Si, por otro lado, desea construir una variable de un tipo proyectado sin que, a su vez, construya un objeto de respaldo Windows Runtime (para que pueda retrasar ese trabajo hasta más adelante), puede hacerlo. Declare su variable o campo usando ese constructor especial std::nullptr_t de C++/WinRT (que la proyección de C++/WinRT inserta en cada clase del entorno de ejecución). Usamos ese constructor especial con m_gamerPicBuffer en el ejemplo de código siguiente.
#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();
}
Todos los constructores del tipo proyectado excepto el constructor std::nullptr_t hacen que se cree un objeto Windows Runtime de respaldo. El constructor std::nullptr_t es esencialmente un no-op. Espera que el objeto proyectado se inicialice en un momento posterior. Por lo tanto, si una clase en tiempo de ejecución tiene un constructor predeterminado o no, puede usar esta técnica para una inicialización retrasada eficaz.
Esta consideración afecta a otros lugares en los que se invoca el constructor predeterminado, como en vectores y mapas. Considere este ejemplo de código, para el cual necesitará una Aplicación en blanco, empaquetada (WinUI 3 de escritorio) para un proyecto de C++.
std::map<int, TextBlock> lookup;
lookup[2] = value;
La asignación crea un nuevo TextBlock y luego lo sobrescribe inmediatamente con value. Este es el remedio.
std::map<int, TextBlock> lookup;
lookup.insert_or_assign(2, value);
Consulte también Cómo afecta el constructor predeterminado a las colecciones.
No retrase la inicialización por error
Tenga cuidado de que no invoque el constructor std::nullptr_t por error. La resolución de conflictos del compilador le da preferencia frente a los constructores de fábrica. Por ejemplo, considere estas dos definiciones de clase en tiempo de ejecución.
// GiftBox.idl
runtimeclass GiftBox
{
GiftBox();
}
// Gift.idl
runtimeclass Gift
{
Gift(GiftBox giftBox); // You can create a gift inside a box.
}
Supongamos que queremos construir un Regalo que no esté dentro de una caja (un Regalo construido con una GiftBox sin inicializar). En primer lugar, echemos un vistazo a la manera incorrecta de hacerlo. Sabemos que hay un constructor Gift que toma un GiftBox. Pero si estamos tentados a pasar un GiftBox nulo (invocando el constructor Gift a través de la inicialización uniforme, como hacemos a continuación), no obtendremos el resultado que queremos.
// 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) };
Lo que consigues aquí es un regalo no inicializado. No obtienes un regalo con un GiftBox sin inicializar. Esta es la manera correcta de hacerlo.
// 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 }) };
En el ejemplo incorrecto, pasar un valor literal nullptr hace que se elija el constructor con inicialización diferida. Para resolver en favor del constructor de fábrica, el tipo del parámetro debe ser un GiftBox. Aún puede pasar un GiftBox con inicialización retrasada explícitamente, como se muestra en el ejemplo correcto.
Este ejemplo siguiente también es correcto, ya que el parámetro tiene el tipo GiftBox y no std::nullptr_t.
GiftBox giftBox{ nullptr };
Gift gift{ giftBox }; // Calls factory constructor.
La ambigüedad solo surge cuando se pasa un nullptr literal.
No copie la construcción por error.
Esta precaución es similar a la descrita en la sección No retrasar la inicialización por error anterior.
Además del constructor con inicialización diferida, la proyección de C++/WinRT también incorpora un constructor de copia en cada clase del entorno de ejecución. Es un constructor de un solo parámetro que acepta el mismo tipo que el objeto que se va a construir. El puntero inteligente resultante apunta al mismo objeto subyacente de Windows Runtime que el señalado por su parámetro del constructor. El resultado son dos punteros inteligentes que apuntan al mismo objeto subyacente.
Esta es una definición de clase en tiempo de ejecución que usaremos en los ejemplos de código.
// GiftBox.idl
runtimeclass GiftBox
{
GiftBox(GiftBox biggerBox); // You can place a box inside a bigger box.
}
Supongamos que queremos construir una GiftBox dentro de otra GiftBox más grande.
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) };
La manera correcta de hacerlo es llamar explícitamente a la factoría de activación.
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) };
Si la API se implementa en un componente de Windows Runtime
Esta sección se aplica tanto si ha creado el componente usted mismo como si procede de un proveedor.
Note
Para obtener información sobre cómo instalar y usar la extensión de Visual Studio de C++/WinRT (VSIX) y el paquete NuGet (que juntos proporcionan compatibilidad con la compilación y la plantilla de proyecto), consulta Visual Studio compatibilidad con C++/WinRT.
En el proyecto de la aplicación, haga referencia al archivo de metadatos de Windows Runtime (.winmd) del componente y compile el proyecto. Durante la compilación, la cppwinrt.exe herramienta genera una biblioteca estándar de C++ que describe completamente (o proyectos) la superficie de API del componente. En otras palabras, la biblioteca generada contiene los tipos proyectados para el componente.
A continuación, al igual que para un tipo de espacio de nombres de Windows, se incluye un encabezado y se construye el tipo proyectado a través de uno de sus constructores. El código de inicio del proyecto de aplicación registra la clase en tiempo de ejecución y el constructor del tipo proyectado llama a RoActivateInstance para activar la clase en tiempo de ejecución desde el componente al que se hace referencia.
#include <winrt/ThermometerWRC.h>
struct App : AppT<App>
{
ThermometerWRC::Thermometer thermometer;
...
};
Para obtener más información, código y una guía sobre cómo consumir las API implementadas en un componente de Windows Runtime, consulte Componentes de Windows Runtime con C++/WinRT y Crear eventos en C++/WinRT.
Si la API se implementa en el proyecto de consumo
El ejemplo de código de esta sección se ha tomado del tema Controles XAML; enlazados a una propiedad de C++/WinRT. Consulte ese tema para obtener más detalles, código y un tutorial sobre cómo consumir una clase en tiempo de ejecución que se implementa en el mismo proyecto que lo consume.
Un tipo que se consume desde la interfaz de usuario XAML debe ser una clase en tiempo de ejecución, incluso si está en el mismo proyecto que el XAML. En este escenario, se genera un tipo proyectado a partir de los metadatos de Windows Runtime de la clase en tiempo de ejecución (.winmd). De nuevo, incluye un encabezado, pero después tiene una opción entre las formas de construcción de la instancia de la clase en tiempo de ejecución de C++/WinRT versión 1.0 o la versión 2.0. El método versión 1.0 usa winrt::make; El método versión 2.0 se conoce como construcción uniforme. Echemos un vistazo a cada uno a su vez.
Construcción mediante winrt::make
Comencemos con el método predeterminado (C++/WinRT versión 1.0), ya que es una buena idea estar al menos familiarizado con ese patrón. Se construye el tipo proyectado mediante su constructor std::nullptr_t. Ese constructor no realiza ninguna inicialización, por lo que debe asignar un valor a la instancia a través de la función auxiliar winrt::make , pasando los argumentos de constructor necesarios. Una clase en tiempo de ejecución implementada en el mismo proyecto que el código consumidor no necesita registrarse ni instanciarse mediante la activación de Windows Runtime/COM.
Consulta Controles XAML; enlazar a una propiedad de C++/WinRT para ver un tutorial completo. En esta sección se muestran los extractos de ese tutorial.
// 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>();
...
}
Construcción uniforme
Con C++/WinRT versión 2.0 y versiones posteriores, hay una forma optimizada de construcción disponible para usted conocido como construcción uniforme (consulte Noticias y cambios, en C++/WinRT 2.0).
Consulta Enlazar controles XAML a una propiedad de C++/WinRT para ver un tutorial completo. En esta sección se muestran los extractos de ese tutorial.
Para usar la construcción uniforme en lugar de winrt::make, necesitará un generador de activación. Una buena manera de generar una es agregar un constructor a su IDL.
// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
MainPage();
BookstoreViewModel MainViewModel{ get; };
}
}
A continuación, en MainPage.h declarar e inicializar m_mainViewModel en un solo paso, como se muestra a continuación.
// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
...
private:
Bookstore::BookstoreViewModel m_mainViewModel;
...
};
}
...
Y, a continuación, en el constructor MainPage de MainPage.cpp, no es necesario el código m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.
Para obtener más información sobre la construcción uniforme y ejemplos de código, vea Opt in to uniform construction (Participar en la construcción uniforme) y acceso directo a la implementación.
Instanciación y devolución de tipos e interfaces proyectados
Este es un ejemplo de cómo podrían verse los tipos e interfaces proyectados en el proyecto consumidor. Recuerde que un tipo proyectado (como el de este ejemplo) es generado por herramientas y no es algo que usted mismo escribiría.
struct MyRuntimeClass : MyProject::IMyRuntimeClass, impl::require<MyRuntimeClass,
Windows::Foundation::IStringable, Windows::Foundation::IClosable>
MyRuntimeClass es un tipo proyectado; las interfaces proyectadas incluyen IMyRuntimeClass, IStringable e IClosable. En este tema se muestran las distintas formas en las que se puede crear una instancia de un tipo proyectado. Este es un recordatorio y un resumen, usando MyRuntimeClass como ejemplo.
// 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>();
- Puede acceder a los miembros de todas las interfaces de un tipo proyectado.
- Puede devolver un tipo proyectado a un autor de llamada.
- Los tipos e interfaces proyectados derivan de winrt::Windows::Foundation::IUnknown. Por lo tanto, puedes llamar a IUnknown::as sobre un tipo o una interfaz proyectados para consultar otras interfaces proyectadas, que también puedes usar o devolver al código llamador. La función miembro as funciona como QueryInterface.
void f(MyProject::MyRuntimeClass const& myrc)
{
myrc.ToString();
myrc.Close();
IClosable iclosable = myrc.as<IClosable>();
iclosable.Close();
}
Factorías de activación
La forma cómoda y directa de crear un objeto de C++/WinRT es la siguiente.
using namespace winrt::Windows::Globalization::NumberFormatting;
...
CurrencyFormatter currency{ L"USD" };
Pero puede haber ocasiones en las que quiera crear usted mismo la factoría de activación y, a continuación, crear objetos a partir de ella cuando le convenga. Estos son algunos ejemplos que muestran cómo usar la plantilla de función 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");
Las clases de los dos ejemplos anteriores son tipos de un espacio de nombres Windows. En este ejemplo siguiente, ThermoWRC::Thermo es un tipo personalizado implementado en un componente de Windows Runtime.
auto factory = winrt::get_activation_factory<ThermometerWRC::Thermometer>();
ThermometerWRC::Thermometer thermometer = factory.ActivateInstance<ThermometerWRC::Thermometer>();
Ambigüedades de elemento/tipo
Cuando una función miembro tiene el mismo nombre que un tipo, hay ambigüedad. Las reglas de C++ para la búsqueda no cualificada de nombres en funciones miembro hacen que la búsqueda examine primero la clase antes de buscar en los espacios de nombres. La regla el fallo de sustitución no es un error (SFINAE) no se aplica (se aplica durante la resolución de sobrecargas de plantillas de función). Por lo tanto, si el nombre dentro de la clase no tiene sentido, el compilador no sigue buscando una mejor coincidencia, simplemente notifica un 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>() };
}
}
Arriba, el compilador cree que estás pasando FrameworkElement.Style() (que, en C++/WinRT, es una función miembro) como parámetro de plantilla de IUnknown::as. La solución consiste en forzar que el nombre Style se interprete como el tipo 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>();
}
}
La búsqueda de nombres sin calificar tiene una excepción especial en el caso de que el nombre vaya seguido de ::, en cuyo caso omite las funciones, las variables y los valores de enumeración. Esto le permite hacer cosas como esta.
struct MyPage : Page
{
void DoSomething()
{
Visibility(Visibility::Collapsed); // No ambiguity here (special exception).
}
}
La llamada a Visibility() hace referencia al nombre de la función miembro UIElement.Visibility. Pero el parámetro Visibility::Collapsed sigue la palabra Visibility con ::, por lo que se omite el nombre del método y el compilador encuentra la clase enum.
API importantes
- Función QueryInterface
- Función RoActivateInstance
- clase Windows::Foundation::Uri
- Plantilla de funciones winrt::get_activation_factory
- Plantilla de funciones winrt::make
- estructura winrt::Windows::Foundation::IUnknown