Unreal での WinRTWinRT in Unreal

概要Overview

HoloLens 開発の過程で、WinRT を使用して機能を作成することが必要になる場合があります。Over the course of your HoloLens development you may need to write a feature using WinRT. たとえば、HoloLens アプリケーションでファイルのダイアログを開くには、FileSavePicker ヘッダーファイルに含まれている必要があります。For example, opening a file dialogue in a HoloLens application would need the FileSavePicker in winrt/Windows.Storage.Pickers.h header file. Unreal は WinRT コードをネイティブにコンパイルしないため、独立したバイナリをビルドし、Unreal のビルドシステムで使用できるようにすることができます。Since Unreal doesn't natively compile WinRT code, it's your job to build a separate binary and that can be consumed by Unreal’s build system. このチュートリアルでは、このようなシナリオについて説明します。This tutorial will walk you through just such a scenario.

目標Objectives

  • FileSaveDialogue を開くユニバーサル Windows DLL を作成するCreate a Universal Windows DLL that opens a FileSaveDialogue
  • その DLL を Unreal game プロジェクトにリンクするLink that DLL to an Unreal game project
  • 新しい DLL を使用して、不要なブループリントから HoloLens にファイルを保存するSave a file on the HoloLens from an Unreal blueprint using the new DLL

作業の開始Getting started

  1. すべての 必要なツール がインストールされていることを確認するCheck that you have all required tools installed
  2. 新しい Unreal プロジェクトを作成し、 Consumewinrt という名前を指定します。Create a new Unreal project and name it Consumewinrt
  3. HoloLens 開発に 必要なプラグイン を有効にするEnable the required plugins for HoloLens development
  4. デバイスまたはエミュレーターに配置するためのセットアップSetup for deployment to a device or emulator

WinRT DLL の作成Creating a WinRT DLL

  1. 新しい Visual Studio プロジェクトを開き、Unreal game の uproject ファイルと同じディレクトリに DLL (ユニバーサル Windows) プロジェクトを作成します。Open a new Visual Studio project and create a DLL (Universal Windows) project in the same directory to the Unreal game’s uproject file.

DLL の作成

  1. プロジェクトに HoloLensWinrtDLL という名前を付け、その場所を ThirdParty サブディレクトリとして、unreal game の uproject ファイルに設定します。Name the project HoloLensWinrtDLL and set the location as a ThirdParty subdirectory to the Unreal game’s uproject file.
    • 後でパスを簡単に検索するには 、[ソリューションとプロジェクトを同じディレクトリに配置 する] を選択します。Select Place solution and project in the same directory to simplify looking for paths later.

DLL の構成

重要

新しいプロジェクトがコンパイルされた後、空白の cpp ファイルとヘッダーファイルに特に注意する必要があります。これには、それぞれ HoloLensWinrtDLLHoloLensWinrtDLL という名前が付けられます。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. ヘッダーは、Unreal の DLL を使用するインクルードファイルです。 cpp は、エクスポートした関数の本体を保持し、それ以外の場合はコンパイルできない WinRT コードを含みます。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. コードを追加する前に、必要な WinRT コードをコンパイルできるように、プロジェクトのプロパティを更新する必要があります。Before you add any code, you need to update the project properties to ensure the WinRT code you need can compile:
    • HoloLensWinrtDLL プロジェクトを右クリックし、[プロパティ] を選択します。Right click on the HoloLensWinrtDLL project and select properties
    • 構成 ドロップダウンを [すべての構成] に変更し、[プラットフォーム] ドロップダウンを [すべてのプラットフォーム] に変更します。Change the Configuration dropdown to All Configurations and the Platform dropdown to All Platforms
    • [ 構成プロパティ] で> C/c + +> すべてのオプション] を選択します。Under Configuration Properties> C/C++> All Options:
      • 非同期タスクを待機できるように、 await追加のオプション に追加します。Add await to Additional Options to ensure we can wait on async tasks
      • C++ 言語標準ISO c++ 17 標準 (/std: C++ 17) に変更して WinRT コードを含めるChange C++ Language Standard to ISO C++17 Standard (/std:c++17) to include any WinRT code

プロジェクトプロパティのアップグレード

プロジェクトは、ファイルダイアログを開き、ファイルを HoloLens ディスクに保存する WinRT コードを使用して、DLL のソースを更新する準備ができています。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.

DLL コードの追加Adding the DLL code

  1. HoloLensWinrtDLL を開き、dll のエクスポート関数を追加して、unreal に使用します。Open HoloLensWinrtDLL.h and add a dll exported function for Unreal to consume:
#pragma once

class HoloLensWinrtDLL
{
public:
    _declspec(dllexport) static void OpenFileDialogue();
};
  1. HoloLensWinrtDLL を開き、クラスで使用するすべてのヘッダーを追加します。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>

注意

すべての WinRT コードは HoloLensWinrtDLL に格納されているため、unreal はヘッダーを参照するときに winrt コードを含めようとしません。All WinRT code is stored in HoloLensWinrtDLL.cpp so Unreal doesn't try to include any WinRT code when referencing the header.

  1. HoloLensWinrtDLL の中で、OpenFileDialogue () およびサポートされているすべてのコードの関数本体を追加します。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. SaveGameManager クラスを HoloLensWinrtDLL に追加して、ファイルのダイアログを処理し、ファイルを保存します。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. Release > ARM64 のソリューションをビルドして、dll ソリューションから ARM64/Release/HoloLensWinrtDLL 子ディレクトリに dll をビルドします。Build the solution for Release > ARM64 to build the DLL to the child directory ARM64/Release/HoloLensWinrtDLL from the DLL solution.

