Novedades de C++/WinRT

A medida que se publican versiones posteriores de C++/WinRT, en este tema se describen las novedades y los cambios.

Resumen de mejoras y adiciones recientes hasta marzo de 2020

Tiempos de compilación hasta un 23 % más cortos

Los equipos del compilador de C++/WinRT y C++ han colaborado para hacer todo lo posible para acortar los tiempos de compilación. Hemos analizado minuciosamente las métricas del compilador para determinar cómo pueden reestructurarse los componentes internos de C++/WinRT para ayudar al compilador de C++ a eliminar la sobrecarga durante la compilación, así como cómo puede mejorarse el propio compilador de C++ para gestionar la biblioteca C++/WinRT. C++/WinRT se ha optimizado para el compilador; y el compilador se ha optimizado para C++/WinRT.

Tomemos, por ejemplo, el peor de los casos: crear una cabecera precompilada (PCH) que contiene todas y cada una de las cabeceras de espacio de nombres de proyección de C++/WinRT.

Versión Tamaño de PCH (bytes) Hora (s)
C++/WinRT de julio, con Visual C++ 16.3 3,004,104,632 31
versión 2.0.200316.3 de C++/WinRT, con Visual C++ 16.5 2,393,515,336 24

Una reducción de tamaño de 20% y una reducción de 23% en el tiempo de compilación.

Compatibilidad mejorada con MSBuild

Hemos invertido mucho trabajo en mejorar la compatibilidad de MSBuild con una gran selección de escenarios diferentes.

Almacenamiento en caché de fábrica aún más rápido

Hemos mejorado la integración de la caché de factoría para integrar mejor las rutas críticas, lo que se traduce en una ejecución más rápida.

Esa mejora no afecta al tamaño del código, como se describe a continuación en Optimized EH code-gen, si la aplicación usa el control de excepciones de C++en gran medida, puede reducir el archivo binario mediante la /d2FH4 opción , que está activada de forma predeterminada en los nuevos proyectos creados con Visual Studio 2019 16.3 y versiones posteriores.

Boxeo más eficaz

Cuando se usa en una aplicación XAML, winrt::box_value ahora es más eficaz (consulta Boxing y unboxing). Las aplicaciones que realizan muchas operaciones de "boxing" también notarán una reducción en el tamaño del código.

Compatibilidad para implementar interfaces COM que implementan IInspectable

Si necesitas implementar una interfaz COM (que no sea de Windows Runtime) que simplemente resulta implementar IInspectable, ahora puedes hacerlo con C++/WinRT. Consulte interfaces COM que implementan IInspectable.

Mejoras en el bloqueo de módulos

El control sobre el bloqueo de módulos ahora permite escenarios de hospedaje personalizados y la eliminación del bloqueo de nivel de módulo por completo. Consulte las mejoras del bloqueo de módulos.

Compatibilidad con información de errores que no es de Windows Runtime

Algunas API (incluso algunas API de Windows Runtime) notifican errores sin usar Windows Runtime API de origen de errores. En casos como ese, C++/WinRT ahora recurre a la información de error de COM. Consulta compatibilidad con C++/WinRT para obtener información de error que no sea de WinRT.

Habilitación de la compatibilidad con módulos de C++

La compatibilidad con módulos de C++ vuelve, pero solo en forma experimental. La característica aún no está completa en el compilador de C++.

Reanudación de corrutina más eficaz

Las corrutinas de C++/WinRT ya funcionan bien, pero seguimos buscando formas de mejorar eso. Consulte Mejorar la escalabilidad de la reanudación de corrutinas.

Nuevos asistentes asincrónicos de when_all y when_any

La función auxiliar when_all crea un objeto IAsyncAction que se completa cuando se han completado todos los awaitables proporcionados. El asistente when_any crea una IAsyncAction que se completa cuando se completa cualquiera de las operaciones que se pueden esperar proporcionadas.

Consulte Agregar el asistente asíncrono when_any y Agregar el asistente asíncrono when_all.

Otras optimizaciones y adiciones

Además, se han introducido muchas correcciones de errores y optimizaciones secundarias y adiciones, incluidas varias mejoras para simplificar la depuración y optimizar las implementaciones internas y predeterminadas. Siga este vínculo para obtener una lista exhaustiva: https://github.com/microsoft/xlang/pulls?q=is%3Apr+is%3Aclosed.

