Partager via


Nouveautés de C++/WinRT

Au fur et à mesure que de nouvelles versions de C++/WinRT sont publiées, cette rubrique décrit les nouveautés et les modifications apportées.

Cumul des améliorations/nouveautés récentes à compter de mars 2020

Temps de génération jusqu’à 23 % plus courts

Les équipes C++/WinRT et du compilateur C++ ont collaboré pour raccourcir le plus possible les temps de génération. Nous avons examiné l’analytique du compilateur pour déterminer comment restructurer les éléments internes de C++/WinRT pour aider le compilateur C++ à éliminer la surcharge au moment de la compilation, et comment améliorer le compilateur C++ lui-même pour gérer la bibliothèque C++/WinRT. C++/WinRT a été optimisé pour le compilateur, et le compilateur a été optimisé pour C++/WinRT.

Prenons l’exemple du pire des scénarios de génération d’un en-tête précompilé (PCH) qui contient chaque en-tête d’espace de noms de projection C++/WinRT.

Version Taille PCH (octets) Durée (s)
C++/WinRT à partir de juillet, avec Visual C++ 16.3 3 004 104 632 31
version 2.0.200316.3 de C++/WinRT, avec Visual C++ 16.5 2 393 515 336 Vingt-quatre

Réduction de 20 % de la taille et réduction de 23 % du temps de génération.

Amélioration de la prise en charge de MSBuild

Nous avons investi beaucoup de travail dans l’amélioration de la prise en charge de MSBuild pour une grande sélection de différents scénarios.

Mise en cache de fabrique encore plus rapide

Nous avons amélioré l’incorporation du cache de fabrique pour une meilleure inclusion des chemins chauds, ce qui accélère l’exécution.

Cette amélioration n’affecte pas la taille du code, comme décrit ci-dessous dans La génération de code EH optimisée, si votre application utilise fortement la gestion des exceptions C++, vous pouvez réduire votre binaire à l’aide de l’option /d2FH4 , qui est activée par défaut dans les nouveaux projets créés avec Visual Studio 2019 16.3 et versions ultérieures.

Boxing plus efficace

Lorsqu’elle est utilisée dans une application XAML, winrt ::box_value est désormais plus efficace (voir Boxing et unboxing). Les applications qui font un grand nombre de boxings bénéficient aussi d’une réduction de la taille du code.

Prise en charge de l’implémentation des interfaces COM qui implémentent IInspectable

Si vous devez implémenter une interface COM (non-Windows-Runtime) qui implémente également IInspectable, vous pouvez maintenant le réaliser avec C++/WinRT. Consultez les interfaces COM qui implémentent IInspectable.

Améliorations du verrouillage de module

Le contrôle du verrouillage de module permet à la fois des scénarios d’hébergement personnalisé et l’élimination complète du verrouillage au niveau du module. Consultez les améliorations apportées au verrouillage du module .

Prise en charge des informations d’erreurs autres que Windows Runtime

Certaines API (même certaines API Windows Runtime) signalent des erreurs sans utiliser les API d’origine d’erreurs Windows Runtime. Dans ce type de cas, C++/WinRT utilise finalement les informations d’erreurs COM. Consultez Prise en charge de C++/WinRT pour les informations d’erreurs non-WinRT.

Activer la prise en charge des modules C++

La prise en charge des modules C++ est de retour, mais uniquement sous une forme expérimentale. La fonctionnalité n’est pas encore complète dans le compilateur C++.

Reprise de coroutines plus efficace

Les coroutines C++/WinRT s’exécutent déjà bien, mais nous continuons à chercher à les améliorer. Consultez Améliorer la scalabilité de la reprise des coroutines.

Nouveaux assistants asynchrones when_all et when_any

La fonction utilitaire when_all crée un objet IAsyncAction qui se termine lorsque tous les objets en attente fournis sont terminés. L'aide when_any crée une IAsyncAction qui se termine lorsque l'un des éléments attendus fournis s'est terminé.

Consultez Ajout de l'assistant asynchrone when_any et Ajout de l'assistant asynchrone when_all.

Autres optimisations et ajouts

