Vorgehensweise: Verwenden von vorhandenem C++-Code in einer UWP-App (Universelle Windows-Plattform)
Es gibt verschiedene Möglichkeiten, wie Sie vorhandenen C++-Code in Universelle Windows-Plattform(UWP)-Projekten verwenden können. Auf einige Arten müssen Code nicht mit aktivierten Komponentenerweiterungen (C++/CX) neu kompiliert werden (d. h. mit der /ZW
Option). Möglicherweise müssen Sie Code in C++ standard beibehalten oder eine klassische Win32-Kompilierungsumgebung für einige Code beibehalten. Sie können dies trotzdem mit geeigneten Architekturoptionen tun. Berücksichtigen Sie den gesamten Code, der UWP-UI und Typen enthält, die für C#-, Visual Basic- und JavaScript-Aufrufer verfügbar gemacht werden. Dieser Code sollte sich in Windows-App-Projekten und Windows-Runtime Komponentenprojekten befinden. Code, den Sie nur von C++ (einschließlich C++/CX) aufrufen, kann entweder in einem Projekt enthalten sein, das mit der /ZW
Option oder einem C++-Standardprojekt kompiliert wird. Nur Binärcode, der keine unzulässigen APIs verwendet, kann verwendet werden, indem er als statische Bibliothek verknüpft wird. Sie können sie auch mit der App als Inhalt verpacken und in einer DLL laden.
Die vielleicht einfachste Möglichkeit, für die Ausführung Ihres Desktop-Programms in der UWP-Umgebung zu sorgen, ist der Einsatz von Desktop Bridge-Technologien. Sie enthalten den Desktop App Converter, der Ihre vorhandene Anwendung als UWP-App packt, ohne dass Codeänderungen erforderlich sind. Weitere Informationen finden Sie unter Desktop Bridge.
Im restlichen Artikel wird erläutert, wie C++-Bibliotheken (DLLs und statische Bibliotheken) zum Universelle Windows-Plattform portieren. Möglicherweise möchten Sie Ihren Code portieren, damit Ihre C++-Kernlogik mit mehreren UWP-Apps verwendet werden kann.
UWP-Apps werden in einer geschützten Umgebung ausgeführt. Daher sind viele Win32-, COM- und CRT-API-Aufrufe, die die Plattformsicherheit gefährden könnten, nicht zulässig. Die /ZW
Compileroption kann solche Aufrufe erkennen und einen Fehler generieren. Sie können das Zertifizierungskit für Apps in Ihrer Anwendung verwenden, um Code zu erkennen, der nicht zulässige APIs aufruft. Weitere Informationen finden Sie unter Zertifizierungskit für Windows-Apps.
Wenn Quellcode für die Bibliothek verfügbar ist, können Sie versuchen, die unzulässigen API-Aufrufe zu beseitigen. Eine Liste der nicht zulässigen APIs finden Sie unter Win32- und COM-APIs für UWP-Apps und CRT-Funktionen, die in Universelle Windows-Plattform-Apps nicht unterstützt werden. Einige Alternativen finden Sie unter Alternatives to Windows APIs in UWP apps (Alternativen zu Windows-APIs in UWP-Apps).
Wenn Sie einfach versuchen, einen Verweis aus einem universellen Windows-Projekt zu einer klassischen Desktopbibliothek hinzuzufügen, wird eine Fehlermeldung angezeigt, die besagt, dass die Bibliothek nicht kompatibel ist. Wenn es sich um eine statische Bibliothek handelt, können Sie eine Verknüpfung mit Ihrer Bibliothek herstellen, indem Sie die Bibliothek (.lib
Datei) zu Ihrer Linkereingabe hinzufügen, auf die gleiche Weise wie in einer klassischen Win32-Anwendung. Wenn nur eine Binärbibliothek verfügbar ist, ist sie die einzige Option. Eine statische Bibliothek ist mit der ausführbaren Datei Ihrer App verknüpft. Eine Win32-DLL, die Sie in einer UWP-App verwenden, muss jedoch in die App verpackt werden, indem sie in das Projekt eingeschlossen und als Inhalt gekennzeichnet wird. Um eine Win32-DLL in einer UWP-App zu LoadPackagedLibrary
laden, müssen Sie auch anstelle von LoadLibrary
oder LoadLibraryEx
.
Wenn Sie Quellcode für die DLL oder statische Bibliothek haben, können Sie ihn mithilfe der /ZW
Compileroption als UWP-Projekt neu kompilieren. Anschließend können Sie mithilfe der Projektmappen-Explorer einen Verweis darauf hinzufügen und in C++-UWP-Apps verwenden. Verknüpfen Sie die DLL mithilfe der Exportbibliothek.
Um Funktionalität für Aufrufer in anderen Sprachen verfügbar zu machen, können Sie die Bibliothek in eine Komponente für Windows-Runtime konvertieren. Windows-Runtime Komponenten unterscheiden sich von gewöhnlichen DLLs darin, dass sie Metadaten in Form von .winmd
Dateien enthalten, die den Inhalt so beschreiben, dass .NET- und JavaScript-Consumer erforderlich sind. Um API-Elemente für andere Sprachen verfügbar zu machen, können Sie C++/CX-Konstrukte hinzufügen, z. B. Verweisklassen, und sie öffentlich machen. In Windows 10 und höher empfehlen wir die C++/WinRT-Bibliothek anstelle von C++/CX.
Die vorstehende Diskussion gilt nicht für COM-Komponenten, die unterschiedlich behandelt werden müssen. Wenn Sie über einen COM-Server in einer EXE oder DLL verfügen, können Sie ihn in einem universellen Windows-Projekt verwenden. Packen Sie sie als registrierungsfreie COM-Komponente, fügen Sie sie ihrem Projekt als Inhaltsdatei hinzu, und instanziieren Sie sie mit CoCreateInstanceFromApp
. Weitere Informationen finden Sie im Blogbeitrag Using Free-COM DLL in Windows Store C++ Project (Verwenden von Free-COM-DLLs in Windows Store-C++-Projekten).
Wenn Sie eine vorhandene COM-Bibliothek zu der UWP portieren möchten, ist es auch möglich, sie in eine Windows-Runtime Komponente zu konvertieren. Wir empfehlen die C++/WinRT-Bibliothek für solche Ports, aber es ist auch möglich, die Windows-Runtime C++-Vorlagenbibliothek (WRL) zu verwenden. Die WRL ist veraltet und unterstützt nicht alle Funktionen von ATL und OLE. Ob ein solcher Port machbar ist, hängt von den Features von COM, ATL und OLE ab, die Ihre Komponente benötigt.
Je nachdem, welche Entwicklungsszenarien Sie auswählen, sollten Sie sich einer Reihe von Makrodefinitionen bewusst sein. Sie können diese Makros in Ihrem Code verwenden, um Code bedingt unter klassischem Desktop Win32 und UWP zu kompilieren.
#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)
Diese Anweisungen gelten jeweils für UWP-Apps, Windows Phone Store-Apps, beide oder keines von beiden (nur klassische Win32-Desktop-Apps). Diese Makros sind nur in Windows SDK 8.1 und höher verfügbar.
Dieser Artikel enthält die folgenden Verfahren:
Verwenden einer nativen, statischen C++-Bibliothek in einer UWP-App
Portieren einer C++-Bibliothek in eine Komponente für Windows-Runtime
Verwenden einer Win32-DLL in einer UWP-App
Für eine bessere Sicherheit und Zuverlässigkeit werden universelle Windows-Apps in einer eingeschränkten Laufzeitumgebung ausgeführt. Sie können nicht nur eine systemeigene DLL wie in einer klassischen Windows-Desktopanwendung verwenden. Wenn Sie über Quellcode für eine DLL verfügen, können Sie den Code so portieren, dass er unter UWP ausgeführt werden kann. Als Erstes ändern Sie einige Projekteinstellungen und Projektdatei-Metadaten, um das Projekt als UWP-Projekt zu identifizieren. Sie kompilieren den Bibliothekscode mithilfe der /ZW
Option, die C++/CX aktiviert. Bestimmte API-Aufrufe sind in UWP-Apps aufgrund strenger steuerelemente, die dieser Umgebung zugeordnet sind, nicht zulässig. Weitere Informationen finden Sie unter Win32- und COM-APIs für UWP-Apps.
Bei einer nativen DLL, die Funktionen mithilfe von __declspec(dllexport)
exportiert, können Sie diese Funktionen aus einer UWP-App aufrufen, indem Sie die DLL als UWP-Projekt neu kompilieren. Angenommen, wir haben ein Win32 DLL-Projekt namens Giraffe , das ein paar Klassen und ihre Methoden exportiert, mit Code wie der folgenden Headerdatei:
// 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();
};
Und folgende Codedatei:
// 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();
Alles andere im Projekt (pch.h
, dllmain.cpp
) ist Teil der Win32-Standardprojektvorlage. Der Code definiert das Makro GIRAFFE_API
, das beim Definieren zu __declspec(dllexport)
einem bestimmten Zeitpunkt GIRAFFE_EXPORTS
aufgelöst wird. Das heißt, es wird definiert, wenn das Projekt als DLL erstellt wird, aber nicht, wenn ein Client den giraffe.h
Header verwendet. Diese DLL kann in einem UWP-Projekt verwendet werden, ohne den Quellcode zu ändern. Es müssen nur einige Projekteinstellungen und -eigenschaften geändert werden.
Das folgende Verfahren gilt, wenn Sie über eine systemeigene DLL verfügen, die Funktionen mithilfe __declspec(dllexport)
von Funktionen verfügbar macht.
So portieren Sie eine systemeigene DLL auf UWP, ohne ein neues Projekt zu erstellen
Öffnen Sie Ihr DLL-Projekt in Visual Studio.
Öffnen Sie die Projekteigenschaften für das DLL-Projekt, und legen Sie die Konfiguration auf Alle Konfigurationen fest.
Legen Sie in den Projekteigenschaften unter C/C++>Allgemein (Registerkarte) die Option Windows-Runtime-Erweiterung verwenden auf Yes (/ZW) (Ja (/ZW)) fest. Diese Eigenschaft aktiviert Komponentenerweiterungen (C++/CX).
Wählen Sie in Projektmappen-Explorer den Projektknoten aus, öffnen Sie das Kontextmenü, und wählen Sie "Projekt entladen" aus. Öffnen Sie anschließend das Kontextmenü des entladenen Projektknotens, und klicken Sie dann auf die Option zum Bearbeiten der Projektdatei. Suchen Sie das Element
WindowsTargetPlatformVersion
, und ersetzen Sie es durch die folgenden Elemente.<AppContainerApplication>true</AppContainerApplication> <ApplicationType>Windows Store</ApplicationType> <WindowsTargetPlatformVersion>10.0.10156.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformMinVersion>10.0.10156.0</WindowsTargetPlatformMinVersion> <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
Schließen Sie die
.vcxproj
Datei, öffnen Sie das Kontextmenü erneut, und wählen Sie "Projekt erneut laden" aus.Der Projektmappen-Explorer erkennt das Projekt nun als universelles Windows-Projekt.
Stellen Sie sicher, dass der Name der vorkompilierten Headerdatei richtig ist. Im Abschnitt "Vorkompilierte Kopfzeilen" müssen Sie möglicherweise die vorkompilierte Kopfzeilendatei von
pch.h
zustdafx.h
oder umgekehrt ändern, wenn ein Fehler wie dieser angezeigt wird:Fehler C2857: "#include"-Anweisung, die mit der
/Ycpch.h
Befehlszeilenoption angegeben wurde, wurde in der Quelldatei nicht gefunden.Das Problem besteht darin, dass ältere Projektvorlagen eine andere Benennungskonvention für die vorkompilierte Headerdatei verwenden. Visual Studio 2019 und höhere Projekte verwenden
pch.h
.Erstellen Sie das Projekt. Möglicherweise erhalten Sie einige Fehler bei inkompatiblen Befehlszeilenoptionen. Die nun veraltete, aber häufig verwendete Option Minimale Neuerstellung aktivieren (/Gm) ist beispielsweise standardmäßig in vielen älteren C++-Projekten festgelegt und nicht mit
/ZW
kompatibel.Einige Funktionen sind beim Kompilieren für die Universelle Windows-Plattform nicht verfügbar. Es werden Compilerfehler zu problemen angezeigt. Beheben Sie diese Fehler, bis Sie über einen sauberen Build verfügen.
Wenn Sie die DLL in einer UWP-App in derselben Projektmappe verwenden möchten, öffnen Sie das Kontextmenü für den UWP-Projektknoten, und klicken Sie auf Hinzufügen>Verweis.
Aktivieren Sie unter Projekte>Projektmappe das Kontrollkästchen neben dem DLL-Projekt, und klicken Sie dann auf die Schaltfläche OK.
Fügen Sie die Kopfzeilendatei(n) der Bibliothek in die Datei Ihrer UWP-App
pch.h
ein.#include "..\Giraffe\giraffe.h"
Fügen Sie im UWP-Projekt wie gewohnt Code zum Aufrufen von Funktionen und Erstellen von Typen aus der DLL hinzu.
MainPage::MainPage() { InitializeComponent(); GiraffeFactory gf; Giraffe* g = gf.Create(); int id = g->GetID(); }
Verwenden einer nativen, statischen C++-Bibliothek in einer UWP-App
Sie können eine native statische C++-Bibliothek in einem UWP-Projekt verwenden, aber es gibt einige Einschränkungen zu beachten. Lesen Sie zunächst mehr zu statischen Bibliotheken in C++/CX. Sie können auf den nativen Code in Ihrer statischen Bibliothek aus Ihrer UWP-App zugreifen, aber es wird nicht empfohlen, öffentliche Verweistypen in einer solchen statischen Bibliothek zu erstellen. Wenn Sie eine statische Bibliothek mit der Option /ZW
kompilieren, gibt der Bibliothekar (eigentlich der Linker) folgende Warnung aus:
LNK4264: archiving object file compiled with /ZW into a static library; note that when authoring Windows Runtime types it is not recommended to link with a static library that contains Windows Runtime metadata (LNK4264: Mit /ZW kompilierte Objektdatei wird in einer statischen Bibliothek archiviert. Beachten Sie, dass beim Erstellen von Windows-Runtime-Typen das Verknüpfen mit einer statischen Bibliothek, die Windows-Runtime-Metadaten enthält, nicht empfohlen wird.)
Sie können jedoch eine statische Bibliothek in einer UWP-App verwenden, ohne sie neu zu kompilieren mit /ZW
. Ihre Bibliothek kann keine Verweistypen deklarieren oder C++/CX-Konstrukte verwenden. Wenn Sie jedoch nur eine Bibliothek mit systemeigenem Code verwenden möchten, können Sie dies tun, indem Sie die folgenden Schritte ausführen.
So verwenden Sie eine systemeigene, statische C++-Bibliothek in einem UWP-Projekt
Wählen Sie in den Eigenschaften des UWP-Projekts im linken Bereich Konfigurationseigenschaften>Linker>Eingabe aus. Fügen Sie im rechten Bereich der Eigenschaft Zusätzliche Abhängigkeiten den Pfad zur Bibliothek hinzu. Fügen Sie beispielsweise für eine Bibliothek im Projekt, in der die Ausgabe
<SolutionFolder>\Debug\MyNativeLibrary\MyNativeLibrary.lib
platziert wird, den relativen PfadDebug\MyNativeLibrary\MyNativeLibrary.lib
hinzu.Fügen Sie eine Include-Anweisung hinzu, um auf die Headerdatei auf Ihre
pch.h
Datei (falls vorhanden) oder in einer beliebigen.cpp
Datei nach Bedarf zu verweisen, und beginnen Sie mit dem Hinzufügen von Code, der die Bibliothek verwendet.#include "..\MyNativeLibrary\MyNativeLibrary.h"
Fügen Sie im Knoten "Verweise" in Projektmappen-Explorer keinen Verweis hinzu. Dieser Mechanismus funktioniert nur für Komponenten für Windows-Runtime.
Portieren einer C++-Bibliothek in eine Komponente für Windows-Runtime
Angenommen, Sie möchten systemeigene APIs in einer statischen Bibliothek aus einer UWP-App nutzen. Wenn Sie über den Quellcode für die systemeigene Bibliothek verfügen, können Sie den Code zu einer Windows-Runtime Komponente portieren. Es wird keine statische Bibliothek mehr sein; Sie wandeln sie in eine DLL um, die Sie in jeder C++-UWP-App verwenden können. In diesem Verfahren wird beschrieben, wie Sie eine neue Windows-Runtime Komponente erstellen, die C++/CX-Erweiterungen verwendet. Informationen zum Erstellen einer Komponente, die stattdessen C++/WinRT verwendet, finden Sie unter Windows-Runtime Komponenten mit C++/WinRT.
Wenn Sie C++/CX verwenden, können Sie Verweistypen und andere C++/CX-Konstrukte hinzufügen, die für Clients in jedem UWP-App-Code verfügbar sind. Sie können auf diese Typen von C#, Visual Basic oder JavaScript zugreifen. Die grundlegende Prozedur lautet wie folgt:
- Erstellen eines Windows-Runtime Component(Universal Windows)-Projekts,
- Kopieren Sie den Code für ihre statische Bibliothek in die Bibliothek, und
- beheben Sie alle Fehler des Compilers, der durch die
/ZW
Option verursacht wird.
So portieren Sie eine C++-Bibliothek in eine Komponente für Windows-Runtime
Erstellen Sie ein Windows-Runtime Component(Universal Windows)-Projekt.
Schließen Sie das Projekt.
Suchen Sie im Windows Explorer das neue Projekt. Suchen Sie dann das C++-Bibliotheksprojekt, das den Code enthält, den Sie portieren möchten. Kopieren Sie die Quelldateien (Headerdateien, Codedateien und andere Ressourcen, einschließlich in Unterverzeichnissen), aus Ihrem C++-Bibliotheksprojekt. Fügen Sie sie in den neuen Projektordner ein, um die gleiche Ordnerstruktur beizubehalten.
Öffnen Sie das Windows-Runtime Component-Projekt erneut. Öffnen Sie das Kontextmenü für den Projektknoten in Projektmappen-Explorer, und wählen Sie "Vorhandenes Element hinzufügen">aus.
Wählen Sie alle Dateien aus, die Sie aus dem ursprünglichen Projekt hinzufügen möchten, und klicken Sie auf OK. Wiederholen Sie dies ggf. für Unterordner.
Möglicherweise ist der Code jetzt teilweise doppelt. Wenn mehrere vorkompilierte Kopfzeilen vorhanden sind (z. B. beide
stdafx.h
undpch.h
), wählen Sie eine aus, die beibehalten werden soll. Kopieren Sie allen erforderlichen Code, wie z. B. include-Anweisungen, in den beibehaltenen Header. Löschen Sie dann die andere, und stellen Sie in den Projekteigenschaften unter "Vorkompilierte Kopfzeilen" sicher, dass der Name der Headerdatei korrekt ist.Wenn Sie die als vorkompilierten Header zu verwendende Datei geändert haben, überprüfen Sie, ob die Optionen für vorkompilierte Header für jede Datei korrekt sind. Wählen Sie jede
.cpp
Datei wiederum aus, öffnen Sie das Eigenschaftenfenster, und stellen Sie sicher, dass alle auf "Verwenden" (/Yu) festgelegt sind, mit Ausnahme des vorkompilierten Headers, der auf "Erstellen" (/Yc) festgelegt werden soll.Erstellen Sie das Projekt, und beheben Sie alle Fehler. Diese Fehler können durch die Verwendung der
/ZW
Option verursacht werden, oder sie können durch eine neue Version des Windows SDK verursacht werden. Oder sie können Abhängigkeiten wie Kopfzeilendateien widerspiegeln, von denen Ihre Bibliothek abhängt, oder Unterschiede in den Projekteinstellungen zwischen Ihrem alten Projekt und dem neuen.Fügen Sie Ihrem Projekt öffentliche Verweistypen hinzu, oder konvertieren Sie gewöhnliche Typen in Bezugstypen. Verwenden Sie diese Typen, um Einstiegspunkte für die Funktionalität verfügbar zu machen, die Sie von UWP-Apps aufrufen möchten.
Testen Sie die Komponente, indem Sie in einem UWP-App-Projekt einen Verweis darauf erstellen, und fügen Sie Code zum Aufrufen der öffentlichen APIs hinzu, die Sie erstellt haben.