UE5 EA Visual Studio 2019 ~動的リンクライブラリ(.dll)を作成してUEで使用する~
Visual Studio 2019で動的ライブラリ(.dll)を作成するプロジェクトを作成していきます。
DLLには2種類のリンク方式があります。
Explicit Linking(明示的リンク)
Implicit Linking(暗黙的リンク)
2種類のリンク方式のDLLを作成して、UE4で呼び出す方法についてまとめました。
Visual Studio 2019で動的ライブラリ(DLL)を作成する
Explicit Linking(明示的リンク)のDLLを作成する
Visual Studio 2019で新しいプロジェクトを作成します。
Dynamic Link Library(DLL)を作成するテンプレートを選択します。
今回は一つのソリューションに2つのプロジェクトを含めるので、Project nameとSolution nameを別々に設定します。
・Project name:DLL_Explicit
・Solution name:DLLSample
Module-Definition File(.def)とC++ファイル(.cpp)を追加します。
・DLL_Explicit.def
・DLL_Explicit.cpp
Module-Definition File(.def)は[Visual C++ > Code]を選択すると表示されます。
DLL_Explicit.def
LIBRARY DLL_Explicit
EXPORTS
DLL_Explicit_AddTest @1
DLL_Explicit_AddTest_Arg3 @2
DLL_ExplicitTest.cpp
#include "pch.h"
int DLL_Explicit_AddTest(int A, int B)
{
return A + B;
}
int DLL_Explicit_AddTest_Arg3(int A, int B, int C)
{
return A + B + C;
}
Module-Definition File[DLL_Explicit.def]が設定されていることを確認します。
プロジェクトファイルを右クリック > Properties
Release(x64)の設定に作成したModule-Definition File[DLL_Explicit.def]が設定されていることを確認します。
Build ConfigurationをRelease(x64)に設定します。
Configuration Managerを開きます。
Build ConfigurationをRelease(x64)に設定します。
・Active solution configuration:Release
・Active solution platform:x64
プロジェクトをビルドします。
ソリューションのフォルダ > x64 > Release配下にDLLが作成されます。
Explicit Linging(明示的リンク)のDLLは.dllファイルのみを使用します。
Implicit Linking(暗黙的リンク)のDLLを作成する
ソリューションにImplicit Linking(暗黙的リンク)のDLLを作成するプロジェクトを追加します。
Dynamic Link Library(DLL)を作成するテンプレートを選択します。
Project nameを[DLL_Implicit]設定します。
ヘッダファイル(.h)とC++ファイル(.cpp)を追加します。
・DLL_Implicit.h
・DLL_Implicit.cpp
DLL_Implicit.h
#pragma once
#ifdef DLL_EX
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
DLL_API int DLL_Implicit_AddTest(int A, int B);
DLL_API int DLL_Implicit_AddTest_Arg3(int A, int B, int C);
#ifdef __cplusplus
}
#endif
DLL_Implicit.cpp
#include "pch.h"
#include "DLL_Implicit.h"
int __stdcall DLL_Implicit_AddTest(int A, int B)
{
return A + B;
}
int __stdcall DLL_Implicit_AddTest_Arg3(int A, int B, int C)
{
return A + B + C;
}
この状態で一度Buildを行います。
Implicit Linking(暗黙的リンク)のDLLはDLLとLIB と、LIBから呼び出すのでヘッダーファイルが必要になります。
(ソリューションフォルダ)/x64/Release
・DLL_Implicit.dll
・DLL_Implicit.lib
(ソリューションフォルダ)/DLL_Implicit
・DLL_Implicit.h
UE5 EAでDLLを使用する
DLLを使用するテスト用のC++プロジェクトを作成する
UE5 EAでDLLを使用する準備をします。
BlankのC++プロジェクトを作成します。
Explicit Linking(明示的リンク)のDLL(DLL_Explicit.dll)を使用する
DLL_Explicit.dllをUE5プロジェクトにコピーします。
【コピー元】
(ソリューションファイル)/x64/Release
・DLL_Explicit.dll
【コピー先】
(UE5プロジェクトフォルダ)/Binaries/Win64
Explicit Linking(明示的リンク)のDLLを呼び出すためのActorクラスを追加します。
親クラスにActorを選択します。
名前を[DLLExplicitActor](Private)に設定します。
追加したソースコードを修正します。
DLLExplicitActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DLLExplicitActor.generated.h"
UCLASS()
class ADLLExplicitActor : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="Call DLL Explicit Test")
static int32 CallExplicitAddTest(const int32 A, const int32 B, bool& success);
UFUNCTION(BlueprintCallable, Category = "Call DLL Explicit Test")
static int32 CallExplicitAddTest_Arg3(const int32 A, const int32 B, const int32 C, bool& success);
};
DLLExplicitActor.cpp
#include "DLLExplicitActor.h"
int32 ADLLExplicitActor::CallExplicitAddTest(const int32 A, const int32 B, bool& success)
{
typedef int(*_dll_function)(int _A, int _B); // DLLAddTestのポインタ型を宣言する
static void* dll_ptr = nullptr; // 読み込むDLL(DynamicLibTest.dll)を格納する変数
static _dll_function func_ptr = nullptr; // DLLに含まれる関数へのポインタを格納する変数
const static FString dllname = "DLL_Explicit.dll"; // DLL名
const static FString funcname = "DLL_Explicit_AddTest"; // 関数名
// DLLを読み込み、ポインタを取得
dll_ptr = FPlatformProcess::GetDllHandle(*dllname);
if (!dll_ptr)
{
success = false;
return 0;
}
// DLLから関数の位置を取得
func_ptr = (_dll_function)FPlatformProcess::GetDllExport(dll_ptr, *funcname);
if (!func_ptr)
{
success = false;
return 0;
}
// 関数の呼び出しが成功したので、関数を呼び出す
success = true;
return (*func_ptr)(A, B);
}
int32 ADLLExplicitActor::CallExplicitAddTest_Arg3(const int32 A, const int32 B, const int32 C, bool& success)
{
typedef int(*_dll_function)(int _A, int _B, int _C);
static void* dll_ptr = nullptr;
static _dll_function func_ptr = nullptr;
const static FString dllname = "DLL_Explicit.dll";
const static FString funcname = "DLL_Explicit_AddTest_Arg3";
// DLLを読み込み、ポインタを取得
dll_ptr = FPlatformProcess::GetDllHandle(*dllname);
if (!dll_ptr)
{
success = false;
return 0;
}
func_ptr = (_dll_function)FPlatformProcess::GetDllExport(dll_ptr, *funcname);
if (!func_ptr)
{
success = false;
return 0;
}
success = true;
return (*func_ptr)(A, B, C);
}
ビューポートに作成したActor[DLLExplicitActor]を追加します。
DLLの関数を呼び出して、PrintStringで出力する処理を書いていきます。
レベルブループリントを開きます。
BeginPlay時に関数[CallExplicitAddTest]と[CallExplicitAddTest_Arg3]を呼び出して、PrintStringで出力する処理を実装します。
関数ごとに色を別々にすると確認しやすいです。
Playして足し算の結果を確認します。
足し算結果が合っているので、DLLの関数を呼び出すことが出来ました。
ShippingBuild時にアプリのパッケージ内にDLLをコピーする(Build.cs)
DLLを特定の場所に置くことで実行できますが、DLLはアプリのパッケージ内に含める必要があります。DLLをパッケージ内に含める設定を行います。
「(UE5 EAプロジェクト名).Build.cs」を開きます。
CPP_DLLTest.Build.cs
using UnrealBuildTool;
public class CPP_DLLTest : ModuleRules
{
public CPP_DLLTest(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] { });
var DLLExplicitPath = ModuleDirectory + "../../../Binaries/Win64/DLL_Explicit.dll";
PublicDelayLoadDLLs.Add(DLLExplicitPath);
RuntimeDependencies.Add(new RuntimeDependency(DLLExplicitPath));
}
}
DLLを読み込み、パッケージ内にDLLをコピーする処理
var DLLExplicitPath = ModuleDirectory + "../../../Binaries/Win64/DLL_Explicit.dll";
PublicDelayLoadDLLs.Add(DLLExplicitPath);
RuntimeDependencies.Add(new RuntimeDependency(DLLExplicitPath));
Shippingビルドをして、DLLがアプリ内に含まれるか確認します。
Binary Configurationを[Shipping]に設定します。
プロジェクトをパッケージ化します。
DLL_Explicit.dllがアプリと同じフォルダにコピーされました。
ここまでがExplicit Linging(明示的リンク)のDLLを使用するまでの設定になります。
Implicit Linking(暗黙的リンク)のDLL(DLL_Implicit.dll)を使用する
Implicit Linking(暗黙的リンク)のDLLはDLLとLIB と、LIBから呼び出すのでヘッダーファイルが必要になります。
(ソリューションフォルダ)/x64/Release
・DLL_Implicit.dll
・DLL_Implicit.lib
(ソリューションフォルダ)/DLL_Implicit
・DLL_Implicit.h
必要なファイルを以下の構成になるようにコピーします
(UE5 EA Projectフォルダ)
├ Binaries
| └ Win64
| └ DLL_Implicit.dll
└ Source/
└ (UE5 EA Project名)/
├ Library/
| ├ header/
| | └ DLL_Implicit.h
| └ lib/
| └ DLL_Implicit.lib
├ Private
|
静的ライブラリの時と同様にBuild.csの修正を行います。
CPP_DLLTestBuild.cs
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class CPP_DLLTest : ModuleRules
{
public CPP_DLLTest(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] { });
var DLLExplicitPath = ModuleDirectory + "../../../Binaries/Win64/DLL_Explicit.dll";
PublicDelayLoadDLLs.Add(DLLExplicitPath);
RuntimeDependencies.Add(new RuntimeDependency(DLLExplicitPath));
PublicIncludePaths.Add(ModuleDirectory + "/Library/header");
if (Target.Platform == UnrealTargetPlatform.Win64)
{
PublicAdditionalLibraries.Add(ModuleDirectory + "/Library/lib/DLL_Implicit.lib");
}
var DLLImplicitPath = ModuleDirectory + "../../../Binaries/Win64/DLL_Implicit.dll";
PublicDelayLoadDLLs.Add(DLLImplicitPath);
RuntimeDependencies.Add(new RuntimeDependency(DLLImplicitPath));
}
}
・ヘッダーファイルのIncludePathを追加
・静的ライブラリを追加する(プラットフォームがWin64)
・DLLのコピー処理も追加します。
PublicIncludePaths.Add(ModuleDirectory + "/Library/header");
if (Target.Platform == UnrealTargetPlatform.Win64)
{
PublicAdditionalLibraries.Add(ModuleDirectory + "/Library/lib/DLL_Implicit.lib");
}
var DLLImplicitPath = ModuleDirectory + "../../../Binaries/Win64/DLL_Implicit.dll";
PublicDelayLoadDLLs.Add(DLLImplicitPath);
RuntimeDependencies.Add(new RuntimeDependency(DLLImplicitPath));
静的ライブラリ(.lib)とヘッダーファイルの配置、Build.csの修正が出来たら、Visual Studio projectを更新します。
静的ライブラリ(.lib)とヘッダーファイルがプロジェクトに追加されました。
ビューポートに作成したActor[DLLImplicitActor]を追加します。
DLLの関数を呼び出して、PrintStringで出力する処理を書いていきます。
親クラスにActorを選択します。
名前をDLLImplicitActor(Private)に設定します。
追加したソースコードを修正します。
DLL_Implicit.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DLLImplicitActor.generated.h"
UCLASS()
class ADLLImplicitActor : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Call DLL Implict Test")
static int32 CallImplicitAddTest(const int32 A, const int32 B);
UFUNCTION(BlueprintCallable, Category = "Call DLL Implict Test")
static int32 CallImplicitAddTest_Arg3(const int32 A, const int32 B, const int32 C);
};
DLL_Implicit.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "DLLImplicitActor.h"
#include "DLL_Implicit.h"
int32 ADLLImplicitActor::CallImplicitAddTest(const int32 A, const int32 B)
{
return DLL_Implicit_AddTest(A, B);
}
int32 ADLLImplicitActor::CallImplicitAddTest_Arg3(const int32 A, const int32 B, const int32 C)
{
return DLL_Implicit_AddTest_Arg3(A, B, C);
}
ビューポートに作成したActor[DLLImplicitActor]を追加します。
DLLの関数を呼び出して、PrintStringで出力する処理を書いていきます。
レベルブループリントを開きます。
BeginPlay時に関数[CallImplicitAddTest]と[CallImplicitAddTest_Arg3]を呼び出して、PrintStringで出力する処理を実装します。
関数ごとに色を別々にすると確認しやすいです。Explicitの結果と切り分けるために数値を10倍しています。
Playして足し算の結果を確認します。
足し算結果が合っているので、DLLの関数を呼び出すことが出来ました。
Shippingビルド時にDLLがパッケージ内にコピーされるか確認します。
プロジェクトをパッケージングします。
DLL_Implicit.dllも同様にパッケージにコピーされました。
ここまでがImplicit Linging(暗黙的リンク)のDLLを使用するまでの設定になります。
まとめ
静的ライブラリとそんなに変わらなそうだから直ぐに書けると始めましたが、かなりのボリュームになりました。
これで外部ライブラリを使用出来るようになったのでUnreal Engine以外の機能を取り込むことが出来るようになりました。
DLLは奥が深いし、今後も使っていくので随時更新していきます。
いよいよプラグイン開発の入口に立つことが出来たのでワクワクします。
【参考資料】
【参照URL(VisualStudio側)】
【参照URL(Unreal Engine側)】
この記事が気に入ったらサポートをしてみませんか?