Noticias y cambios, en C++/WinRT 2.0

Para obtener más información sobre la extensión de Visual Studio para C++/WinRT (VSIX), el paquete NuGet Microsoft.Windows.CppWinRT y la herramienta cppwinrt.exe —incluido cómo obtenerlos e instalarlos—, consulta Compatibilidad de Visual Studio con C++/WinRT, XAML, la extensión VSIX y el paquete NuGet.

Cambios en la extensión de Visual Studio de C++/WinRT para la versión 2.0

  • El visualizador de depuración ahora admite Visual Studio 2019 y sigue siendo compatible con Visual Studio 2017.
  • Se han realizado numerosas correcciones de errores.

Cambios en el paquete NuGet Microsoft.Windows.CppWinRT para la versión 2.0

  • La herramienta cppwinrt.exe ahora está incluida en el paquete NuGet Microsoft.Windows.CppWinRT, y genera encabezados de proyección de plataforma para cada proyecto según sea necesario. Por lo tanto, la cppwinrt.exe herramienta ya no depende del SDK de Windows (aunque la herramienta todavía se incluye con el SDK por motivos de compatibilidad).
  • cppwinrt.exe ahora genera encabezados de proyección en cada carpeta intermedia específica de la plataforma o configuración ($IntDir) para habilitar compilaciones paralelas.
  • El soporte de compilación de C++/WinRT (props/targets) ya está completamente documentado, por si quiere personalizar manualmente los archivos de proyecto. Consulte el archivo Léame del paquete NuGet Microsoft.Windows.CppWinRT.
  • Se han realizado numerosas correcciones de errores.

Cambios en C++/WinRT para la versión 2.0

Código Abierto

La cppwinrt.exe herramienta toma un archivo de metadatos de Windows Runtime (.winmd) y genera a partir de él una biblioteca estándar de C++ basada en archivos de encabezado que proyecta las API descritas en los metadatos. De este modo, puede consumir esas API desde el código de C++/WinRT.

Esta herramienta ahora es un proyecto completamente código abierto, disponible en GitHub. Visite Microsoft/cppwinrt.

Bibliotecas de xlang

Una biblioteca de solo encabezado completamente portátil (para analizar el formato de metadatos ECMA-335 utilizado por el Windows Runtime) constituye la base de todas las herramientas de Windows Runtime y xlang en el futuro. Cabe destacar que también reescribimos desde cero la herramienta cppwinrt.exe utilizando las bibliotecas xlang. Esto proporciona consultas de metadatos mucho más precisas, solucionando algunos problemas de larga duración con la proyección del lenguaje C++/WinRT.

Menos dependencias

Debido al lector de metadatos de xlang, la cppwinrt.exe propia herramienta tiene menos dependencias. Esto hace que sea mucho más flexible, además de ser utilizable en más escenarios, especialmente en entornos de compilación restringidos. En particular, ya no se basa en RoMetadata.dll.   Estas son las dependencias para cppwinrt.exe 2.0.  

  • ADVAPI32.dll
  • KERNEL32.dll
  • SHLWAPI.dll
  • XmlLite.dll

Todos esos archivos DLL están disponibles no solo en Windows 10, sino también en Windows 7, e incluso Windows Vista. Si lo desea, su antiguo servidor de compilación con Windows 7 ahora puede ejecutar cppwinrt.exe para generar encabezados de C++ para su proyecto. Con un poco de trabajo, incluso puedes ejecutar C++/WinRT en Windows 7, si eso te interesa.