Par ailleurs, de nombreux correctifs de bogues ainsi que des optimisations et des ajouts mineurs ont été introduits, y compris diverses améliorations visant à simplifier le débogage et à optimiser les implémentations des éléments internes et par défaut. Suivez ce lien pour obtenir la liste exhaustive : https://github.com/microsoft/xlang/pulls?q=is%3Apr+is%3Aclosed.

Nouveautés et modifications dans C++/WinRT 2.0

Pour plus d’informations sur l'd’extension Visual Studio C++/WinRT , le package NuGet Microsoft.Windows.CppWinRT, ainsi que l’outil , notamment comment les acquérir et les installer, consultez prise en charge de Visual Studio pour C++/WinRT, XAML, l’extension VSIX et le package NuGet.

Modifications apportées à l’extension Visual Studio C++/WinRT (VSIX) pour la version 2.0

  • Le visualiseur de débogage prend désormais en charge Visual Studio 2019 et continue de prendre en charge Visual Studio 2017.
  • De nombreuses corrections de bogues ont été effectuées.

Modifications apportées au package NuGet Microsoft.Windows.CppWinRT pour la version 2.0

  • L’outil cppwinrt.exe est désormais inclus dans le package NuGet Microsoft.Windows.CppWinRT et il génère des en-têtes de projection de plateforme pour chaque projet à la demande. Par conséquent, l’outil cppwinrt.exe ne dépend plus du SDK Windows (même s’il est toujours fourni avec le SDK pour des raisons de compatibilité).
  • cppwinrt.exe génère maintenant des en-têtes de projection sous chaque dossier intermédiaire spécifique de la plateforme/configuration ($IntDir) pour activer des builds parallèles.
  • La prise en charge des builds C++/WinRT (propriétés/cibles) est maintenant entièrement documentée, au cas où vous souhaiteriez personnaliser manuellement vos fichiers projet. Consultez le readme du package NuGet Microsoft.Windows.CppWinRT .
  • De nombreuses corrections de bogues ont été effectuées.

Modifications apportées à C++/WinRT pour la version 2.0

Libre

L’outil cppwinrt.exe prend un fichier de métadonnées Windows Runtime (.winmd) et génère à partir de celui-ci une bibliothèque C++ standard basée sur un fichier d’en-tête qui projette les API décrites dans les métadonnées. Ainsi, vous pouvez utiliser ces API à partir de votre code C++/WinRT.

Cet outil est désormais un projet entièrement open source, disponible sur GitHub. Visitez Microsoft/cppwinrt.

Bibliothèques xlang

Une bibliothèque à en-tête uniquement entièrement portable (pour l’analyse du format de métadonnées ECMA-335 utilisé par Windows Runtime) constitue la base de tous les outils Windows Runtime et xlang à venir. Nous avons notamment aussi réécrit l’outil cppwinrt.exe ex nihilo en utilisant les bibliothèques xlang. Les requêtes de métadonnées sont ainsi beaucoup plus précises, ce qui permet de résoudre certains problèmes de longue date liés à la projection du langage C++/WinRT.

Moins de dépendances

À cause du lecteur de métadonnées xlang, l’outil cppwinrt.exe lui-même a moins de dépendances. Il est ainsi beaucoup plus flexible et utilisable dans plus de scénarios, en particulier dans les environnements de build contraints. Il ne s’appuie notamment plus sur RoMetadata.dll.   Voici les dépendances pour cppwinrt.exe 2.0.  

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

Toutes ces DLL sont disponibles sur Windows 10, mais également sur les versions antérieures, jusqu’à Windows 7, et même Windows Vista. Si vous le souhaitez, votre ancien serveur de builds exécutant Windows 7 peut désormais exécuter cppwinrt.exe pour générer des en-têtes C++ pour votre projet. Avec un peu de travail, vous pouvez même exécuter C++/WinRT sur Windows 7, si cela vous intéresse.

À l’inverse, cppwinrt.exe 1.0 comporte ces dépendances.

  • 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

Attribut noexcept de Windows Runtime

