UnrealC++でUE4の標準ライブラリでダイナミックリンク

#はじめに
最近、UE4の標準ライブラリでダイナミックリンクライブラリをダイナミックリンクさせる方法を見つけたのでご紹介します。
ダイナミックリンクライブラリやダイナミックリンクについては、以下の記事で分かりやすく解説されています。

[VC++　DLLの呼び出しと解放](https://qiita.com/village/items/dd265b9e47e95023a0c5)

#つくるもの
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325493/affe10ff-423d-57f5-2799-f4e1a7475fe6.png)

BPから自作のダイナミックリンクライブラリ(以下DLL)の関数を使用するノードを作成します。

#つくってみる
まずは、DLLを作成します。作り方については「はじめに」でご紹介した記事を参照してください。

```DllTest.cpp
extern "C" __declspec(dllexport) int PlusInt(int x, int y)
{
	return (x + y);
}
```
BPから使用する関数は上記の関数です。2つの整数を足した値を返します。

次に作成したDLLをロードして関数を実行できるようにする部分を作成します。
今回はDLLのロードやアンロードなどの処理をモジュールクラスに実装します。

```TestPlugin.h
#pragma once

#include "Modules/ModuleManager.h"

typedef int(*PlusInt)(int X, int Y);

class FTestPluginModule : public IModuleInterface
{
private:
	//ロードするDllのポインタ
	void* ModulePtr;

	//Dllから取得する関数のポインタ
	PlusInt PlusIntPtr;

public:
	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;

	int ExecPlusInt(int X, int Y);
};
```
まずはヘッダーファイルから見ていきましょう。
ロードした関数を実行する関数とDLLのポインタ、ロードする関数のポインタを定義します。
DLLのロードとアンロードはモジュールの開始時と終了時に行います。

```TestPlugin.cpp
#include "TestPlugin.h"
#include "Misc/Paths.h"

#define LOCTEXT_NAMESPACE "FTestPluginModule"

void FTestPluginModule::StartupModule()
{
	//dllファイルのパスを取得
	FString DllPath = FPaths::ConvertRelativePathToFull(FPaths::Combine(FPaths::ProjectPluginsDir(), TEXT("TestPlugin"), TEXT("ThirdParty")));
#ifdef _WIN64
	DllPath = FPaths::Combine(DllPath, TEXT("Win64"));
#elif _WIN32
	DllPath = FPaths::Combine(DllPath, TEXT("Win32"));
#endif
	DllPath = FPaths::Combine(DllPath, TEXT("DllTest.dll"));

	//モジュールをロード
	ModulePtr = FPlatformProcess::GetDllHandle(*DllPath);
	if (ModulePtr == nullptr)
	{
		UE_LOG(LogTemp, Fatal, TEXT("Failed to load module"));
	}

	//関数ポインタを取得
	PlusIntPtr = (PlusInt)FPlatformProcess::GetDllExport(ModulePtr, TEXT("PlusInt"));
	if (PlusIntPtr == nullptr)
	{
		UE_LOG(LogTemp, Fatal, TEXT("Failed to get function pointer"));
	}

	UE_LOG(LogTemp, Log, TEXT("Dll loaded"));
}

void FTestPluginModule::ShutdownModule()
{
	FPlatformProcess::FreeDllHandle(ModulePtr);
	UE_LOG(LogTemp, Log, TEXT("Dll unloaded"));
}

int FTestPluginModule::ExecPlusInt(int X, int Y)
{
	return PlusIntPtr(X, Y);
}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FTestPluginModule, TestPlugin)
```
次に実装ファイルを見ていきましょう。
まず、DLLのロードやアンロードなどを行うのは`FPlatformProcess`クラスです。
DLLの操作については以下の関数を使用します。

|操作|関数|
|:-----------------:|:------------------:|
|DLLのロード|FPlatformProcess::GetDllHandle|
|関数ポインタの取得|FPlatformProcess::GetDllExport|
|DLLのアンロード|FPlatformProcess::FreeDllHandle|
処理の流れは「はじめに」でご紹介した記事にあるWIN32APIを利用した場合と変わりません。

DLLのファイルパスを組み立て、DLLをロードし、関数ポインタを取得する、という流れです。
最後にロードしたDLLをアンロードします。

最後にBPから利用できるようBlueprintFunctionLibraryを作成します。

```TestPluginBPLibrary.h
UFUNCTION(BlueprintCallable, Category = "TestPlugin")
static int PlusInt_DLL(int X, int Y);
```

```TestPluginBPLibrary.cpp
int UTestPluginBPLibrary::PlusInt_DLL(int X, int Y)
{
	FTestPluginModule& TestPluginModule = FModuleManager::LoadModuleChecked<FTestPluginModule>(FName("TestPlugin"));
	return TestPluginModule.ExecPlusInt(X, Y);
}
```

プロジェクトをビルドしてBPで以下のような処理を組み、実行すると2つの整数の合計が表示されるはずです。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325493/c6606c55-d76f-a41c-d23b-b81b5e1883c1.png)
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325493/b511ca3d-8738-e615-f661-e0c3c3056002.png)

#おわりに
ダイナミックリンクは外部APIを使用する際に利用する機会があるのではないでしょうか。
WIN32APIでも同じことはできますが、UE4のライブラリを使用することでWindowsだけでなくMacやLinuxでも動作するようになります。
各プラットフォームでの処理が気になるのであればソースコードを見ているのも面白いかもしれません。

この記事で紹介したプロジェクトは以下でダウンロードできます。
https://github.com/Naotsun19B/DLL_DynamicLink