Contraste la lista anterior con estas dependencias, que la versión 1.0 cppwinrt.exe tiene.

  • ADVAPI32.dll
  • SHELL32.dll
  • api-ms-win-core-file-l1-1-0.dll
  • XmlLite.dll
  • api-ms-win-core-libraryloader-l1-2-0.dll
  • api-ms-win-core-processenvironment-l1-1-0.dll
  • RoMetadata.dll
  • SHLWAPI.dll
  • KERNEL32.dll
  • api-ms-win-core-rtlsupport-l1-1-0.dll
  • api-ms-win-core-heap-l1-1-0.dll
  • api-ms-win-core-timezone-l1-1-0.dll
  • api-ms-win-core-console-l1-1-0.dll
  • api-ms-win-core-localization-l1-2-0.dll
  • OLEAUT32.dll
  • api-ms-win-core-winrt-error-l1-1-0.dll
  • api-ms-win-core-winrt-error-l1-1-1.dll
  • api-ms-win-core-winrt-l1-1-0.dll
  • api-ms-win-core-winrt-string-l1-1-0.dll
  • api-ms-win-core-synch-l1-1-0.dll
  • api-ms-win-core-threadpool-l1-2-0.dll
  • api-ms-win-core-com-l1-1-0.dll
  • api-ms-win-core-com-l1-1-1.dll
  • api-ms-win-core-synch-l1-2-0.dll

El atributo Windows Runtime noexcept

El Windows Runtime tiene un nuevo [noexcept] atributo, que puede usar para decorar los métodos y propiedades en MIDL 3.0. La presencia del atributo indica a las herramientas auxiliares que la implementación no produce una excepción (ni devuelve un HRESULT con error). Esto permite que las proyecciones de lenguaje optimicen la generación de código evitando la sobrecarga de control de excepciones necesaria para admitir llamadas de interfaz binaria de aplicaciones (ABI) que pueden producir errores.

C++/WinRT aprovecha esto generando implementaciones de C++ noexcept tanto del código de consumo como del de creación. Si tiene métodos o propiedades de API que no tienen errores y le preocupa el tamaño del código, puede investigar este atributo.

Generación de código optimizada

C++/WinRT ahora genera código fuente de C++ aún más eficaz (en segundo plano) para que el compilador de C++ pueda generar el código binario más pequeño y eficaz posible. Muchas de las mejoras están dirigidas a reducir el coste del manejo de excepciones evitando la información de desenrollado innecesaria. Los archivos binarios que usan grandes cantidades de código de C++/WinRT verán aproximadamente una reducción de 4% en el tamaño del código. El código también es más eficaz (se ejecuta más rápido) debido al número reducido de instrucciones.

Estas mejoras se basan en una nueva característica de interoperabilidad que también está disponible para usted. Todos los tipos de C++/WinRT que son propietarios de recursos ahora incluyen un constructor para tomar posesión directamente, evitando el enfoque de dos pasos anterior.

ABI::Windows::Foundation::IStringable* raw = ...

IStringable projected(raw, take_ownership_from_abi);

printf("%ls\n", projected.ToString().c_str());

Generación de código optimizada para el control de excepciones (EH)

Este cambio complementa el trabajo realizado por el equipo del optimizador de C++ de Microsoft para reducir el costo del control de excepciones. Si usa interfaces binarias de aplicación (ABA) (por ejemplo, COM) en gran medida en el código, observará una gran cantidad de código siguiendo este patrón.

int32_t Function() noexcept
{
    try
    {
        // code here constitutes unique value.
    }
    catch (...)
    {
        // code here is always duplicated.
    }
}

C++/WinRT genera este patrón para cada API que se implementa. Con miles de funciones de API, cualquier optimización aquí puede ser significativa. En el pasado, el optimizador no detectaba que todos esos bloques `catch` eran idénticos, por lo que duplicaba mucho código en torno a cada ABI (lo que, a su vez, contribuyó a la creencia de que usar excepciones en el código del sistema produce binarios de gran tamaño). Sin embargo, a partir de Visual Studio 2019, el compilador de C++ fusiona todos esos funclets de catch y solo almacena los únicos. El resultado es una reducción adicional y general de 18% en el tamaño del código para los archivos binarios que dependen en gran medida de este patrón. No solo es el código EH ahora más eficaz que el uso de códigos de retorno, pero también la preocupación por los archivos binarios más grandes es ahora algo del pasado.

Mejoras de compilación incrementales

La cppwinrt.exe herramienta ahora compara la salida de un archivo de encabezado o origen generado con el contenido de cualquier archivo existente en el disco y solo escribe el archivo si el archivo ha cambiado de hecho. Esto ahorra un tiempo considerable con la E/S de disco y garantiza que el compilador de C++ no considera "sucios" los archivos. El resultado es que se evita o reduce la recompilación, en muchos casos.