Windows Runtime a un nouvel [noexcept] attribut, que vous pouvez utiliser pour décorer vos méthodes et propriétés dans MIDL 3.0. La présence de l’attribut indique aux outils associés que votre implémentation ne lève pas d’exceptions (et ne retourne pas de HRESULT ayant échoué). Ainsi, les projections de langage optimisent la génération de code en évitant la surcharge de la gestion des exceptions nécessaire pour prendre en charge les appels d’interface binaire d’application (ABI) en risque d’échec.

C++/WinRT tire parti de cette optimisation en produisant des implémentations noexcept C++ à la fois du code de consommation et du code de création. Si vous avez des méthodes ou propriétés d’API sans échec et que la taille du code vous préoccupe, vous pouvez examiner cet attribut.

Génération de code optimisée

C++/WinRT génère désormais du code source C++ encore plus efficace (en arrière-plan) pour que le compilateur C++ puisse produire le code binaire le plus petit et le plus efficace possible. De nombreuses améliorations ont vocation à réduire le coût de la gestion des exceptions en évitant les informations de déroulement inutiles. Les binaires qui utilisent de grandes quantités de code C++/WinRT observent une réduction d’environ 4 % de la taille du code. Le code est également plus efficace (il s’exécute plus rapidement) en raison du nombre réduit d’instructions.

Ces améliorations s’appuient sur une nouvelle fonctionnalité d’interopérabilité également à votre disposition. Tous les types C++/WinRT propriétaires de ressources incluent désormais un constructeur à des fins de prise de possession directe, ce qui permet d’éviter l’approche antérieure en deux étapes.

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

IStringable projected(raw, take_ownership_from_abi);

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

Génération du code de gestion des exceptions optimisée

Cette modification complète le travail effectué par l’équipe en charge de l’optimiseur Microsoft C++ pour réduire le coût de la gestion des exceptions. Si vous utilisez massivement des interfaces binaires d’applications (ABI) (par exemple, COM) dans votre code, vous pouvez observer qu’une grande quantité de code suit ce modèle.

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

C++/WinRT lui-même génère ce modèle pour toutes les API implémentées. Avec des milliers de fonctions d’API, toute optimisation peut ici s’avérer significative. Par le passé, l’optimiseur n’aurait pas détecté que ces blocs catch sont tous identiques, si bien qu’il dupliquait beaucoup de code autour de chaque ABI (qui à leur tour contribuaient à la croyance que l’utilisation d’exceptions dans le code système générait des binaires volumineux). Toutefois, à partir de Visual Studio 2019, le compilateur C++ incorpore tous ces funclets catch et stocke uniquement ceux qui sont uniques. Il en résulte une réduction globale supplémentaire de 18 % de la taille du code pour les binaires qui s’appuient lourdement sur ce modèle. Non seulement le code de gestion des exeptions est maintenant plus efficace qu’avec l’utilisation de codes de retour, mais la préoccupation liée à la taille plus importante des binaires relève à présent du passé.

Améliorations des builds incrémentielles

L’outil cppwinrt.exe compare désormais la sortie d’un fichier d’en-tête/source généré au contenu de tout fichier existant sur le disque, puis il écrit dans le fichier uniquement si le fichier a été réellement modifié. Cela fait gagner un temps considérable avec les E/S de disque et garantit que les fichiers ne sont pas considérés comme « modifiés » par le compilateur C++. En conséquence, la recompilation est évitée ou réduite, dans de nombreux cas.

Interfaces génériques maintenant toutes générées

En raison du lecteur de métadonnées xlang, C++/WinRT génère désormais toutes les interfaces paramétrables, ou génériques, à partir des métadonnées. Les interfaces telles que Windows ::Foundation ::Collections ::IVector<T> sont désormais générées à partir de métadonnées plutôt que écrites manuellement winrt/base.h. Le résultat est que la taille de winrt/base.h a été réduite de moitié et que les optimisations sont générées directement dans le code (ce qui était difficile à faire avec l’approche manuelle).

Important

