Como: usar o código C++ existente em um aplicativo da Plataforma Universal do Windows
Existem várias maneiras em que você pode usar o código C++ existente em projetos UWP (Plataforma Universal do Windows). Algumas maneiras não exigem que o código seja recompilado com as extensões de componente (C++/CX) habilitadas (ou seja, com a opção /ZW
) e algumas exigem. Talvez seja necessário manter o código no C++ padrão ou preservar um ambiente de compilação clássico do Win32 para alguns códigos. Você ainda pode fazer isso, usando as opções de arquitetura apropriadas. Considere todo o seu código que contém a interface do usuário UWP e os tipos expostos a chamadores do C#, Visual Basic e JavaScript. Esse código deve estar em projetos do aplicativo do Windows e projetos do Componente do Windows Runtime. O código que você chama somente a partir do C++ (incluindo C++/CX) pode estar em um projeto que é compilado com a opção /ZW
ou em um projeto C++ padrão. O código somente binário que não usa APIs não permitidas pode ser usado, vinculando-o como biblioteca estática. Ou você pode empacotá-lo com o aplicativo como conteúdo e carregá-lo em uma DLL.
Talvez a maneira mais fácil para que seu programa da área de trabalho seja executado no ambiente UWP seja usar as tecnologias de Ponte de Desktop. Elas incluem o Desktop App Converter, que empacotará o aplicativo existente como um aplicativo UWP sem nenhuma alteração de código necessária. Para saber mais, veja Ponte de Desktop.
O restante deste arquivo de biblioteca discute como transportar as bibliotecas C++ (bibliotecas estáticas e de DLLs) para a Plataforma Universal do Windows. Convém fazer a portabilidade do código para que a lógica principal do C++ possa ser usada com vários aplicativos UWP.
Os Aplicativos UWP são executados em um ambiente protegido. Como resultado, muitas chamadas à API do Win32, do COM e do CRT que podem comprometer a segurança da plataforma não são permitidas. A opção do compilador /ZW
pode detectar essa chamada e gerar um erro. Você pode usar o Kit de Certificação de Aplicativo em seu aplicativo para detectar o código que chama as APIs proibidas. Para obter mais informações, confira Kit de certificação de aplicativos do Windows.
Se o código-fonte estiver disponível para a biblioteca, você pode eliminar as chamadas a APIs proibidas. Para obter uma lista de APIs proibidas, confira APIs do Win32 e do COM para aplicativos UWP e Funções do CRT sem suporte em aplicativos da Plataforma Universal do Windows. Algumas alternativas podem ser encontradas em Alternatives to Windows APIs in UWP apps (Alternativas para APIs do Windows em aplicativos UWP).
Se você tentar adicionar uma referência de um Projeto Universal do Windows a uma biblioteca de área de trabalho clássica, você obterá uma mensagem de erro que diz que a biblioteca não é compatível. Se for uma biblioteca estática, você pode vincular à sua biblioteca adicionando a biblioteca (arquivo .lib
) à entrada do vinculador, da mesma forma que faria em um aplicativo clássico do Win32. Se apenas uma biblioteca binária estiver disponível, ela será a única opção. Uma biblioteca estática é vinculada ao executável do aplicativo. No entanto, uma DLL do Win32 que você consumirá em um aplicativo UWP deve ser empacotada em um aplicativo, incluída no projeto e marcada como Conteúdo. Para carregar uma DLL do Win32 em um aplicativo UWP, você também precisa chamar LoadPackagedLibrary
, em vez de LoadLibrary
ou LoadLibraryEx
.
Se você tiver o código-fonte da DLL ou da biblioteca estática, poderá recompilar como um projeto UWP, usando a opção do compilador /ZW
. Você pode adicionar uma referência a isso usando o Gerenciador de Soluções e usá-la em aplicativos UWP do C++. Vincule a DLL usando a biblioteca de exportação.
Para expor a funcionalidade para chamadores em outras linguagens, você pode converter a biblioteca em um componente do Windows Runtime. Os Componentes do Windows Runtime diferem de DLLs comuns na medida em que eles incluem metadados na forma de arquivos .winmd
que descrevem os conteúdos de uma maneira que os consumidores .NET e JavaScript exigem. Para expor elementos de API para outras linguagens, você pode adicionar constructos C++/CX, como classes de referência e torná-los públicos. No Windows 10 e posterior, é recomendável usar a biblioteca C++/WinRT, em vez do C++/CX.
A discussão anterior não se aplica aos componentes do COM, que devem ser tratados de maneira diferente. Se você tiver um servidor COM em um EXE ou uma DLL, poderá usá-lo em um Projeto Universal do Windows. Empacote-o como um componente do COM sem registro, adicione-o ao projeto como arquivo de conteúdo e instancie-o usando CoCreateInstanceFromApp
. Para obter mais informações, confira Using Free-COM DLL in Windows Store C++ Project (Usando a DLL Free-COM no projeto C ++ da Windows Store).
Se você quiser portar uma biblioteca do COM existente para a UWP, também será possível convertê-la em um Componente do Windows Runtime. Recomendamos a biblioteca C++/WinRT para essas portas, mas também é possível usar a Biblioteca de Modelos do Windows Runtime C++ (WRL). A WRL foi preterida e não dá suporte a todos os recursos da ATL e do OLE. Determinar se essa porta é viável depende dos recursos do COM, da ATL e do OLE que o componente exige.
Independentemente dos cenários de desenvolvimento escolhidos, você deve estar ciente das várias definições de macro. Você pode usar essas macros no código para compilar o código condicionalmente na área de trabalho clássica do Win32 e da 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)
Essas instruções aplicam-se, respectivamente, a aplicativos UWP e a aplicativos da Windows Phone Store, a ambos ou a nenhum (somente área de trabalho clássica do Win32). Essas macros só estão disponíveis no SDK do Windows 8.1 e posteriores.
Este artigo contém os seguintes procedimentos:
Usando uma biblioteca estática em C++ nativa em um aplicativo UWP
Portabilidade uma biblioteca C++ para um componente do Windows Runtime
Como usar uma DLL do Win32 em um aplicativo UWP
Para maior segurança e confiabilidade, os Aplicativos Universais do Windows são executados em um ambiente de runtime restrito. Você não pode simplesmente usar qualquer DLL nativa como faria em um aplicativo da área de trabalho clássico do Windows. Se você tiver o código-fonte para uma DLL, poderá transportar o código para que ele seja executado na UWP. Comece alterando algumas configurações do projeto e metadados de arquivo de projeto para identificar o projeto como um projeto UWP. Você compilará o código da biblioteca usando a opção /ZW
, que habilita C++/CX. Determinadas chamadas à API não são permitidas em aplicativos UWP devido aos controles mais rigorosos associados a esse ambiente. Para obter mais informações, confira APIs do Win32 e do COM para aplicativos UWP.
Se houver uma DLL nativa que exporta funções usando __declspec(dllexport)
, você poderá chamar essas funções em um aplicativo UWP recompilando a DLL como um projeto UWP. Por exemplo, suponha que temos um projeto de DLL do Win32 chamado Giraffe, que exporta algumas classes e seus métodos, com um código como o seguinte arquivo de cabeçalho:
// 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();
};
E o seguinte arquivo 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 o resto do projeto (pch.h
, dllmain.cpp
) faz parte do modelo de projeto padrão do Win32. O código define a macro GIRAFFE_API
, que é resolvida para __declspec(dllexport)
, quando GIRAFFE_EXPORTS
é definido. Ou seja, ele é definido quando o projeto é criado como uma DLL, mas não quando um cliente usa o cabeçalho giraffe.h
. Essa DLL pode ser usada em um projeto UWP, sem alterar o código-fonte. Apenas algumas configurações e propriedades do projeto precisam ser alteradas.
O procedimento a seguir se aplica ao quando você tem uma DLL nativa que expõe as funções usando o __declspec(dllexport)
.
Para transportar uma DLL nativa para a UWP sem criar um novo projeto
Abra o projeto da DLL no Visual Studio.
Abra as Propriedades do Projeto do projeto de DLL e defina a Configuração como Todas as Configurações.
Nas Propriedades do Projeto, na guia C/C++>Geral, defina Consumir extensão do Windows Runtime para Yes (/ZW). Essa propriedade habilita as extensões de componente (C++/CX).
No Gerenciador de Soluções, selecione o nó do projeto, abra o menu de atalho e escolha Descarregar Projeto. Em seguida, abra o menu de atalho no nó do projeto descarregado e escolha editar o arquivo de projeto. Localize o elemento
WindowsTargetPlatformVersion
e substitua-o pelos seguintes elementos.<AppContainerApplication>true</AppContainerApplication> <ApplicationType>Windows Store</ApplicationType> <WindowsTargetPlatformVersion>10.0.10156.0</WindowsTargetPlatformVersion> <WindowsTargetPlatformMinVersion>10.0.10156.0</WindowsTargetPlatformMinVersion> <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
Feche o arquivo
.vcxproj
, abra o menu de atalho novamente e escolha Recarregar Projeto.Agora, o Gerenciador de Soluções identifica o projeto como universal do Windows.
Verifique se o nome do arquivo de cabeçalho pré-compilado está correto. Na seção Cabeçalhos Pré-Compilados, talvez seja necessário alterar o Arquivo de Cabeçalho Pré-Compilado de
pch.h
parastdafx.h
ou vice-versa, se vir um erro como este:Erro C2857: a instrução '#include' especificada com a opção de linha de comando
/Ycpch.h
não foi encontrada no arquivo de origemO problema é que os modelos de projeto mais antigos usam uma convenção de nomenclatura diferente para o arquivo de cabeçalho pré-compilado. Os projetos do Visual Studio 2019 e posteriores usam o
pch.h
.Compile o projeto. Você pode obter alguns erros sobre as opções de linha de comando incompatíveis. Por exemplo, a opção usada com frequência, mas agora preterida Habilitar Recompilação Mínima (/Gm), é definida por padrão em muitos projetos C++ mais antigos e é incompatível com
/ZW
.Algumas funções não estão disponíveis ao compilar para a Plataforma Universal do Windows. Você verá erros de compilador sobre quaisquer problemas. Resolva esses erros até ter um build limpo.
Para usar a DLL em um aplicativo UWP na mesma solução, abra o menu de atalho do nó do projeto UWP e escolha Adicionar>Referência.
Em Projetos>Solução, marque a caixa de seleção ao lado do projeto de DLL e selecione o botão OK.
Inclua os arquivos de cabeçalho da biblioteca no arquivo
pch.h
do aplicativo UWP.#include "..\Giraffe\giraffe.h"
Adicione o código como de costume no projeto UWP para invocar funções e criar tipos da DLL.
MainPage::MainPage() { InitializeComponent(); GiraffeFactory gf; Giraffe* g = gf.Create(); int id = g->GetID(); }
Como usar uma biblioteca estática em C++ nativa em um aplicativo UWP
Você pode usar uma biblioteca estática em C++ nativa em um projeto UWP, mas há algumas restrições e limitações para estar atento. Comece lendo sobre bibliotecas estáticas em C++/CX. Você pode acessar o código nativo na biblioteca estática do aplicativo UWP, mas não é recomendável criar tipos de referência pública nessa biblioteca estática. Se você compilar uma biblioteca estática com a opção /ZW
, o bibliotecário (na verdade, o vinculador disfarçado) avisará:
LNK4264: arquivando arquivo-objeto compilado com /ZW em uma biblioteca estática; observe que, na criação de tipos do Windows Runtime, não é recomendado vincular a uma biblioteca estática que contêm metadados do Windows Runtime
No entanto, você pode usar uma biblioteca estática em um aplicativo UWP sem recompilá-la com /ZW
. A biblioteca não pode declarar nenhum tipo de ref ou usar constructos C++/CX. Mas, se o objetivo é apenas usar uma biblioteca de código nativo, você pode fazê-lo seguindo estas etapas.
Para usar uma biblioteca estática em C++ nativa em um projeto UWP
Nas propriedades do projeto para o projeto UWP, escolha Propriedades de Configuração>Vinculador>Entrada no painel esquerdo. No painel direito, adicione o caminho para a biblioteca na propriedade Dependências Adicionais. Por exemplo, para uma biblioteca no projeto que coloca sua saída em
<SolutionFolder>\Debug\MyNativeLibrary\MyNativeLibrary.lib
, adicione o caminho relativoDebug\MyNativeLibrary\MyNativeLibrary.lib
.Adicione uma instrução include para fazer referência ao arquivo de cabeçalho no arquivo
pch.h
(se presente) ou em qualquer arquivo.cpp
, conforme necessário, e comece a adicionar o código que usa a biblioteca.#include "..\MyNativeLibrary\MyNativeLibrary.h"
Não adicione uma referência no nó Referências no Gerenciador de Soluções. Esse mecanismo funciona somente para Componente do Windows Runtime.
Portabilidade de uma biblioteca C++ para um componente do Windows Runtime
Suponha que você queira consumir APIs nativas em uma biblioteca estática de um aplicativo UWP. Se você tiver o código-fonte da biblioteca nativa, poderá portar o código para um Componente do Windows Runtime. Não será mais uma biblioteca estática. Você a transformará em uma DLL que pode ser usada em qualquer aplicativo UWP C++. Este procedimento descreve como criar um novo Componente do Windows Runtime que usa extensões C++/CX. Para obter informações sobre como criar um componente que usa C++/WinRT, confira Componentes do Windows Runtime com C++/WinRT.
Ao usar C++/CX, você pode adicionar tipos de referência e outros constructos C++/CX, que estão disponíveis para clientes em qualquer código de aplicativo UWP. Você pode acessar esses tipos do C#, Visual Basic ou JavaScript. O procedimento básico é:
- Crie um projeto do Componente do Windows Runtime (Universal do Windows),
- copie o código para a sua biblioteca estática e
- resolva os erros do compilador causados pela opção
/ZW
.
Para transportar uma biblioteca C++ para um componente do Windows Runtime
Crie um projeto do Componente do Windows Runtime (Universal do Windows).
Feche o projeto.
No Explorador de Arquivos do Windows, localize o novo projeto. Localize o projeto de biblioteca em C++ que contém o código que você deseja transportar. Copie os arquivos de origem (arquivos de cabeçalho, arquivos de código e quaisquer outros recursos, incluindo em subdiretórios) do projeto de biblioteca C++. Cole-os na nova pasta do projeto, preservando a mesma estrutura de pastas.
Abra novamente o projeto de Componente do Windows Runtime. Abra o menu de atalhos do nó de projeto no Gerenciador de Soluções e escolha Adicionar>Item Existente.
Selecione todos os arquivos a serem adicionados do projeto original e, em seguida, escolha OK. Repita se necessário para as subpastas.
Agora você pode ter alguns códigos duplicados. Se houver mais de um cabeçalho pré-compilado (digamos,
stdafx.h
epch.h
), escolha um para manter. Copie qualquer código necessário, como instruções include, no que você está mantendo. Em seguida, exclua o outro e, nas propriedades do projeto, em Cabeçalhos Pré-compilados, certifique-se de que o nome do arquivo de cabeçalho esteja correto.Se você alterou o arquivo a ser usado como o cabeçalho pré-compilado, certifique-se de que as opções de cabeçalho pré-compilado estejam corretas para cada arquivo. Selecione cada arquivo
.cpp
separadamente, abra sua janela Propriedades e certifique-se de que todos estejam definidos como Usar (/Yu), exceto o cabeçalho pré-compilado desejado, que deve ser definido como Criar (/Yc).Compile o projeto e resolva quaisquer erros. Esses erros podem ser causados pelo uso da opção
/ZW
ou podem ser causados por uma nova versão do SDK do Windows. Ou podem refletir dependências como arquivos de cabeçalho dos quais a biblioteca depende ou diferenças nas configurações do projeto entre o projeto antigo e o novo.Adicione tipos de referência pública ao projeto ou converta tipos comuns em tipos de referência. Use esses tipos para expor pontos de entrada na funcionalidade que você deseja chamar em aplicativos UWP.
Teste o componente adicionando uma referência a ela de um projeto de aplicativo UWP e adicione um pouco de código para chamar as APIs públicas criadas.