Ahora se generan todas las interfaces genéricas

Debido al lector de metadatos xlang, C++/WinRT ahora genera todas las interfaces parametrizadas o genéricas a partir de metadatos. Las interfaces como Windows::Foundation::Collections::IVector<T> ahora se generan a partir de metadatos en lugar de escribirse a mano en winrt/base.h. El resultado es que el tamaño de winrt/base.h se ha recortado a la mitad y que las optimizaciones se generan directamente en el código (lo que era difícil de hacer con el enfoque enrollado a mano).

Important

Las interfaces como el ejemplo dado ahora aparecen en sus respectivos encabezados de espacio de nombres, en lugar de en winrt/base.h. Así que, si aún no lo has hecho, tendrás que incluir la cabecera del espacio de nombres adecuada para poder utilizar la interfaz.

Optimizaciones de componentes

Esta actualización agrega compatibilidad con varias optimizaciones de participación adicionales para C++/WinRT, que se describen en las secciones siguientes. Dado que estas optimizaciones son cambios incompatibles (para los que quizá debas hacer pequeños cambios a fin de darles soporte), tendrás que activarlas explícitamente. En Visual Studio, establezca la propiedad de proyecto Propiedades> comunesC++/WinRT>Optimizadas en . Esto tiene el efecto de agregar <CppWinRTOptimized>true</CppWinRTOptimized> al archivo del proyecto. Y tiene el mismo efecto que añadir el modificador -opt[imize] al ejecutar cppwinrt.exe desde la línea de comandos.

Un nuevo proyecto (de una plantilla de proyecto) usará -opt de forma predeterminada.

Construcción uniforme y acceso directo a la implementación

Estas dos optimizaciones permiten que el componente acceda directamente a sus propios tipos de implementación, incluso cuando solo usa los tipos proyectados. No es necesario usar make, make_self ni get_self si simplemente desea usar la superficie de API pública. Tus llamadas se compilarán como llamadas directas a la implementación, y puede que incluso se integren completamente en línea.

Para obtener más información y ejemplos de código, consulte Activar la construcción uniforme y el acceso directo a implementaciones.

Factorías con borrado de tipos

Esta optimización evita las dependencias de #include en module.g.cpp para que no sea necesario volver a compilar cada vez que se produzca un cambio en cualquier clase de implementación única. El resultado es una mejora del rendimiento de la compilación.

Más inteligente y eficaz module.g.cpp para proyectos grandes con varias bibliotecas

El module.g.cpp archivo ahora también contiene dos asistentes de composición adicionales, denominados winrt_can_unload_now y winrt_get_activation_factory. Estos se han diseñado para proyectos más grandes en los que un archivo DLL se compone de una serie de bibliotecas, cada una con sus propias clases en tiempo de ejecución. En esa situación, tienes que vincular manualmente DllGetActivationFactory y DllCanUnloadNow de la DLL. Estas utilidades te facilitan mucho hacerlo al evitar falsos errores de originación. La herramienta cppwinrt.exe también puede usar la opción -lib para dar a cada biblioteca su propio preámbulo (en lugar de winrt_xxx), de modo que las funciones de cada biblioteca puedan nombrarse individualmente y, por tanto, combinarse sin ambigüedad.

Compatibilidad con corrutinas

La compatibilidad con corrutinas se incluye automáticamente. Anteriormente, la asistencia estaba distribuida en varios lugares, lo que nos parecía demasiado limitado. Y, después, temporalmente para v2.0, era necesario un winrt/coroutine.h archivo de encabezado, pero eso ya no es necesario. Dado que las interfaces asincrónicas de Windows Runtime ahora se generan, en lugar de estar escritas a mano, ahora residen en winrt/Windows.Foundation.h. Además de ser más fácil de mantener y de dar soporte, significa que las funciones auxiliares de corrutina, como resume_foreground, ya no tienen que añadirse al final del archivo de encabezado de un espacio de nombres concreto. En su lugar, pueden incluir más naturalmente sus dependencias. Esto permite además a resume_foreground admitir no solo la reanudación en un Windows::UI::Core::CoreDispatcher, sino también, ahora, la reanudación en un Windows::System::DispatcherQueue determinado. Anteriormente, solo se podía admitir una; pero no ambos, ya que la definición solo podía residir en un espacio de nombres.

