WinRT no UnrealWinRT in Unreal

Ao longo do desenvolvimento do seu HoloLens, talvez seja necessário escrever um recurso usando o WinRT.Over the course of your HoloLens development you may need to write a feature using WinRT. Por exemplo, abrir uma caixa de diálogo de arquivo em um aplicativo HoloLens precisaria do FileSavePicker no arquivo de cabeçalho winrt/Windows. Storage....For example, opening a file dialogue in a HoloLens application would need the FileSavePicker in winrt/Windows.Storage.Pickers.h header file. O WinRT tem suporte no sistema de compilação inreal da versão 4,26 em diante.WinRT is supported in Unreal's build system from version 4.26 onwards.

Inreal não compila nativamente o código WinRT na versão 4,25, portanto, é seu trabalho criar um binário separado e que pode ser consumido pelo sistema de compilação não real.Unreal doesn't natively compile WinRT code in version 4.25, so it's your job to build a separate binary and that can be consumed by Unreal’s build system. Este tutorial guiará você pelo cenário desse tipo.This tutorial will walk you through just such a scenario.

ObjetivosObjectives

  • Criar uma DLL universal do Windows que abre um FileSaveDialogueCreate a Universal Windows DLL that opens a FileSaveDialogue
  • Vincular essa DLL a um projeto de jogo não realLink that DLL to an Unreal game project
  • Salvar um arquivo no HoloLens de um projeto não real usando a nova DLLSave a file on the HoloLens from an Unreal blueprint using the new DLL

IntroduçãoGetting started

  1. Verifique se você tem todas as ferramentas necessárias instaladasCheck that you have all required tools installed
  2. Criar um novo projeto inreal e nomeá-lo ConsumewinrtCreate a new Unreal project and name it Consumewinrt
  3. Habilitar os plug-ins necessários para o desenvolvimento do HoloLensEnable the required plugins for HoloLens development
  4. Configuração para implantação em um dispositivo ou emuladorSetup for deployment to a device or emulator

Criando uma DLL do WinRTCreating a WinRT DLL

  1. Abra um novo projeto do Visual Studio e crie um projeto dll (universal do Windows) no mesmo diretório para o arquivo uproject do jogo inreal.Open a new Visual Studio project and create a DLL (Universal Windows) project in the same directory to the Unreal game’s uproject file.

Criando uma DLL

  1. Nomeie o projeto HoloLensWinrtDLL e defina o local como um subdiretório ThirdParty para o arquivo uproject do jogo inreal.Name the project HoloLensWinrtDLL and set the location as a ThirdParty subdirectory to the Unreal game’s uproject file.
    • Selecione posicionar solução e projeto no mesmo diretório para simplificar a procura de caminhos mais tarde.Select Place solution and project in the same directory to simplify looking for paths later.

Configurando a DLL

Importante

Depois que o novo projeto é compilado, você deseja prestar atenção especial aos arquivos cpp e de cabeçalho em branco, chamados HoloLensWinrtDLL. cpp e HoloLensWinrtDLL. h , respectivamente.After the new project compiles, you want to pay special attention to the blank cpp and header files, named HoloLensWinrtDLL.cpp and HoloLensWinrtDLL.h respectively. O cabeçalho é o arquivo de inclusão que usa a DLL em tempo real, enquanto a cpp mantém o corpo de todas as funções que você exporta e inclui qualquer código do WinRT que não seja possível compilar de outra forma.The header is the include file that uses the DLL in Unreal, while the cpp holds the body of any functions you export and includes any WinRT code that Unreal wouldn't otherwise be able to compile.

  1. Antes de adicionar qualquer código, você precisa atualizar as propriedades do projeto para garantir que o código do WinRT que você precisa pode compilar:Before you add any code, you need to update the project properties to ensure the WinRT code you need can compile:
    • Clique com o botão direito do mouse no projeto HoloLensWinrtDLL e selecione PropriedadesRight click on the HoloLensWinrtDLL project and select properties
    • Alterar a lista suspensa de configuração para todas as configurações e a lista suspensa de plataforma para todas as plataformasChange the Configuration dropdown to All Configurations and the Platform dropdown to All Platforms
    • Em Propriedades de configuração> C/C++> todas as opções:Under Configuration Properties> C/C++> All Options:
      • Adicionar Await a Opções adicionais para garantir que possamos aguardar em tarefas assíncronasAdd await to Additional Options to ensure we can wait on async tasks
      • Alterar o padrão de linguagem C++ para ISO C++ 17 Standard (/std: C++ 17) para incluir qualquer código do WinRTChange C++ Language Standard to ISO C++17 Standard (/std:c++17) to include any WinRT code

