Procédure : Utiliser le code C++ existant dans une application de plateforme Windows universelle

Il existe différentes façons d’utiliser le code C++ existant dans les projets plateforme Windows universelle (UWP). Certaines façons ne nécessitent pas de recompilation du code avec les extensions de composant (C++/CX) activées (c’est-à-dire, avec l’option /ZW ) et certaines d’entre elles. Vous devrez peut-être conserver du code en C++standard ou conserver un environnement de compilation Win32 classique pour du code. Vous pouvez toujours le faire, avec les choix d’architecture appropriés. Considérez tout votre code qui contient l’interface utilisateur UWP et les types exposés aux appelants C#, Visual Basic et JavaScript. Ce code doit se trouver dans les projets d’application Windows et les projets de composants Windows Runtime. Le code que vous appelez uniquement à partir de C++ (y compris C++/CX) peut être dans un projet qui se compile avec l’option /ZW ou un projet C++ standard. Le code binaire uniquement qui n’utilise pas d’API non autorisées peut être utilisé en le liant en tant que bibliothèque statique. Vous pouvez également l’empaqueter avec l’application en tant que contenu et le charger dans une DLL.

Le moyen le plus simple d’exécuter votre programme de bureau dans l’environnement UWP consiste peut-être à utiliser les technologies de pont de bureau. Ils incluent Desktop App Converter, qui empaquete votre application existante en tant qu’application UWP sans aucune modification de code requise. Pour plus d’informations, consultez Desktop Bridge.

Le reste de cet article explique comment porter des bibliothèques C++ (DLL et bibliothèques statiques) vers le plateforme Windows universelle. Vous pouvez porter votre code afin que votre logique C++ principale puisse être utilisée avec plusieurs applications UWP.

Les applications UWP s’exécutent dans un environnement protégé. Par conséquent, de nombreux appels d’API Win32, COM et CRT susceptibles de compromettre la sécurité de la plateforme ne sont pas autorisés. L’option /ZW du compilateur peut détecter ces appels et générer une erreur. Vous pouvez utiliser le Kit de certification des applications sur votre application pour détecter le code qui appelle des API non autorisées. Pour plus d’informations, consultez Kit de certification des applications Windows.

Si le code source est disponible pour la bibliothèque, vous pouvez essayer d’éliminer les appels d’API non autorisés. Pour obtenir la liste des API qui ne sont pas autorisées, consultez les API Win32 et COM pour les applications UWP et les fonctions CRT non prises en charge dans les applications plateforme Windows universelle. Des alternatives sont disponibles dans Alternatives aux API Windows dans les applications UWP.

Si vous essayez simplement d’ajouter une référence d’un projet Windows universel à une bibliothèque de bureau classique, vous obtenez un message d’erreur indiquant que la bibliothèque n’est pas compatible. S’il s’agit d’une bibliothèque statique, vous pouvez créer un lien vers votre bibliothèque en ajoutant la bibliothèque (.lib fichier) à votre entrée de l’éditeur de liens, de la même façon que dans une application Win32 classique. Si seule une bibliothèque binaire est disponible, il s’agit de la seule option. Une bibliothèque statique est liée à l’exécutable de votre application. Toutefois, une DLL Win32 que vous utilisez dans une application UWP doit être empaquetée dans l’application en l’incluant dans le projet et en la marquant comme contenu. Pour charger une DLL Win32 dans une application UWP, vous devez également appeler LoadPackagedLibrary à la place ou LoadLibraryLoadLibraryEx.

Si vous avez du code source pour la DLL ou la bibliothèque statique, vous pouvez la recompiler en tant que projet UWP à l’aide de l’option du /ZW compilateur. Vous pouvez ensuite ajouter une référence à celle-ci à l’aide de l’Explorateur de solutions et l’utiliser dans les applications UWP C++. Lier la DLL à l’aide de la bibliothèque d’exportation.

Pour exposer des fonctionnalités aux appelants dans d'autres langages, vous pouvez convertir la bibliothèque en composant Windows Runtime. Les composants Windows Runtime diffèrent des DLL ordinaires dans lesquelles ils incluent des métadonnées sous la forme de .winmd fichiers qui décrivent le contenu d’une manière dont les consommateurs .NET et JavaScript ont besoin. Pour exposer des éléments d’API à d’autres langages, vous pouvez ajouter des constructions C++/CX, telles que des classes ref, et les rendre publiques. Dans Windows 10 et versions ultérieures, nous vous recommandons la bibliothèque C++/WinRT au lieu de C++/CX.