Les interfaces comme l’exemple donné apparaissent désormais dans leurs en-têtes d’espace de noms respectifs, plutôt que dans winrt/base.h. Ainsi, si vous ne l’avez pas déjà fait, vous devez inclure l’en-tête d’espace de noms approprié afin d’utiliser l’interface.

Optimisations du composant

Cette mise à jour ajoute une prise en charge de plusieurs optimisations supplémentaires volontaires pour C++/WinRT, décrites dans les sections ci-dessous. Étant donné que ces optimisations sont des changements cassants (pour lesquels vous risquez de devoir apporter des changements mineurs pour les prendre en charge), vous devez les activer explicitement. Dans Visual Studio, définissez la propriété de projet Propriétés communes>C++/WinRT>Optimisé sur Oui. <CppWinRTOptimized>true</CppWinRTOptimized> est alors ajouté à votre fichier projet. Cela revient à ajouter le commutateur -opt[imize] lors de l’appel de cppwinrt.exe à partir de la ligne de commande.

Un nouveau projet (provenant d’un modèle de projet) utilisera -opt par défaut.

Construction uniforme et accès à l’implémentation direct

Ces deux optimisations permettent à votre composant d’accéder directement à ses propres types d’implémentation, même quand il utilise uniquement les types projetés. Il n'est pas nécessaire d'utiliser make, make_self, ni get_self si vous souhaitez simplement utiliser la surface de l'API publique. Vos appels se compileront jusqu’aux appels directs dans l’implémentation, et ceux-ci peuvent même être entièrement inline.

Pour plus d’informations et plus d'exemples de code, consultez Adhérez à la construction uniforme et à l'accès direct à l'implémentation.

Fabriques avec types effacés

Cette optimisation évite les dépendances #include dans module.g.cpp afin qu’il n’ait pas besoin d’être recompilé à chaque modification d’une seule classe d’implémentation. Les performances des builds s’en retrouvent alors améliorées.

module.g.cpp plus intelligent et plus efficace pour les projets volumineux avec plusieurs bibliothèques

Le module.g.cpp fichier contient désormais également deux aides composables supplémentaires, appelées winrt_can_unload_now et winrt_get_activation_factory. Celles-ci ont été conçues pour les projets volumineux dans lesquels une DLL comprend plusieurs bibliothèques, chacune avec ses propres classes d’exécution. Dans ce cas, vous devez assembler manuellement les DllGetActivationFactory et DllCanUnloadNow de la DLL. Ces assistances vous facilitent grandement la tâche, en vous évitant les fausses erreurs d’origine. L’indicateur cppwinrt.exe de l’outil -lib peut également être utilisé pour donner à chaque bibliothèque individuelle son propre préambule (au lieu de winrt_xxx) afin que les fonctions de chaque bibliothèque puissent être nommées individuellement et par conséquent combinées sans ambiguïté.

Prise en charge des coroutines

La prise en charge des coroutines est automatiquement incluse. Auparavant, la prise en charge se trouvait à plusieurs endroits, ce qui était trop contraignant à notre avis. Puis, de façon temporaire pour v2.0, un fichier d’en-tête winrt/coroutine.h était nécessaire, mais il ne l’est plus. Étant donné que les interfaces asynchrones Windows Runtime sont maintenant générées, au lieu d’être manuscrites, elles se trouvent désormais dans winrt/Windows.Foundation.h. En plus d’être plus gérables et faciles à supporter, cela signifie que les aides coroutine telles que resume_foreground n’ont plus besoin d’être ajoutées à la fin de l'en-tête d'un espace de nom spécifique. En effet, elles peuvent inclure plus naturellement leurs dépendances. Cela permet à resume_foreground de prendre en charge non seulement la reprise sur un Windows ::UI ::Core ::CoreDispatcher donné, mais il prend désormais en charge la reprise sur un Windows ::System ::DispatcherQueue donné. Auparavant, un seul pouvait être pris en charge, mais pas les deux, dans la mesure où la définition ne pouvait résider que dans un seul espace de noms.

Voici un exemple de prise en charge de 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);
}