Atualizando Propriedades do projeto

Seu projeto está pronto para atualizar a origem da DLL com o código do WinRT que abre uma caixa de diálogo de arquivo e salva um arquivo no disco do HoloLens.Your project is ready to update the DLL’s source with WinRT code that opens a file dialogue and saves a file to the HoloLens disk.

Adicionando o código DLLAdding the DLL code

  1. Abra HoloLensWinrtDLL. h e adicione uma função exportada de dll para consumir inrealmente:Open HoloLensWinrtDLL.h and add a dll exported function for Unreal to consume:
#pragma once

class HoloLensWinrtDLL
{
public:
    _declspec(dllexport) static void OpenFileDialogue();
};
  1. Abra HoloLensWinrtDLL. cpp e adicione todos os cabeçalhos que a classe usará:Open HoloLensWinrtDLL.cpp and add all headers the class will use:
#include "pch.h"
#include "HoloLensWinrtDLL.h"

#include <winrt/Windows.Storage.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Storage.Pickers.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>

#include <string>
#include <vector>
#include <thread>

Observação

Todo o código do WinRT é armazenado em HoloLensWinrtDLL. cpp , de modo que não tente incluir nenhum código do winrt ao referenciar o cabeçalho.All WinRT code is stored in HoloLensWinrtDLL.cpp so Unreal doesn't try to include any WinRT code when referencing the header.

  1. Ainda em HoloLensWinrtDLL. cpp, adicione um corpo de função para OpenFileDialogue () e todo o código com suporte:Still in HoloLensWinrtDLL.cpp, add a function body for OpenFileDialogue() and all supported code:
// sgm is declared outside of OpenFileDialogue so it doesn't
// get destroyed when OpenFileDialogue goes out of scope.
SaveGameManager sgm;

void HoloLensWinrtDLL::OpenFileDialogue()
{
    sgm.SaveGame();
}
  1. Adicione uma classe SaveGameManager a HoloLensWinrtDLL. cpp para manipular a caixa de diálogo do arquivo e salvar o arquivo:Add a SaveGameManager class to HoloLensWinrtDLL.cpp to handle the file dialogue and saving the file:
class SaveGameManager
{
public:
    SaveGameManager()
    {
    }

    ~SaveGameManager()
    {
        // Wait for currently running thread to complete before terminating.
        if(m_thread.joinable())
        {
            m_thread.join();
        }
    }

    void SaveGame()
    {
        OpenFileDialogueAction();
    }

private:
    winrt::Windows::Storage::StorageFile m_file = winrt::Windows::Storage::StorageFile(nullptr);
    std::thread m_thread;

    winrt::Windows::Foundation::IAsyncAction OpenFileDialogueAction()
    {
        std::vector<winrt::hstring> extensions;
        extensions.push_back(L".txt");

        auto picker = winrt::Windows::Storage::Pickers::FileSavePicker();

        // FileSavePicker needs a file type to open without errors.
        picker.FileTypeChoices().Insert(L"Plain Text",
                                        winrt::single_threaded_vector<winrt::hstring>(
                                        std::move(extensions)));

        // Opening the FilePicker must be done on the Game UI thread.
        // Any other IAsyncOperations should be done on a background thread.
        m_file = co_await picker.PickSaveFileAsync();

        if(m_file)
        {
            // Unreal's game thread is an STA, async tasks need to run on
            // a background MTA thread, or waiting on them will deadlock.    
            std::thread thread([this]() { RunThread(); });
            m_thread = std::move(thread);
        }
    }

    void RunThread()
    {
        // Ensure this thread is an MTA
        winrt::init_apartment();
        Run().get();
    }

    winrt::Windows::Foundation::IAsyncAction Run()
    {
        co_await winrt::Windows::Storage::FileIO::WriteTextAsync(
                m_file, L"Hello WinRT");
    }
};
  1. Compile a solução para a versão > ARM64 para criar a dll para o diretório filho ARM64/Release/HoloLensWinrtDLL da solução de dll.Build the solution for Release > ARM64 to build the DLL to the child directory ARM64/Release/HoloLensWinrtDLL from the DLL solution.