Este es un ejemplo de la compatibilidad con DispatcherQueue .

...
#include <winrt/Windows.System.h>
using namespace Windows::System;
...
fire_and_forget Async(DispatcherQueueController controller)
{
    bool queued = co_await resume_foreground(controller.DispatcherQueue());
    assert(queued);

    // This is just to simulate queue failure...
    co_await controller.ShutdownQueueAsync();

    queued = co_await resume_foreground(controller.DispatcherQueue());
    assert(!queued);
}

Los asistentes de corrutina ahora también están decorados con [[nodiscard]], mejorando así su facilidad de uso. Si olvidas (o no te das cuenta de que tienes que) usar co_await para que funcionen, debido a [[nodiscard]], esos errores ahora generan una advertencia del compilador.

Ayuda para diagnosticar asignaciones directas (stack)

Dado que los nombres de las clases proyectadas y de implementación son iguales de forma predeterminada y solo difieren por el espacio de nombres, es posible confundir una con la otra y crear accidentalmente una implementación en la pila, en vez de usar la familia de funciones auxiliares make. Esto puede ser difícil de diagnosticar en algunos casos, ya que el objeto puede destruirse mientras las referencias pendientes siguen activas. Ahora una aserción lo detecta en las compilaciones de depuración. Aunque la aserción no detecta la asignación de pila dentro de una corrutina, resulta útil detectar la mayoría de estos errores.

Para obtener más información, consulta Diagnóstico de asignaciones directas.

Asistentes de captura mejorados y delegados variádicos

Esta actualización corrige también la limitación con los asistentes de captura al admitir tipos proyectados. Esto surge de vez en cuando con las API de interoperabilidad de Windows Runtime, cuando devuelven un tipo proyectado.

Esta actualización también agrega compatibilidad con get_strong y get_weak al crear un delegado variádico (no Windows Runtime).

Compatibilidad con la destrucción diferida y la qi segura durante la destrucción

No es raro que el destructor de un objeto de clase en tiempo de ejecución llame a un método que aumente temporalmente el recuento de referencias. Cuando el recuento de referencias vuelve a cero, el objeto se destruce una segunda vez. En una aplicación XAML, es posible que tengas que realizar una QueryInterface (QI) desde un destructor para invocar alguna implementación de limpieza en un nivel superior o inferior de la jerarquía. Pero el recuento de referencias del objeto ya ha alcanzado cero, de modo que QI constituye también un rebote de recuento de referencias.

Esta actualización añade compatibilidad con la aplicación de antirrebote al recuento de referencias, garantizando que, una vez que llegue a cero, nunca pueda volver a activarse, sin dejar de permitir hacer QI para cualquier objeto temporal que necesites durante la destrucción. Este procedimiento es inevitable en ciertas aplicaciones/controles XAML, y C++/WinRT ahora es resistente a él.

Puede posponer la destrucción proporcionando una función estática final_release en su tipo de implementación. El último puntero restante al objeto, en forma de std::unique_ptr, se pasa al final_release. A continuación, puede optar por mover la propiedad de ese puntero a otro contexto. Es seguro para usted qi el puntero sin desencadenar una destrucción doble. Pero el cambio neto al recuento de referencias debe ser cero en el punto en que se destructe el objeto.

El valor devuelto de final_release puede ser void, un objeto de operación asincrónico como IAsyncAction o winrt::fire_and_forget.

struct Sample : implements<Sample, IStringable>
{
    hstring ToString()
    {
        return L"Sample";
    }

    ~Sample()
    {
        // Called when the unique_ptr below is reset.
    }

    static void final_release(std::unique_ptr<Sample> self) noexcept
    {
        // Move 'self' as needed to delay destruction.
    }
};

En el ejemplo siguiente, una vez que se libera MainPage (por última vez), se llama a final_release. Esa función pasa cinco segundos esperando (en el grupo de hilos) y, a continuación, reanuda su ejecución usando el Dispatcher de la página (que requiere QI/AddRef/Release para funcionar). A continuación, limpia un recurso en ese subproceso de interfaz de usuario. Y finalmente borra el unique_ptr, lo que hace que realmente se llame al destructor MainPage . Incluso en ese destructor, se invoca DataContext, lo que requiere un QI para IFrameworkElement.