Les assistances de coroutine sont désormais également décorées avec [[nodiscard]], ce qui en améliore l’utilisabilité. Si vous oubliez de (ou ne savez pas pas que vous devez) les co_await pour qu’elles fonctionnent, alors, en raison de [[nodiscard]], ces erreurs produisent maintenant un avertissement du compilateur.

Aide au diagnostic des allocations directes (pile)

Étant donné que les noms de classe projetés et d’implémentation sont (par défaut) les mêmes et ne diffèrent que par l’espace de noms, il est possible de les confondre et de créer accidentellement une implémentation sur la pile, plutôt que d’utiliser la famille make d’assistances. Cela peut être difficile à diagnostiquer dans certains cas, étant donné que l’objet peut être détruit alors que des références en attente sont toujours en version d’évaluation. Une assertion améliore maintenant cela pour les versions de débogage. Tandis que l’assertion ne détecte pas l’allocation de la pile à l’intérieur d’une coroutine, elle s’avère néanmoins utile pour intercepter la plupart des erreurs de ce type.

Pour plus d’informations, consultez Diagnostic des allocations directes.

Assistances de capture améliorées et délégués variadiques

Cette mise à jour corrige la limitation avec les assistances de capture en prenant également en charge les types projetés. Cela se produit de temps en temps avec les API d’interopérabilité Windows Runtime, quand elles retournent un type projeté.

Cette mise à jour ajoute également une prise en charge de get_strong et get_weak lors de la création d’un délégué variadique (non-Windows Runtime).

Prise en charge de la destruction différée et méthode QI sans échec pendant la destruction

Il n’est pas rare dans le destructeur d’un objet de classe runtime d’appeler une méthode qui perturbe temporairement le compteur de références. Quand le compteur de références revient à zéro, l’objet est détruit une deuxième fois. Dans une application XAML, vous devrez peut-être effectuer un QueryInterface (QI) dans un destructeur, afin d’appeler une implémentation de nettoyage vers le haut ou vers le bas de la hiérarchie. Le compteur de références de l’objet ayant cependant déjà atteint zéro, cette méthode QI entraîne donc également un rebond du compteur de références.

Cette mise à jour ajoute la prise en charge d’un antirebond du compteur de références, garantissant que quand il atteint zéro, il ne peut jamais repartir, tout en vous permettant d’exécuter une méthode QI pour tous les éléments temporaires nécessaires lors de la destruction. Cette procédure est inévitable dans certaines applications/certains contrôles XAML et C++/WinRT y est désormais résilient.

Vous pouvez différer la destruction en fournissant une fonction de final_release statique sur votre type d’implémentation. Le dernier pointeur restant vers l’objet, sous la forme d’un std::unique_ptr, est passé à votre final_release. Vous pouvez ensuite choisir de déplacer la propriété de ce pointeur à un autre contexte. Vous pouvez sans problème appliquer une méthode QI au pointeur sans déclencher une double destruction. Mais la modification nette du compteur de références doit être égale à zéro au moment où vous détruisez l’objet.

La valeur de retour de final_release peut être void, un objet d’opération asynchrone tel que IAsyncAction ou 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.
    }
};

Dans l’exemple ci-dessous, une fois la mainPage publiée (pour la dernière fois), final_release est appelée. Cette fonction passe cinq secondes en attente (sur le pool de threads), puis elle reprend en utilisant le Dispatcher de la page (ce qui nécessite QI/AddRef/Release pour fonctionner). Elle nettoie ensuite une ressource sur ce thread d’interface utilisateur. Enfin, elle efface le unique_ptr, ce qui provoque l’appel du destructeur MainPage. Même dans ce destructeur, DataContext est appelé, ce qui nécessite une méthode QI pour IFrameworkElement.

Vous n’êtes pas obligé d’implémenter votre final_release en tant que coroutine. Cela fonctionne cependant et simplifie considérablement le déplacement de la destruction vers un autre thread, qui est ce qui se produit dans cet exemple.

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

Pour plus d’informations, consultez Destruction différée.

Prise en charge améliorée de l’héritage d’interface unique de style COM