WinRT バイナリを Unreal に追加するAdding the WinRT binary to Unreal

アン Real で DLL をリンクして使用するには、C++ プロジェクトが必要です。Linking and using a DLL in Unreal requires a C++ project. ブループリントプロジェクトを使用している場合は、C++ クラスを追加することで、C++ プロジェクトに簡単に変換できます。If you're using a Blueprint project, it can be easily converted to a C++ project by adding a C++ class:

  1. Unreal エディターで、[ファイル > 新しい C++ クラス... ] を開きます。In the Unreal editor, open File > New C++ Class… 次に、 Winrtactor という名前の新しい アクター を作成し、DLL 内のコードを実行します。and create a new Actor named WinrtActor to run the code in the DLL:

新しいアクターの作成

注意

Uproject ファイルと同じディレクトリに、Source/ConsumeWinRT/ConsumeWinRT という名前の新しいビルドスクリプトと共にソリューションが作成されました。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. ソリューションを開き、 game/ConsumeWinRT/Source/consumewinrt フォルダーを参照し、 ConsumeWinRT.build.cs を開きます。Open the solution, browse for the Games/ConsumeWinRT/Source/ConsumeWinRT folder, and open ConsumeWinRT.build.cs:

ConsumeWinRT.build.cs ファイルを開く

DLL のリンクLinking the DLL

  1. ConsumeWinRT.build.cs で、プロパティを追加して、DLL のインクルードパス (HoloLensWinrtDLL を含むディレクトリ) を検索します。In ConsumeWinRT.build.cs, add a property to find the include path for the DLL (the directory containing HoloLensWinrtDLL.h). DLL は、インクルードパスの子ディレクトリにあるため、このプロパティはバイナリルートディレクトリとして使用されます。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. クラスコンストラクターで、次のコードを追加してインクルードパスを更新し、新しい lib をリンクして、遅延読み込みを行い、DLL をパッケージ化された appx の場所にコピーします。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. Winrtactor を開き、1つの関数定義を追加します。1つは、ブループリントによって呼び出されます。Open WinrtActor.h and add one function definition, one that a blueprint will call:
public:
    UFUNCTION(BlueprintCallable)
    static void OpenFileDialogue();
  1. Winrtactor を開き、beginplay を更新して 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
}

注意事項

DLL は、その関数のいずれかを呼び出す前に読み込む必要があります。The DLL must be loaded before calling any of its functions.

ゲームを構築するBuilding the game

  1. ゲームソリューションをビルドして、game プロジェクトで開かれている Unreal エディターを起動します。Build the game solution to launch the Unreal editor opened to the game project:
    • [ アクターの配置 ] タブで、新しい winrtactor を検索し、シーンにドラッグします。In the Place Actors tab, search for the new WinrtActor and drag it into the scene
    • レベルブループリントを開き、 Winrtactor でブループリント呼び出し可能関数を実行します。Open the level blueprint to execute the blueprint callable function in the WinrtActor

WinrtActor をシーンに配置する

  1. 世界 中では、前にシーンにドロップした Windrtactor を見つけて、レベルのブループリントにドラッグします。In the World Outliner, find the WindrtActor previously dropped into the scene and drag it into the level blueprint:

WinrtActor をレベルブループリントにドラッグする

  1. レベルブループリントで、[出力] ノードを WinrtActor からドラッグし、[ ファイルを開く] ダイアログ を検索して、任意のユーザー入力からノードをルーティングします。In the level blueprint, drag the output node from WinrtActor, search for Open File Dialogue, then route the node from any user input. この場合、[ファイルを開く] ダイアログが音声イベントから呼び出されます。In this case, Open File Dialogue is being called from a speech event:

レベルブループリントでのノードの構成

  1. このゲームを HoloLens 用にパッケージ化し、展開して、を実行します。Package this game for HoloLens, deploy it, and run.

Unreal が OpenFileDialogue を呼び出すと、ファイルのダイアログが表示され、HoloLens のファイル名を要求するメッセージが表示されます。When Unreal calls OpenFileDialogue, a File Dialogue opens on the HoloLens prompting for a .txt file name. ファイルが保存されたら、デバイスポータルの [ ファイルエクスプローラー ] タブにアクセスして、"Hello WinRT" という内容を表示します。After the file is saved, go to the File explorer tab in the device portal to see the contents “Hello WinRT”.

まとめSummary

このチュートリアルのコードは、Unreal で WinRT コードを使用するための出発点として使用することをお勧めします。We encourage you to use the code in this tutorial as a starting point for consuming WinRT code in Unreal. Windows と同じファイルを使用して、ユーザーが HoloLens ディスクにファイルを保存できるようにします。It allows users to save files to the HoloLens disk using the same file dialogue as Windows. 同じプロセスに従って、HoloLensWinrtDLL ヘッダーから他の関数をエクスポートし、Unreal で使用します。Follow the same process to export any additional functions from the HoloLensWinrtDLL header and used in Unreal. バックグラウンド MTA スレッドで非同期 WinRT コードを待機する DLL コードに注意してください。これにより、Unreal game スレッドのデッドロックが回避されます。Note the DLL code that waits on any async WinRT code in a background MTA thread, which avoids deadlocking the Unreal game thread.

次の開発チェックポイントNext Development Checkpoint

私たちが用意した Unreal 開発チェックポイント体験に従っている場合、読者は Mixed Reality プラットフォームの機能と API を探索している段階にいます。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. ここから、任意の トピック に進み、デバイスまたはエミュレーターへのアプリのデプロイに直接進むことができます。From here, you can proceed to any topic or jump directly to deploying your app on a device or emulator.

関連項目See also