No es necesario implementar final_release como una corrutina. Pero eso funciona y hace que sea muy sencillo mover la destrucción a un subproceso diferente, que es lo que sucede en este ejemplo.

struct MainPage : PageT<MainPage>
{
    MainPage()
    {
    }

    ~MainPage()
    {
        DataContext(nullptr);
    }

    static IAsyncAction final_release(std::unique_ptr<MainPage> self)
    {
        co_await 5s;

        co_await resume_foreground(self->Dispatcher());
        co_await self->resource.CloseAsync();

        // The object is destructed normally at the end of final_release,
        // when the std::unique_ptr<MyClass> destructs. If you want to destruct
        // the object earlier than that, then you can set *self* to `nullptr`.
        self = nullptr;
    }
};

Para obtener más información, consulta Destrucción diferida.

Compatibilidad mejorada con la herencia de interfaz única de tipo COM

Además de utilizarse para la programación de Windows Runtime, C++/WinRT también se utiliza para crear y usar API exclusivamente COM. Esta actualización permite implementar un servidor COM donde existe una jerarquía de interfaz. Esto no es necesario para el Windows Runtime; pero es necesario para algunas implementaciones COM.

Manejo correcto de los parámetros out

Puede resultar complicado trabajar con out parámetros; especialmente Windows Runtime matrices. Con esta actualización, C++/WinRT es considerablemente más robusto y tolerante a errores en lo que respecta a out params y matrices, tanto si esos parámetros llegan a través de una proyección de lenguaje como si proceden de un desarrollador de COM que usa la ABI nativa y comete el error de no inicializar las variables de forma coherente. En cualquier caso, C++/WinRT ahora hace lo correcto a la hora de transferir tipos proyectados a la ABI (asegurándose de liberar cualquier recurso) y de poner a cero o limpiar los parámetros que se reciben a través de la ABI.

Los eventos ahora gestionan correctamente los tokens no válidos

La implementación de winrt::event ahora controla correctamente el caso en el que se llama a su método remove con un valor de token no válido (un valor que no está presente en la matriz).

Las variables locales de las corrutinas ahora se destruyen antes de que la corrutina retorne.

La forma tradicional de implementar un tipo de corrutina puede permitir que las variables locales de la corrutina se destruyan después de que la corrutina retorne o finalice (en lugar de antes de la suspensión final). La reanudación de cualquier waiter ahora se aplaza hasta la suspensión final, con el fin de evitar este problema y acumular otras ventajas.

Noticias y cambios, en Windows SDK versión 10.0.17763.0 (Windows 10, versión 1809)

La tabla siguiente contiene noticias y cambios para C++/WinRT en la versión 10.0.17763.0 del SDK de Windows (Windows 10, versión 1809).

Característica nueva o modificada Más información
Cambio importante. Para que se compile, C++/WinRT no depende de los encabezados del SDK de Windows. Consulte Aislamiento de los archivos de encabezado del SDK de Windows, a continuación.
El formato del sistema del proyecto de Visual Studio ha cambiado. Vea Cómo cambiar el destino de su proyecto de C++/WinRT a una versión posterior del SDK de Windows, a continuación.
Hay nuevas funciones y clases base que le ayudarán a pasar un objeto de colección a una función Windows Runtime, o para implementar sus propias propiedades de colección y tipos de colección. Consulta Colecciones con C++/WinRT.
Puede usar la extensión de marcado {Binding} con las clases en tiempo de ejecución de C++/WinRT. Para obtener más información y ejemplos de código, consulte Introducción al enlace de datos.
La compatibilidad con la cancelación de una corrutina permite registrar una devolución de llamada de cancelación. Para obtener más información y ejemplos de código, consulte Cancelar una operación asíncrona y funciones de devolución de llamada de cancelación.
Al crear un delegado que apunte a una función miembro, puede crear una referencia fuerte o débil al objeto actual (en lugar de un puntero this sin formato) en el momento en que se registra el controlador. Para obtener más información y ejemplos de código, consulte la subsección Si usa una función miembro como delegado en la sección Acceso seguro al puntero this con un delegado de control de eventos.
Los errores se corrigen que fueron descubiertos por la conformidad mejorada de Visual Studio con el estándar de C++. La cadena de herramientas LLVM y Clang también se aprovecha mejor para validar la conformidad de los estándares de C++/WinRT. Ya no encontrará el problema descrito en ¿Por qué no se compilará mi nuevo proyecto? Uso Visual Studio 2017 (versión 15.8.0 o posterior) y sdk versión 17134