Comme dans la programmation Windows Runtime, C++/WinRT est également utilisé pour créer et consommer des API uniquement COM. Cette mise à jour permet d’implémenter un serveur COM dans lequel il existe une hiérarchie d’interfaces. Elle n’est pas obligatoire pour Windows Runtime, mais elle l’est pour certaines implémentations COM.

Gestion correcte des paramètres out

Il peut s’avérer difficile d’utiliser des paramètres out, notamment des tableaux Windows Runtime. Avec cette mise à jour, C++/WinRT est considérablement plus robuste et plus résistant aux erreurs lorsqu’il s’agit de paramètres et tableaux out, que ces paramètres arrivent par le biais d’une projection de langage ou par le biais d’un développeur COM qui utilise l’ABI brute et qui commet l’erreur de ne pas lancer des variables de manière cohérente. Dans les deux cas, C++/WinRT remet désormais correctement les types projetés à l’ABI (en n’oubliant pas de libérer les ressources), et réinitialise ou efface correctement les paramètres qui arrivent par l’intermédiaire de l’ABI.

Gestion désormais fiable des jetons non valides par les événements

L’implémentation winrt ::event gère désormais correctement le cas où sa méthode remove est appelée avec une valeur de jeton non valide (valeur qui n’est pas présente dans le tableau).

Destruction des variables locales de coroutine avant le retour de la coroutine

La façon traditionnelle d’implémenter un type de coroutine peut permettre à des variables locales au sein de la coroutine d’être détruites après le retour/la fin de la coroutine (plutôt qu’avant la suspension finale). La reprise d’objets waiter est désormais différée jusqu’à la suspension finale, afin d’éviter ce problème et de bénéficier d’autres avantages.

Actualités et modifications du SDK Windows version 10.0.17763.0 (Windows 10, version 1809)

Le tableau ci-dessous contient les nouveautés et les modifications concernant C++/WinRT dans le SDK Windows version 10.0.17763.0 (Windows 10, version 1809).

Fonctionnalité nouvelle ou modifiée Plus d’infos
Changement cassant. Pour permettre sa compilation, C++/WinRT ne dépend pas des en-têtes du SDK Windows. Consultez « Isolation des fichiers d’en-tête du Kit de développement logiciel (SDK) Windows », ci-dessous.
Le format du système de projet Visual Studio a changé. Découvrez comment recibler votre projet C++/WinRT vers une version ultérieure du Kit de développement logiciel (SDK) Windows, ci-dessous.
Il existe de nouvelles fonctions et classes de base pour vous aider à passer un objet de collection à une fonction Windows Runtime ou pour implémenter vos propres propriétés et types de collection. Consultez Collections avec C++/WinRT.
Vous pouvez utiliser l’extension de balisage {Binding} avec vos classes runtime C++/WinRT. Pour plus d’informations et pour obtenir des exemples de code, consultez la vue d’ensemble de la liaison de données.
La prise en charge de l’annulation d’une coroutine vous permet d’inscrire un rappel d’annulation. Pour plus d’informations et des exemples de code, consultez Annulation d’une opération asynchrone et rappels d’annulation.
Lors de la création d’un délégué pointant vers une fonction membre, vous pouvez établir une référence forte ou faible à l’objet actuel (au lieu d’un brut ce pointeur) au point où le gestionnaire est inscrit. Pour plus d’informations et des exemples de code, consultez la sous-section Si vous utilisez une fonction membre comme délégué dans la section Accès sécurisé au pointeur this avec un délégué de gestion des événements.
Des bogues découverts par la conformité améliorée de Visual Studio à la norme C++ sont corrigés. La chaîne d’outils LLVM et Clang est également mieux exploitée pour valider la conformité aux normes C++/WinRT. Vous ne rencontrerez plus le problème décrit dans Pourquoi mon nouveau projet ne sera-t-il pas compilé ? J’utilise Visual Studio 2017 (version 15.8.0 ou ultérieure) et le SDK version 17134

