Procedimiento Usar código C++ existente en una aplicación para la Plataforma universal de Windows
Estas son las distintas formas en que puede utilizar el código C++ existente en proyectos de la Plataforma universal de Windows. Algunas maneras no requieren que el código se vuelva a compilar con las extensiones de componente (C++/CX) habilitadas (es decir, con la opción /ZW
) y otras sí. Es posible que tenga que mantener el código en C++estándar o conservar un entorno de compilación de Win32 clásico para cierto código. Todavía puede hacerlo con las elecciones de arquitectura adecuadas. Considere todo el código que contiene tipos y UI de UWP y está expuesto a autores de llamada de C#, Visual Basic y JavaScript. Este código debe estar en proyectos de aplicaciones de Windows y proyectos de componentes de Windows Runtime. El código al que debe llamar únicamente desde C++ (incluido C++/CX) puede encontrarse tanto en un proyecto que se compila con la opción /ZW
como en un proyecto de C++ estándar. El código solo binario que no usa API no permitidas se puede usar al vincularlo como una biblioteca estática. O bien, puede empaquetarlo con la aplicación como contenido y cargarlo en una DLL.
Quizás la forma más sencilla de conseguir que un programa de escritorio se ejecute en el entorno de UWP es usar las tecnologías de Puente de dispositivo de escritorio. Entre estas se incluye Desktop App Converter, que empaquetará su aplicación existente como una aplicación para UWP sin necesidad de realizar cambios en el código. Para obtener más información, vea Puente de dispositivo de escritorio.
El resto de este artículo trata sobre cómo migrar bibliotecas de C++ (DLL y bibliotecas estáticas) a la Plataforma universal de Windows. Podría interesarle trasladar su código de modo que su lógica básica de C++ se pueda usar con varias aplicaciones para UWP.
Las aplicaciones para UWP se ejecutan en un entorno protegido. Como resultado, no se permiten muchas llamadas API de Win32, COM y CRT que podrían poner en riesgo la seguridad de la plataforma. La opción del compilador /ZW
puede detectar este tipo de llamadas y generar un error. Puede usar el Kit de certificación de aplicaciones en la aplicación para detectar código que llama a API no permitidas. Para más información sobre estas pruebas, vea Kit para la certificación de aplicaciones en Windows.
Si el código fuente está disponible para la biblioteca, puede intentar eliminar las llamadas a API no permitidas. Para ver una lista de las API no permitidas, consulte API de Win32 y COM para aplicaciones de UWP y Funciones de CRT no admitidas en aplicaciones de la Plataforma universal de Windows. Pueden encontrarse algunas alternativas en Alternatives to Windows APIs in UWP apps (Alternativas a las API de Windows en aplicaciones de la Plataforma universal de Windows).
Si solo intenta agregar una referencia de un proyecto Universal Windows a una biblioteca de escritorio clásica, obtendrá un mensaje de error que indica que la biblioteca no es compatible. En el caso de una biblioteca estática, puede incluir un vínculo a la biblioteca agregando la biblioteca (archivo .lib
) a la entrada del enlazador, tal como lo haría en una aplicación clásica de Win32. Si solo hay disponible una biblioteca binaria, es la única opción. Una biblioteca estática está vinculada al archivo ejecutable de la aplicación. Sin embargo, una DDL de Win32 que consume en una aplicación para UWP se debe empaquetar en la aplicación al incluirla en el proyecto y marcarla como contenido. Para cargar un DLL de Win32 en una aplicación para UWP, también tiene que llamar a LoadPackagedLibrary
en vez de LoadLibrary
oLoadLibraryEx
.
Si tiene código fuente para la DLL o para una biblioteca estática, puede volver a compilarlo como un proyecto UWP al usar la opción del compilador /ZW
. A continuación, puede agregar una referencia mediante el Explorador de soluciones y usarla en aplicaciones para UWP de C++. Vincule la DLL al usar la biblioteca de exportación.
Para exponer la funcionalidad a llamadores en otros lenguajes, puede convertir la biblioteca en un componente de Windows en tiempo de ejecución. Los componentes de Windows Runtime se diferencian de los DLL normales en que incluyen metadatos en forma de archivos .winmd
que describen el contenido de la manera en que los consumidores de .NET y JavaScript lo requieren. Para exponer elementos de la API en otros lenguajes, puede agregar construcciones de C++/CX, como clases de referencia, y hacerlas públicas. En Windows 10 y versiones posteriores, puede recomendar la biblioteca de C++/WinRT en lugar de C++/CX.
La descripción anterior no se aplica en el caso de los componentes COM, que deben controlarse de manera diferente. Si cuenta con un servidor COM en un EXE o una DLL, puede usarlo en un proyecto de Universal Windows. Empaquételo como un componente COM sin registro, agréguelo al proyecto como un archivo de contenido y cree una instancia de él mediante CoCreateInstanceFromApp
. Para más información, vea Using Free-COM DLL in Windows Store C++ Project (Usar un archivo DLL de COM gratuito en un proyecto de C++ de la Tienda Windows).
Si quiere migrar una biblioteca COM existente a UWP, también es posible convertirla en un componente de Windows Runtime. Se recomienda la biblioteca de C++/WinRT para estos puertos, pero también es posible usar la biblioteca de plantillas de C++ de Windows Runtime (WRL). La WRL está en desuso y no admite todas las características de ATL y OLE. Si este puerto es factible o no depende de las características de COM, ATL y OLE que requiere el componente.
Independientemente de los escenarios de desarrollo que elija, debe tener en cuenta una serie de definiciones de macro. Puede usar estas macros en su código para compilar código condicionalmente en Win32 de escritorio clásico y 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)
Estas instrucciones se aplican respectivamente a las aplicaciones de la Plataforma universal Windows, la tienda de Windows Phone, ambas o ninguna (solo a las de escritorio clásico de Win32). Estas macros solo están disponibles en Windows SDK 8.1 y versiones posteriores.
Este artículo contiene los siguientes procedimientos:
Mediante un archivo DLL de Win32 en una aplicación de la Plataforma universal de Windows
Usar una biblioteca estática nativa de C++ en una aplicación para UWP
Convertir una biblioteca de C++ en un componente de Windows Runtime
Usar un archivo DLL de Win32 en una aplicación de la UWP
Para obtener mejor seguridad y confiabilidad, las aplicaciones para Universal Windows se ejecutan en un entorno de runtime restringido. No puede simplemente usar cualquier DLL nativa en la forma en que lo haría en una aplicación de escritorio de Windows. Si tiene código fuente para un archivo DLL, puede migrar el código para que se ejecute en la plataforma universal de Windows. Empiece por cambiar algunos metadatos del archivo de proyecto y la configuración del proyecto para identificar el proyecto como un proyecto de UWP. Debe volver a compilar el código de la biblioteca con la opción /ZW
, lo que habilita C++/CX. No se permiten ciertas llamadas a API en las aplicaciones para UWP debido a los controles más estrictos asociados con ese entorno. Para obtener más información, consulte API de Win32 y COM para aplicaciones de UWP.
Si dispone de una DLL nativa que exporta funciones mediante __declspec(dllexport)
, puede llamar a estas funciones desde una aplicación UWP recompilando la DLL como un proyecto UWP. Por ejemplo, supongamos que tenemos un proyecto de DLL de Win32 llamado Giraffe que exporta un par de clases y sus métodos, con un código como el siguiente archivo de encabezado:
// 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();
};
Y el siguiente archivo de código:
// 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();
Todo lo demás en el proyecto (pch.h
, dllmain.cpp
) forma parte de la plantilla de proyecto estándar de Win32. El código define la macro GIRAFFE_API
, que se resuelve en __declspec(dllexport)
cuando se define GIRAFFE_EXPORTS
. Es decir, se define cuando el proyecto se compila como una DLL, pero no cuando un cliente usa el encabezado giraffe.h
. Esta DLL se puede usar en un proyecto de UWP sin cambiar el código fuente. Solo es necesario cambiar algunos valores y propiedades del proyecto.
El siguiente procedimiento se aplica en el caso de que tenga una DLL nativa que expone funciones mediante __declspec(dllexport)
.
Portar una DLL nativa a UWP sin crear un nuevo proyecto
Abra el proyecto de DLL en Visual Studio.
Abra Propiedades del proyecto para el proyecto DLL y establezca Configuración en Todas las configuraciones.
En Propiedades del proyecto, en la pestaña C/C++>General, establezca Usar extensión de Windows Runtime en Sí (/ZW). Esta propiedad habilita las extensiones de componente (C++/CX).
En el Explorador de soluciones, seleccione el nodo del proyecto, abra el menú contextual y elija Descargar el proyecto. A continuación, abra el menú contextual en el nodo del proyecto descargado y elija Editar el archivo de proyecto. Busque el elemento
WindowsTargetPlatformVersion
y reemplácelo por los siguientes elementos.<AppContainerApplication>true</AppContainerApplication> <ApplicationType>Windows Store</ApplicationType> <WindowsTargetPlatformVersion>10.0.10156.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformMinVersion>10.0.10156.0</WindowsTargetPlatformMinVersion> <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
Cierre el archivo
.vcxproj
, vuelva a abrir el menú contextual de nuevo y elija Volver a cargar el proyecto.Ahora, el Explorador de soluciones identifica el proyecto como un proyecto de Windows universal.
Asegúrese de que el nombre de archivo del encabezado precompilado es correcto. En la sección Encabezados precompilados, es posible que tenga que cambiar el archivo de encabezado precompilado de
pch.h
astdafx.h
o de otro modo si ve un error similar al siguiente:error C2857: no se encontró la instrucción '#include' especificada con la opción de línea de comandos
/Ycpch.h
en el archivo de origenLa cuestión es que las plantillas de proyecto anteriores utilizan una nomenclatura diferente para el archivo de encabezado precompilado. Los proyectos de Visual Studio 2019 y versiones posteriores usan
pch.h
.Compile el proyecto. Podrían aparecer algunos errores acerca de opciones de línea de comandos incompatibles. Por ejemplo, la opción Habilitar recompilación mínima (/Gm) usada con frecuencia, pero ahora en desuso, se establece de forma predeterminada en muchos proyectos de C++ más antiguos y no es compatible con
/ZW
.Algunas funciones no están disponibles cuando compile para la Plataforma universal de Windows. Verá errores del compilador acerca de cualquier problema. Resuelva estos errores hasta que tenga una compilación limpia.
Para usar el archivo DLL en una aplicación para UWP en la misma solución, abra el menú contextual del nodo del proyecto de UWP y seleccione Agregar>Referencia.
En Proyectos>Solución, active la casilla que se encuentra junto al proyecto DLL y seleccione el botón Aceptar.
Incluya los archivos de encabezado de la biblioteca en el archivo
pch.h
de la aplicación para UWP.#include "..\Giraffe\giraffe.h"
Agregue código como de costumbre en el proyecto de UWP para invocar funciones y crear tipos en el archivo DLL.
MainPage::MainPage() { InitializeComponent(); GiraffeFactory gf; Giraffe* g = gf.Create(); int id = g->GetID(); }
Usar una biblioteca estática nativa de C++ en una aplicación de la UWP
Puede utilizar una biblioteca estática de C++ nativa en un proyecto UWP, pero se deben tener en cuenta algunas restricciones y limitaciones. Empiece leyendo sobre bibliotecas estáticas en C++/CX. Puede acceder al código nativo de la biblioteca estática desde su aplicación de UWP, pero no se recomienda crear tipos de referencia pública en ese tipo de biblioteca estática. Si compila una biblioteca estática con la opción /ZW
, el bibliotecario (en realidad, el enlazador camuflado) advierte:
LNK4264: almacenamiento de un archivo objeto compilado con /ZW en una biblioteca estática; tenga en cuenta que, al crear tipos de Windows Runtime, no se recomienda la vinculación con una biblioteca estática que contenga metadatos de Windows Runtime.
Sin embargo, puede utilizar una biblioteca estática en una aplicación para UWP sin recompilarla con /ZW
. La biblioteca no puede declarar ningún tipo de referencia ni usar construcciones de C++/CX. Sin embargo, si su objetivo es precisamente usar una biblioteca de código nativo, puede hacerlo siguiendo estos pasos.
Utilizar una biblioteca estática nativa de C++ en un proyecto de UWP
En las propiedades del proyecto UWP, elija Propiedades de configuración>Vinculador>Entrada en el panel izquierdo. En el panel derecho, agregue la ruta de acceso a la biblioteca en la propiedad Dependencias adicionales. Por ejemplo, para una biblioteca en un proyecto que coloca su salida en
<SolutionFolder>\Debug\MyNativeLibrary\MyNativeLibrary.lib
, agregue la ruta de acceso relativaDebug\MyNativeLibrary\MyNativeLibrary.lib
.Agregue una instrucción include para que la referencia al archivo de encabezado de su archivo
pch.h
(si está presente) haga referencia al archivo.cpp
, según sea necesario, y comience a agregar el código que utiliza la biblioteca.#include "..\MyNativeLibrary\MyNativeLibrary.h"
No agregue una referencia en el nodo Referencias del Explorador de soluciones. Este mecanismo solo funciona con los componentes de Windows Runtime.
Convertir una biblioteca de C++ en un componente de Windows Runtime
Supongamos que desea consumir API nativas en una biblioteca estática desde una aplicación para UWP. Si tiene el código fuente para la biblioteca nativa, puede migrar el código a un componente de Windows Runtime. Ya no será una biblioteca estática; la convertirá en una DLL que puedes usar en cualquier aplicación para UWP de C++. En este procedimiento se describe cómo crear un nuevo componente de Windows Runtime que usa extensiones de C++/CX. Para obtener información sobre cómo crear un componente que use C++/WinRT en su lugar, consulte Componentes de Windows Runtime con C++/WinRT.
Cuando usa C++/CX, puede agregar tipos de referencia y otras construcciones de C++/CX, que están disponibles para clientes en cualquier código de aplicación para UWP. Puede acceder a estos tipos en C#, Visual Basic o JavaScript. El procedimiento básico es el siguiente:
- Cree un proyecto de componente de Windows Runtime (Universal Windows),
- copie el código de la biblioteca estática en él y
- solucione cualquier error del compilador causado por la opción
/ZW
.
Trasladar una biblioteca de C++ a un componente de Windows en tiempo de ejecución
Cree un proyecto de componente de Windows Runtime (Universal Windows).
Cierre el proyectos.
En el Explorador de archivos de Windows, busque el nuevo proyecto. A continuación, localice el proyecto de biblioteca de C++ que contiene el código que desee migrar. Copie los archivos de origen (archivos de encabezado, archivos de código y cualquier otro recurso, incluidos los que están en subdirectorios) de su proyecto de biblioteca de C++. Péguelos en la nueva carpeta del proyecto y asegúrese de conservar la misma estructura de carpetas.
Cree un proyecto de componente de Windows Runtime. Abra el menú contextual del nodo del proyecto en el Explorador de soluciones y elija Agregar>Elemento existente.
Seleccione todos los archivos que va a agregar desde el proyecto original y haga clic en Aceptar. Repita este paso con las subcarpetas si es necesario.
Es posible que ahora haya algún código duplicado. Si tiene más de un encabezado precompilado (por ejemplo,
stdafx.h
ypch.h
), elija uno que conservar. Copie cualquier código necesario, como incluir instrucciones, en el encabezado que mantenga. Después, elimine el otro y, en las propiedades del proyecto, en Encabezados precompilados, asegúrese de que el nombre del archivo de encabezado es correcto.Si cambia el archivo para utilizarlo como encabezado precompilado, asegúrese de que las opciones de encabezado precompilado son las adecuadas para cada archivo. Seleccione cada archivo
.cpp
a su vez, abra la ventana de propiedades y asegúrese de que todos están configurados en Usar (/Yu), excepto el encabezado precompilado, que debe configurarse en Crear (/Yc).Compile el proyecto y resuelva los errores. Estos errores podrían deberse al uso de la opción
/ZW
o podrían deberse a una nueva versión de Windows SDK. O bien, podrían reflejar dependencias como los archivos de encabezado de los que depende su biblioteca, o diferencias en los valores del proyecto entre su proyecto anterior y el nuevo.Agregue tipos de referencias públicas a su proyecto, o convierta los tipos ordinarios en tipos de referencia. Use estos tipos para exponer puntos de entrada a la funcionalidad que desea llamar de las aplicaciones para UWP.
Pruebe el componente agregándole una referencia desde un proyecto de aplicación de UWP y agregue algo de código para llamar a las API públicas que creó.