Otros cambios.

  • Cambio importante. winrt::get_abi(winrt::hstring const&) ahora devuelve void* en lugar de HSTRING. Puede usar static_cast<HSTRING>(get_abi(my_hstring)); para obtener un HSTRING. Consulte Interoperar con el HSTRING de ABI.
  • Cambio importante. winrt::put_abi(winrt::hstring&) ahora devuelve void** en lugar de HSTRING*. Puede usar reinterpret_cast<HSTRING*>(put_abi(my_hstring)); para obtener un HSTRING*. Consulte Interoperar con el HSTRING de ABI.
  • Cambio importante. HRESULT ahora se proyecta como winrt::hresult. Si necesitas un HRESULT (para realizar la comprobación de tipos o para admitir rasgos de tipo), puedes static_cast usar winrt::hresult. De lo contrario, winrt::hresult se convierte en HRESULT, siempre y cuando incluya unknwn.h antes de incluir los encabezados de C++/WinRT.
  • Cambio importante. El GUID ahora se proyecta como winrt::guid. Para las API que implemente, debe usar winrt::guid para los parámetros GUID. De lo contrario, winrt::guid se convierte en GUID, siempre que incluya unknwn.h antes de incluir los encabezados de C++/WinRT. Consulte Interoperación con la estructura GUID de la ABI.
  • Cambio importante. El constructor de winrt::handle_type se ha reforzado haciéndolo explícito (ahora es más difícil escribir código incorrecto al usarlo). Si necesita asignar un valor bruto de un descriptor, utilice la función handle_type::attach en su lugar.
  • Cambio importante. Las firmas de WINRT_CanUnloadNow y WINRT_GetActivationFactory han cambiado. No debe declarar estas funciones en absoluto. En su lugar, incluya winrt/base.h (que se incluye automáticamente si incluye algún archivo de encabezado de espacio de nombres de C++/WinRT Windows) para incluir las declaraciones de estas funciones.
  • Para la estructura winrt::clock, from_FILETIME/to_FILETIME han quedado obsoletos en favor de from_file_time/to_file_time.
  • API simplificadas que esperan parámetros de IBuffer . La mayoría de las API prefieren colecciones o matrices. Pero consideramos que debíamos facilitar las llamadas a las API que se basan en IBuffer. Esta actualización proporciona acceso directo a los datos detrás de una implementación de IBuffer . Usa la misma convención de nomenclatura de datos que la que usan los contenedores de la biblioteca estándar de C++. Esa convención también evita colisiones con nombres de metadatos que comienzan convencionalmente con una letra mayúscula.
  • Generación de código mejorada: varias mejoras para reducir el tamaño del código, mejorar la inserción y optimizar el almacenamiento en caché de fábrica.
  • Se ha quitado la recursividad innecesaria. Cuando la línea de comandos hace referencia a una carpeta, en lugar de a una específica .winmd, la cppwinrt.exe herramienta ya no busca archivos de forma .winmd recursiva. La cppwinrt.exe herramienta también controla los duplicados de forma más inteligente, lo que hace que sea más resistente al error del usuario y a los archivos con .winmd formato deficiente.
  • Punteros inteligentes reforzados. Anteriormente, los revocadores de eventos no revocaban al asignárseles mediante movimiento un nuevo valor. Esto ayudó a descubrir un problema por el que las clases de punteros inteligentes no gestionaban de forma fiable la autoasignación, cuyo origen estaba en la plantilla de la estructura winrt::com_ptr. winrt::com_ptr se ha corregido, y también se han corregido los revocadores de eventos para gestionar correctamente la semántica de movimiento, de modo que se revoquen al realizar una asignación.

Important