Autres modifications.

  • Changement cassant. winrt ::get_abi(winrt ::hstring const&) retourne void* désormais au lieu de HSTRING. Vous pouvez utiliser static_cast<HSTRING>(get_abi(my_hstring)); pour obtenir un HSTRING. Consultez l’interopérabilité avec le HSTRING d’ABI.
  • Changement cassant. winrt::put_abi(winrt::hstring&) renvoie maintenant void** au lieu de HSTRING*. Vous pouvez utiliser reinterpret_cast<HSTRING*>(put_abi(my_hstring)); pour obtenir un HSTRING*. Consultez l’interopérabilité avec le HSTRING d’ABI.
  • Changement cassant. HRESULT est maintenant projeté en tant que winrt ::hresult. Si vous avez besoin d’un HRESULT (pour effectuer la vérification de type ou pour prendre en charge les caractéristiques de type), vous pouvez static_cast obtenir un winrt ::hresult. Sinon, winrt ::hresult se convertit en HRESULT, tant que vous incluez unknwn.h avant d’inclure les en-têtes C++/WinRT.
  • Changement cassant. GUID est maintenant projeté en tant que winrt ::guid. Pour les API que vous implémentez, vous devez utiliser winrt ::guid pour les paramètres GUID. Sinon, winrt ::guid se convertit en GUID, tant que vous incluez unknwn.h avant d’inclure des en-têtes C++/WinRT. Consultez l’interaction avec la structure GUID de l'ABI.
  • Changement cassant. Le constructeur winrt ::handle_type a été renforcé en le rendant explicite (il est désormais plus difficile d’écrire du code incorrect avec celui-ci). Si vous devez affecter une valeur de handle brute, appelez la fonction handle_type ::attach à la place.
  • Changement cassant. Les signatures de WINRT_CanUnloadNow et de WINRT_GetActivationFactory ont changé. Vous ne devez pas du tout déclarer ces fonctions. Incluez plutôt winrt/base.h (qui est automatiquement inclus si vous incluez des fichiers d’en-tête d’espace de noms Windows C++/WinRT) pour inclure les déclarations de ces fonctions.
  • Pour le struct winrt::clock, from_FILETIME/to_FILETIME sont déconseillés au profit de from_file_time/to_file_time.
  • API simplifiées qui attendent des paramètres IBuffer . La plupart des API préfèrent les collections ou les tableaux. Mais nous avons estimé que nous devrions faciliter l’appel d’API qui reposent sur IBuffer. Cette mise à jour fournit un accès direct aux données derrière une implémentation IBuffer . Elle utilise la même convention de nommage de données que celle utilisée par les conteneurs de bibliothèque standard C++. Les conflits avec les noms de métadonnées qui commencent conventionnellement par une lettre majuscule sont ainsi évités.
  • Génération de code améliorée : diverses améliorations permettent de réduire la taille du code, d’améliorer l’incorporation (inlining) et d’optimiser la mise en cache de la fabrique.
  • Récursivité inutile supprimée. Quand la ligne de commande fait référence à un dossier, plutôt qu’à un .winmd spécifique, l’outil cppwinrt.exe ne recherche plus des fichiers .winmd de manière récursive. L’outil cppwinrt.exe gère à présent aussi les doublons plus intelligemment, en renforçant leur résilience face aux erreurs des utilisateurs et aux fichiers .winmd mal formés.
  • Pointeurs intelligents renforcés. Auparavant, les révocateurs d’événements échouaient quand une nouvelle valeur était déplacée ou affectée. Cela a permis de découvrir un problème où les classes de pointeur intelligent ne géraient pas de manière fiable l’auto-attribution, ancré dans le modèle de struct winrt::com_ptr. winrt::com_ptr a été corrigé, ainsi que les révocateurs d’événements, pour gérer la sémantique de déplacement correctement afin que la révocation s’effectue au moment de l’affectation.

Important

Des modifications importantes ont été apportées à l’extension Visual Studio C++/WinRT (VSIX) dans la version 1.0.181002.2, puis ultérieurement dans la version 1.0.190128.4. Pour plus d’informations sur ces modifications et sur la façon dont elles affectent vos projets existants, la prise en charge de Visual Studio pour C++/WinRT et les versions antérieures de l’extension VSIX.

Isolation des fichiers d’en-tête du SDK Windows