Adicionar o binário do WinRT a um não realAdding the WinRT binary to Unreal

Vincular e usar uma DLL em um Unreal requer um projeto C++.Linking and using a DLL in Unreal requires a C++ project. Se você estiver usando um projeto Blueprint, ele poderá ser facilmente convertido em um projeto C++ adicionando uma classe C++:If you're using a Blueprint project, it can be easily converted to a C++ project by adding a C++ class:

  1. No editor inreal, abra arquivo > nova classe C++...In the Unreal editor, open File > New C++ Class… e crie um novo ator chamado WinrtActor para executar o código na DLL:and create a new Actor named WinrtActor to run the code in the DLL:

Criando um novo ator

Observação

Agora, uma solução foi criada no mesmo diretório que o arquivo uproject, juntamente com um novo script de compilação chamado source/ConsumeWinRT/ConsumeWinRT. Build. cs.A solution has now been created in the same directory as the uproject file along with a new build script named Source/ConsumeWinRT/ConsumeWinRT.Build.cs.

  1. Abra a solução, procure a pasta Games/ConsumeWinRT/origem/ConsumeWinRT e abra ConsumeWinRT.Build.cs:Open the solution, browse for the Games/ConsumeWinRT/Source/ConsumeWinRT folder, and open ConsumeWinRT.build.cs:

Abrindo o arquivo ConsumeWinRT.build.cs

Vinculando a DLLLinking the DLL

  1. Em ConsumeWinRT.Build.cs, adicione uma propriedade para localizar o caminho de inclusão para a dll (o diretório que contém HoloLensWinrtDLL. h).In ConsumeWinRT.build.cs, add a property to find the include path for the DLL (the directory containing HoloLensWinrtDLL.h). A DLL está em um diretório filho para o caminho de inclusão, portanto, essa propriedade será usada como a dir raiz binária:The DLL is in a child directory to the include path, so this property will be used as the binary root dir:
using System.IO;

public class ConsumeWinRT : ModuleRules
{
    private string WinrtIncPath
    {
        get 
        {
            string ModulePath = Path.GetDirectoryName(
                   RulesCompiler.GetFileNameFromType(this.GetType()));

            // Third party directory is at the project root,
            // which is two directories up from the game .exe (Binaries/HoloLens)
            return Path.GetFullPath(
                   Path.Combine(ModulePath,
                   "../../ThirdParty/HoloLensWinrtDLL"));
        }
    }
}
  1. No construtor de classe, adicione o seguinte código para atualizar o caminho de inclusão, vincular a nova lib e atrasar o carregamento e copiar a DLL para o local Appx empacotado:In the class constructor, add the following code to update the include path, link the new lib, and delay-load and copy the DLL to the packaged appx location:
public ConsumeWinRT(ReadOnlyTargetRules target) : base(Target)
{
    // This is the directory the DLL's include header is in.
    PublicIncludePaths.Add(WinrtIncPath);

    // The code in HoloLensWinrtDLL will only work in a Windows Store app.
    // Only link these binaries for HoloLens.
    // Similar code can be written for desktop and similarly linked 
    // to use the same features when using Holographic Remoting.
    if(Target.Platform == UnrealTargetPlatform.HoloLens)
    {
        // Link the lib
        PublicAdditionalLibraries.Add(Path.Combine(
              WinrtIncPath, "ARM64", "Release",
              "HoloLensWinrtDLL","HoloLensWinrtDLL.lib"));

        string winrtDLL = "HoloLensWinrtDLL.dll";
        // Mark the dll to be DelayLoaded
        PublicDelayLoadDLLs.Add(winrtDLL);
        // RuntimeDependencies are included in packaged builds.
        RuntimeDependencies.Add(Path.Combine(WinrtIncPath,
                "ARM64", "Release", "HoloLensWinrtDLL", winrtDLL));
    }

    // Preserve the original code in build.cs below:
}
  1. Abra WinrtActor. h e adicione uma definição de função, que será chamada por um plano gráfico:Open WinrtActor.h and add one function definition, one that a blueprint will call:
public:
    UFUNCTION(BlueprintCallable)
    static void OpenFileDialogue();
  1. Abra WinrtActor. cpp e atualize BeginPlay para carregar a dll:Open WinrtActor.cpp and update BeginPlay to load the DLL:
void AWinrtActor::BeginPlay()
{
    Super::BeginPlay();

    // Gets path to DLL location
    const FString BinDir = FPaths::ProjectDir() / 
        "ThirdParty" / "HoloLensWinrtDLL" / 
        "arm64" / "Release" / "HoloLensWinrtDLL";

    // Loads DLL into application
    void * dllHandle = FPlatformProcess::GetDllHandle(
        *(BinDir / "HoloLensWinrtDLL.dll"));
}

void AWinrtActor::OpenFileDialogue()
{
#if PLATFORM_HOLOLENS
    HoloLensWinrtDLL::OpenFileDialogue();
#endif
}

Cuidado

A DLL deve ser carregada antes de chamar qualquer uma de suas funções.The DLL must be loaded before calling any of its functions.

Criando o jogoBuilding the game

  1. Crie a solução de jogos para iniciar o editor inreal aberto no projeto de jogo:Build the game solution to launch the Unreal editor opened to the game project:
    • Na guia local atores , pesquise o novo WinrtActor e arraste-o para a cenaIn the Place Actors tab, search for the new WinrtActor and drag it into the scene
    • Abra o Blueprint de nível para executar a função que tem o plano de execução no WinrtActorOpen the level blueprint to execute the blueprint callable function in the WinrtActor

Colocando o WinrtActor na cena

  1. Na estrutura mundial, encontre o WindrtActor que foi previamente colocado na cena e arraste-o para o plano Blueprint:In the World Outliner, find the WindrtActor previously dropped into the scene and drag it into the level blueprint:

Arrastando o WinrtActor para o plano gráfico de nível

  1. No nível Blueprint, arraste o nó saída de WinrtActor, procure a caixa de diálogo abrir arquivo e, em seguida, encaminhe o nó de qualquer entrada do usuário.In the level blueprint, drag the output node from WinrtActor, search for Open File Dialogue, then route the node from any user input. Nesse caso, a caixa de diálogo abrir arquivo está sendo chamada de um evento de fala:In this case, Open File Dialogue is being called from a speech event:

Configurando nós no nível Blueprint

  1. Empacote este jogo para o HoloLens, implante-o e execute-o.Package this game for HoloLens, deploy it, and run.

Quando as chamadas inreais OpenFileDialogue, uma caixa de diálogo de arquivo é aberta no HoloLens solicitando um nome de arquivo. txt.When Unreal calls OpenFileDialogue, a File Dialogue opens on the HoloLens prompting for a .txt file name. Depois que o arquivo for salvo, vá para a guia Explorador de arquivos no portal do dispositivo para ver o conteúdo "Olá WinRT".After the file is saved, go to the File explorer tab in the device portal to see the contents “Hello WinRT”.

ResumoSummary

Incentivamos você a usar o código neste tutorial como um ponto de partida para consumir o código do WinRT em um estado inreal.We encourage you to use the code in this tutorial as a starting point for consuming WinRT code in Unreal. Ele permite que os usuários salvem arquivos no disco do HoloLens usando a mesma caixa de diálogo de arquivo que o Windows.It allows users to save files to the HoloLens disk using the same file dialogue as Windows. Siga o mesmo processo para exportar funções adicionais do cabeçalho HoloLensWinrtDLL e usadas em um não real.Follow the same process to export any additional functions from the HoloLensWinrtDLL header and used in Unreal. Observe o código de DLL que aguarda em qualquer código assíncrono do WinRT em um thread MTA de segundo plano, que evita o deadlock do thread de jogo inreal.Note the DLL code that waits on any async WinRT code in a background MTA thread, which avoids deadlocking the Unreal game thread.

Próximo ponto de verificação de desenvolvimentoNext Development Checkpoint

Se você está seguindo o percurso do ponto de verificação de desenvolvimento do Unreal que apresentamos, você está no meio da exploração de funcionalidades e APIs da plataforma de Realidade Misturada.If you're following the Unreal development checkpoint journey we've laid out, you're in the midst of exploring the Mixed Reality platform capabilities and APIs. A partir daqui, você pode prosseguir para qualquer tópico ou ir diretamente para a implantação de seu aplicativo em um dispositivo ou emulador.From here, you can proceed to any topic or jump directly to deploying your app on a device or emulator.

Confira tambémSee also