Se realizaron cambios importantes en la extensión de Visual Studio de C++/WinRT (VSIX), ambas en la versión 1.0.181002.2 y, después, en la versión 1.0.190128.4. Para obtener más información sobre estos cambios y cómo afectan a los proyectos existentes, Visual Studio compatibilidad con C++/WinRT y versiones anteriores de la extensión VSIX.

Aislamiento respecto a los archivos de cabecera del SDK de Windows

Esto puede ser un cambio importante para el código.

Para que se compile, C++/WinRT ya no depende de los archivos de encabezado del SDK de Windows. Los archivos de encabezado de la biblioteca en tiempo de ejecución de C (CRT) y la biblioteca de plantillas estándar (STL) de C++ tampoco incluyen encabezados de SDK de Windows. Además, mejora el cumplimiento de estándares, evita dependencias involuntarias y reduce considerablemente el número de macros contra las que tiene que protegerse.

Esta independencia significa que C++/WinRT es ahora más portátil y compatible con los estándares, y amplía la posibilidad de convertirse en un compilador y una biblioteca multiplataforma. También significa que los encabezados de C++/WinRT no se ven afectados negativamente por macros.

Si anteriormente lo dejaste en C++/WinRT para incluir los encabezados de Windows en el proyecto, ahora tendrás que incluirlos tú mismo. En cualquier caso, siempre es recomendable incluir explícitamente los encabezados de los que depende y no dejarlos en otra biblioteca para incluirlos por usted.

Actualmente, las únicas excepciones al aislamiento de los archivos de encabezado del SDK de Windows son las funciones intrínsecas y los tipos numéricos. No hay ningún problema conocido con estas últimas dependencias restantes.

En su proyecto, puede volver a habilitar la interoperabilidad con los encabezados del SDK de Windows si lo necesita. Por ejemplo, podrías implementar una interfaz COM (con raíz en IUnknown). Por ejemplo, incluya unknwn.h antes de incluir los encabezados de C++/WinRT. Al hacerlo, la biblioteca base de C++/WinRT habilita varios puntos de enlace para admitir interfaces COM clásicas. Para obtener un ejemplo de código, consulte Creación de componentes COM con C++/WinRT. Del mismo modo, incluya explícitamente cualquier otro encabezado del SDK de Windows que declare tipos o funciones a los que quiera llamar.

Cómo volver a configurar el proyecto de C++/WinRT en una versión posterior del SDK de Windows

El método para cambiar la plataforma de destino de tu proyecto que probablemente dé lugar a menos problemas de compilación y enlace es también el que más trabajo requiere. Este método implica la creación de un nuevo proyecto (destinado a la versión del SDK de Windows que prefiera) y, a continuación, copiar archivos en el nuevo proyecto desde el anterior. Habrá secciones de tus archivos anteriores .vcxproj y .vcxproj.filters que puedes copiar directamente para no tener que añadir archivos en Visual Studio.

Sin embargo, existen otras dos formas de cambiar la plataforma de destino del proyecto en Visual Studio.

  • Vaya a la propiedad del proyecto General>Windows versión del SDK y seleccione Todas las configuraciones y todas las plataformas. Establezca Versión del SDK de Windows en la versión de destino que quiera.
  • En Explorador de soluciones, haga clic con el botón derecho en el nodo del proyecto, haga clic en Retarget Projects, elija las versiones que desea usar como destino y, a continuación, haga clic en Aceptar.

Si encuentra errores de compilador o enlazador después de usar cualquiera de estos dos métodos, puede intentar limpiar la solución (Compilar> soluciónlimpia o eliminar manualmente todas las carpetas y archivos temporales) antes de intentar compilar de nuevo.

Si el compilador de C++ genera "error C2039: 'IUnknown': no es miembro del ''espacio de nombres global''", agregue #include <unknwn.h> en la parte superior de su archivo pch.h (antes de incluir cualquier encabezado de C++/WinRT).

Es posible que también tenga que agregar #include <hstring.h> después de eso.

Si el enlazador de C++ genera "error LNK2019: símbolo externo sin resolver _WINRT_CanUnloadNow@0 al que se hace referencia en la función _VSDesignerCanUnloadNow@0", puede resolverlo agregando #define _VSDESIGNER_DONT_LOAD_AS_DLL al pch.h archivo.