Il s’agit d’un changement cassant potentiel pour votre code.

Pour permettre sa compilation, C++/WinRT ne dépend plus des fichiers d’en-tête du SDK Windows. Les fichiers d’en-tête de la bibliothèque du runtime C (CRT) et la bibliothèque des modèles standard C++ (STL) n’incluent pas non plus d’en-têtes du SDK Windows. Cela permet d’améliorer la conformité aux normes, d’éviter les dépendances par inadvertance et de réduire considérablement le nombre de macros contre lesquelles se protéger.

Cette indépendance signifie que C++/WinRT est désormais plus portable et conforme aux normes, ce qui améliore son potentiel de devenir une bibliothèque multicompilateur et multiplateforme. Cela signifie également que les en-têtes C++/WinRT ne sont pas des macros affectées avec un effet défavorable.

Si vous laissiez auparavant le soin à C++/WinRT d’inclure des en-têtes Windows dans votre projet, vous devez maintenant les inclure vous-même. Il est, dans tous les cas, toujours préférable d’inclure explicitement les en-têtes dont vous dépendez et de ne pas laisser le soin à une autre bibliothèque de les inclure pour vous.

Actuellement, les seules exceptions à l’isolation des fichiers d’en-tête du SDK Windows concernent les intrinsèques et les numériques. Il n’existe aucun problème connu avec ces dernières dépendances restantes.

Dans votre projet, vous pouvez réactiver l’interopérabilité avec les en-têtes du SDK Windows si nécessaire. Vous pouvez, par exemple, implémenter une interface COM (rootée dans IUnknown). Pour cet exemple, incluez unknwn.h avant d’inclure des en-têtes C++/WinRT. Ainsi, la bibliothèque de base C++/WinRT permet à divers hooks de prendre en charge des interfaces COM classiques. Pour obtenir un exemple de code, consultez Créer des composants COM avec C++/WinRT. De même, incluez explicitement tous les autres en-têtes du SDK Windows qui déclarent des types et/ou des fonctions que vous voulez appeler.

Guide pratique pour recibler votre projet C++/WinRT vers une version ultérieure du SDK Windows

La méthode qui permet de recibler votre projet susceptible d’entraîner le moins de problèmes de compilateur et d’éditeur de liens est également la plus fastidieuse. Cette méthode implique de créer un projet (ciblant la version du SDK Windows de votre choix), puis de copier des fichiers vers votre nouveau projet à partir de l’ancien. Vous pouvez tout simplement copier des sections de vos anciens fichiers .vcxproj et .vcxproj.filters pour éviter d’ajouter des fichiers dans Visual Studio.

Toutefois, il existe deux autres façons de recibler votre projet dans Visual Studio.

  • Accédez à la propriété de projet Version générale> duKit de développement logiciel (SDK) Windows, puis sélectionnez Toutes les configurations et toutes les plateformes. Définissez la version du Kit de développement logiciel (SDK) Windows sur la version que vous souhaitez cibler.
  • Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nœud du projet, cliquez sur Retarget Projects, choisissez la ou les versions que vous souhaitez cibler, puis cliquez sur OK.

Si vous rencontrez des erreurs de compilateur ou d’éditeur de liens après avoir utilisé l’une de ces deux méthodes, vous pouvez essayer de nettoyer la solution (Générer> unesolution propre et/ou supprimer manuellement tous les dossiers et fichiers temporaires) avant de réessayer de générer.

Si le compilateur C++ génère l'« erreur C2039 : « IUnknown » : n’est pas membre de « l’espace de noms global », puis ajoutez-y #include <unknwn.h> en haut de votre pch.h fichier (avant d’inclure des en-têtes C++/WinRT).

Vous devrez peut-être également ajouter #include <hstring.h> après.

Si l’éditeur de liens C++ génère « erreur LNK2019 : symbole externe non résolu _WINRT_CanUnloadNow@0 référencé dans la fonction _VSDesignerCanUnloadNow@0 », vous pouvez le résoudre en ajoutant #define _VSDESIGNER_DONT_LOAD_AS_DLL à votre pch.h fichier.