La discussion précédente ne s’applique pas aux composants COM, qui doivent être gérés différemment. Si vous disposez d’un serveur COM dans une DLL ou EXE, vous pouvez l’utiliser dans un projet Windows universel. Empaquetez-le en tant que composant COM sans inscription, ajoutez-le à votre projet en tant que fichier de contenu et instanciez-le à l’aide CoCreateInstanceFromAppde . Pour plus d’informations, consultez le billet de blog Using Free-COM DLL in Windows Store C++ Project.

Si vous souhaitez porter une bibliothèque COM existante vers UWP, il est également possible de la convertir en composant Windows Runtime. Nous vous recommandons la bibliothèque C++/WinRT pour ces ports, mais il est également possible d’utiliser la bibliothèque de modèles C++ Windows Runtime (WRL). Le WRL est déconseillé et ne prend pas en charge toutes les fonctionnalités d’ATL et OLE. Si un tel port est possible dépend des fonctionnalités de COM, ATL et OLE dont votre composant a besoin.

Selon les scénarios de développement que vous choisissez, vous devez connaître un certain nombre de définitions de macros. Vous pouvez utiliser ces macros dans votre code pour compiler le code de manière conditionnelle sous Win32 de bureau classique et UWP.

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PC_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

Ces instructions s’appliquent respectivement aux applications UWP, aux applications du Windows Phone Store, aux deux ou bien aux applications de bureau Win32 classiques uniquement. Ces macros sont disponibles uniquement dans le Kit de développement logiciel (SDK) Windows 8.1 et versions ultérieures.

Cet article contient les procédures suivantes :

Utilisation d’une DLL Win32 dans une application UWP

Pour une meilleure sécurité et fiabilité, les applications Windows universelles s’exécutent dans un environnement d’exécution restreint. Vous ne pouvez pas simplement utiliser une DLL native comme vous le feriez dans une application de bureau Windows classique. Si vous disposez du code source pour une DLL, vous pouvez le déplacer de manière à ce qu'il s'exécute sur UWP. Commencez par modifier quelques paramètres du projet et les métadonnées du fichier projet pour identifier le projet en tant que projet UWP. Vous allez recompiler le code de la bibliothèque à l’aide de l’option /ZW , qui active C++/CX. Certains appels d’API ne sont pas autorisés dans les applications UWP en raison de contrôles plus stricts associés à cet environnement. Pour plus d’informations, consultez les API Win32 et COM pour les applications UWP.

Si vous avez une DLL native qui exporte des fonctions à l’aide de __declspec(dllexport), vous pouvez les appeler à partir d’une application UWP en recompilant la DLL en tant que projet UWP. Par exemple, supposons que nous avons un projet DLL Win32 nommé Giraffe qui exporte quelques classes et leurs méthodes, avec du code comme le fichier d’en-tête suivant :

// giraffe.h
// Define GIRAFFE_EXPORTS when building this DLL
#pragma once

#ifdef GIRAFFE_EXPORTS
#define GIRAFFE_API __declspec(dllexport)
#else
#define GIRAFFE_API
#endif

GIRAFFE_API int giraffeFunction();

class Giraffe
{
    int id;
        Giraffe(int id_in);
    friend class GiraffeFactory;

public:
    GIRAFFE_API int GetID();
};

class GiraffeFactory
{
    static int nextID;

public:
    GIRAFFE_API GiraffeFactory();
    GIRAFFE_API static int GetNextID();
    GIRAFFE_API static Giraffe* Create();
};

Et le fichier de code suivant :

// giraffe.cpp
#include "pch.h"
#include "giraffe.h"

Giraffe::Giraffe(int id_in) : id(id_in)
{
}

int Giraffe::GetID()
{
    return id;
}

int GiraffeFactory::nextID = 0;

GiraffeFactory::GiraffeFactory()
{
    nextID = 0;
}

int GiraffeFactory::GetNextID()
{
    return nextID;
}

Giraffe* GiraffeFactory::Create()
{
    return new Giraffe(nextID++);
}

int giraffeFunction();

Tout le reste du projet (pch.h, dllmain.cpp) fait partie du modèle de projet Win32 standard. Le code définit la macro GIRAFFE_API, qui se résout quand __declspec(dllexport)GIRAFFE_EXPORTS elle est définie. Autrement dit, elle est définie lorsque le projet est généré en tant que DLL, mais pas lorsqu’un client utilise l’en-tête giraffe.h . Cette DLL peut être utilisée dans un projet UWP sans modifier le code source. Seuls certains paramètres et propriétés du projet doivent être modifiés.

La procédure suivante s’applique lorsque vous disposez d’une DLL native qui expose des fonctions à l’aide __declspec(dllexport)de .

