【Unity6】C++からUnity(C#)側に値や文字列を渡したい

# やりたいこと
C++プロジェクトから"return"で値や文字列を渡して、Unity内で使用したい。
色々試行錯誤してみて、自分の中で方法が確立されたのでメモ。
渡したい情報は「数値、浮動小数点、真偽値、文字列」
C++から`int`, `double`, `bool`, `const char*`として渡す。

**環境**
> ・Visual Studio 2022 Community
> ・C++ 14
> ・C♯ 9.0
> ・Unity 6000.0.37f1

### まず .dllプロジェクトを作成する。
今回はVisual Studio 2022 の Community版を使用する。

**新しいプロジェクトの作成(N) → Windowsデスクトップウィザード
→ パス&プロジェクト名設定 → Windowsデスクトッププロジェクト**
に進み、

**アプリケーションの種類(T):** ダイナミックライブラリ(.dll)
**追加のオプション:** 空のプロジェクト(E)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920837/b85c6f25-4d33-42b0-97d8-d862b9c51485.png)

と設定する。
今回はプロジェクト名を`ReturnValue`としている。

## C++側
`ReturnValue.h`と`ReturnValue.cpp`を作成し、以下のように記述する。

**ReturnValue.h**
```cpp
#pragma once

#ifdef RETURNVALUE_EXPORTS
#   define EXPORT __declspec(dllexport)
#else
#   define EXPORT __declspec(dllimport)
#endif

extern "C" __declspec(dllexport) int ReturnInt();
extern "C" __declspec(dllexport) double ReturnDouble();
extern "C" __declspec(dllexport) bool ReturnBool();
extern "C" __declspec(dllexport) const char* ReturnString();
```

**ReturnValue.cpp**
```cpp
#include "ReturnValue.h"

__declspec(dllexport) int ReturnInt()
{
	return 123;
}

__declspec(dllexport) double ReturnDouble()
{
	return 1.23;
}

__declspec(dllexport) bool ReturnBool()
{
	return true;
}

__declspec(dllexport) const char* ReturnString()
{
	return "Hello, C++";
}
```
リリースビルドが無事に通ると、`x64/Release`の中に`ReturnValue.dll`が生成される。

## Unity側
`Assets`フォルダの中に分かりやすいように`Plugins`フォルダを作成し、生成した`ReturnValue.dll`を入れる。

次に適当なC♯ファイルを作成し以下のように記述する。
(今回はファイル名を`Test`としている。)

**Test.cs**
```cs
using System;
using System.Runtime.InteropServices;   // DllImport用
using UnityEngine;

public class Test : MonoBehaviour
{
    [DllImport("ReturnValue.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern int ReturnInt();
    
    [DllImport("ReturnValue.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern double ReturnDouble();
    
    [DllImport("ReturnValue.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern bool ReturnBool();

    [DllImport("ReturnValue.dll", CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr ReturnString();

    // 文字列用
    private string str;

    void Awake()
    {
        Debug.Log($"int: {ReturnInt()}");
        Debug.Log($"double: {ReturnDouble()}");
        Debug.Log($"bool: {ReturnBool()}");

        IntPtr p = ReturnString();
        str = Marshal.PtrToStringAnsi(p);
        Debug.Log($"string: {str}");
    }
}
```

## 実行結果
```
int: 123
UnityEngine.Debug:Log (object)
Test:Awake () (at Assets/Scripts/Test.cs:23)

double: 1.23
UnityEngine.Debug:Log (object)
Test:Awake () (at Assets/Scripts/Test.cs:24)

bool: True
UnityEngine.Debug:Log (object)
Test:Awake () (at Assets/Scripts/Test.cs:25)

string: Hello, C++
UnityEngine.Debug:Log (object)
Test:Awake () (at Assets/Scripts/Test.cs:29)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3920837/2c6f8e80-9695-4f4d-b7bd-43b8939c49d9.png)



参考文献
[C++ライブラリ（DLL）をUnity（C#）向けに作成して利用するシンプルな方法](https://zenn.dev/meson_tech_blog/articles/make-dll-for-unity?redirected=1)