Pour porter une DLL native vers la plateforme UWP sans créer de projet

  1. Ouvrez votre projet DLL dans Visual Studio.

  2. Ouvrez les Propriétés du projet de DLL, puis affectez la valeur Toutes les configurations à Configuration.

  3. Dans les Propriétés du projet, sous C/C++>onglet Général, affectez la valeur Oui (/ZW) à Consommer l’extension Windows Runtime. Cette propriété active les extensions de composant (C++/CX).

  4. Dans Explorateur de solutions, sélectionnez le nœud du projet, ouvrez le menu contextuel, puis choisissez Décharger le projet. Ensuite, ouvrez le menu contextuel sur le nœud du projet déchargé et choisissez de modifier le fichier projet. Localisez l’élément WindowsTargetPlatformVersion, et remplacez-le par les éléments suivants.

    <AppContainerApplication>true</AppContainerApplication>
    <ApplicationType>Windows Store</ApplicationType>
    <WindowsTargetPlatformVersion>10.0.10156.0</WindowsTargetPlatformVersion>
    <WindowsTargetPlatformMinVersion>10.0.10156.0</WindowsTargetPlatformMinVersion>
    <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
    

    Fermez le .vcxproj fichier, ouvrez à nouveau le menu contextuel, puis choisissez Recharger le projet.

    L’Explorateur de solutions identifie désormais le projet en tant que projet Windows universel.

  5. Assurez-vous que le nom de votre fichier d'en-tête précompilé est correct. Dans la section En-têtes précompilés, vous devrez peut-être modifier le fichier d’en-tête précompilé de pch.h vers ou d’une autre façon si vous voyez une erreur semblable à stdafx.h celle-ci :

    erreur C2857 : instruction '#include' spécifiée avec l’option /Ycpch.h de ligne de commande introuvable dans le fichier source

    Le problème est que les modèles de projet plus anciens utilisent une convention d’affectation de noms différente pour le fichier d’en-tête précompilé. Visual Studio 2019 et les projets ultérieurs utilisent pch.h.

  6. Créez le projet. Vous pouvez obtenir des erreurs concernant les options de ligne de commande incompatibles. Par exemple, l’option fréquemment utilisée mais à présent dépréciée Activer la régénération minimale (/Gm) est définie par défaut dans de nombreux projets C++ plus anciens et est incompatible avec /ZW.

    Certaines fonctions ne sont pas disponibles lorsque vous compilez pour le plateforme Windows universelle. Vous verrez des erreurs du compilateur concernant les problèmes éventuels. Résolvez ces erreurs jusqu’à ce que vous ayez une build propre.

  7. Pour utiliser la DLL dans une application UWP de la même solution, ouvrez le menu contextuel du nœud de projet UWP, puis choisissez Ajouter>Référence.

    Sous Projets>Solution, cochez la case en regard du projet DLL, puis choisissez le bouton OK.

  8. Incluez le ou les fichiers d’en-tête de la bibliothèque dans le fichier de pch.h votre application UWP.

    #include "..\Giraffe\giraffe.h"
    
  9. Ajoutez comme d'habitude du code dans le projet UWP pour appeler des fonctions et créer des types à partir de la DLL.

    MainPage::MainPage()
    {
        InitializeComponent();
        GiraffeFactory gf;
        Giraffe* g = gf.Create();
        int id = g->GetID();
    }
    

Utilisation d’une bibliothèque statique C++ native dans une application UWP

Vous pouvez utiliser une bibliothèque statique C++ native dans un projet UWP, mais vous devez tenir compte de certaines restrictions et limitations. Commencez par lire les informations relatives aux bibliothèques statiques dans C++/CX. Vous pouvez accéder au code natif dans votre bibliothèque statique à partir de votre application UWP, mais il n'est pas recommandé de créer des types ref publics dans une bibliothèque statique. Si vous compilez une bibliothèque statique avec l’option /ZW, le générateur de bibliothèques (en fait, l’éditeur de liens déguisé) émet un avertissement :

LNK4264 : archivage du fichier objet compilé avec /ZW dans une bibliothèque statique ; notez qu’au moment de créer des types Windows Runtime, il est déconseillé d’établir une liaison avec une bibliothèque statique qui contient des métadonnées Windows Runtime

Toutefois, vous pouvez utiliser une bibliothèque statique dans une application UWP sans la recompiler avec /ZW. Votre bibliothèque ne peut déclarer aucun type ref ni utiliser des constructions C++/CX. Toutefois, si votre objectif est simplement d’utiliser une bibliothèque de code natif, vous pouvez le faire en suivant ces étapes.

Pour utiliser une bibliothèque statique C++ native dans un projet UWP

  1. Dans les propriétés du projet UWP, choisissez Propriétés de configuration>Éditeur de liens>Entrée dans le volet gauche. Dans le volet droit, ajoutez le chemin d’accès à la bibliothèque dans la propriété Dépendances supplémentaires. Par exemple, pour une bibliothèque dans le projet qui place sa sortie, <SolutionFolder>\Debug\MyNativeLibrary\MyNativeLibrary.libajoutez le chemin Debug\MyNativeLibrary\MyNativeLibrary.librelatif .

  2. Ajoutez une instruction Include pour référencer le fichier d’en-tête à votre pch.h fichier (le cas échéant), ou dans n’importe quel .cpp fichier si nécessaire, puis commencez à ajouter du code qui utilise la bibliothèque.

    #include "..\MyNativeLibrary\MyNativeLibrary.h"
    

    N’ajoutez pas de référence dans le nœud Références dans Explorateur de solutions. Ce mécanisme fonctionne uniquement avec les composants Windows Runtime.

Portage d’une bibliothèque C++ sur un composant Windows Runtime

Supposons que vous souhaitez utiliser des API natives dans une bibliothèque statique à partir d’une application UWP. Si vous disposez du code source de la bibliothèque native, vous pouvez porter le code vers un composant Windows Runtime. Il ne s’agit plus d’une bibliothèque statique ; vous allez le transformer en DLL que vous pouvez utiliser dans n’importe quelle application UWP C++. Cette procédure explique comment créer un composant Windows Runtime qui utilise des extensions C++/CX. Pour plus d’informations sur la création d’un composant qui utilise C++/WinRT à la place, consultez les composants Windows Runtime avec C++/WinRT.

Lorsque vous utilisez C++/CX, vous pouvez ajouter des types ref et d’autres constructions C++/CX, qui sont disponibles pour les clients dans n’importe quel code d’application UWP. Vous pouvez accéder à ces types à partir de C#, Visual Basic ou JavaScript. La procédure de base est la suivante :

  • Créer un projet Windows Runtime Component (Windows universel),
  • copiez le code de votre bibliothèque statique dans celle-ci, et
  • résoudre les erreurs du compilateur causées par l’option /ZW .

Pour déplacer une bibliothèque C++ vers un composant Windows Runtime

  1. Créez un projet Windows Runtime Component (Windows universel).

  2. Fermez le projet.

  3. Dans le Explorateur de fichiers Windows, recherchez le nouveau projet. Localisez ensuite le projet de bibliothèque C++ qui contient le code que vous souhaitez porter. Copiez les fichiers sources (fichiers d’en-tête, fichiers de code et autres ressources, y compris dans les sous-répertoires) à partir de votre projet de bibliothèque C++. Collez-les dans le nouveau dossier de projet, en veillant à conserver la même structure de dossiers.

  4. Rouvrez le projet composant Windows Runtime. Ouvrez le menu contextuel du nœud de projet dans Explorateur de solutions, puis choisissez Ajouter un>élément existant.

  5. Sélectionnez tous les fichiers à ajouter à partir de votre projet d’origine, puis choisissez OK. Répétez cette opération si nécessaire pour les sous-dossiers.

  6. Il est possible que vous vous retrouviez avec du code dupliqué. S’il existe plusieurs en-têtes précompilés (par exemple, les deux stdafx.h et pch.h), choisissez-en un à conserver. Copiez tout le code requis, comme les instructions include, dans celui que vous souhaitez conserver. Ensuite, supprimez l’autre et, dans les propriétés du projet, sous En-têtes précompilés, vérifiez que le nom du fichier d’en-tête est correct.

    Si vous avez modifié le fichier à utiliser comme en-tête précompilé, assurez-vous que les options des en-têtes précompilés sont correctes pour chaque fichier. Sélectionnez à son tour chaque .cpp fichier, ouvrez sa fenêtre de propriétés et assurez-vous que tous sont définis sur Utiliser (/Yu), à l’exception de l’en-tête précompilé, qui doit être défini sur Create (/Yc) .

  7. Générez le projet et corrigez les erreurs. Ces erreurs peuvent être provoquées par l’utilisation de l’option /ZW ou par une nouvelle version du Kit de développement logiciel (SDK) Windows. Elles peuvent également refléter des dépendances telles que des fichiers d’en-tête dont dépend votre bibliothèque ou des différences dans les paramètres de projet entre votre ancien projet et le nouveau.

  8. Ajoutez des types ref publics à votre projet ou convertissez des types ordinaires en types ref. Utilisez ces types pour exposer des points d’entrée dans les fonctionnalités que vous souhaitez appeler à partir d’applications UWP.

  9. Testez le composant en ajoutant une référence à celui-ci à partir d'un projet d'application UWP et ajoutez du code pour appeler les API publiques que vous avez créées.

Voir aussi

Portage vers la plateforme universelle Windows