LoginSignup
2
2

More than 1 year has passed since last update.

Unity C#とC++間の配列・構造体の連携(備忘録)

Posted at

はじめに

前回C++プラグインの各種プラットフォームのテンプレートを作成した記事を書きました。
配列と構造体の連携方法を備忘録として残します。
ソースは前回作成したテンプレートを元にビルドしていきます。

C++コード

ヘッダー

#ifndef SOURCE_LIBRARY_HPP
#define SOURCE_LIBRARY_HPP

#ifdef _WINDOWS
    #define _CRT_SECURE_NO_WARNINGS
    #define DLL_EXPORT __declspec(dllexport)
#endif

#ifndef _WINDOWS
    #define DLL_EXPORT
#endif

struct SampleStruct {
    int a;
    float b;
    char c;
};

extern "C"  {
    DLL_EXPORT void intArray(int* ptr, int length);
    DLL_EXPORT void sampleStruct(SampleStruct* ret);
};

#endif //SOURCE_LIBRARY_HPP

ソース

#include "library.hpp"


void intArray(int* ptr, int length) {
	for (int i = 0; i < length; i++) {
		ptr[i] = i + 1;
	}
}

void sampleStruct(SampleStruct* ret) {
	ret->a = 5;
	ret->b = 5.5f;
	ret->c = 'c';
}

C#とC++のブリッジ

using System;
using System.Runtime.InteropServices;

public class PluginTest
{
    public struct SampleStruct
    {
        public int a;
        public float b;
        public char c;
    }
    
#if !UNITY_EDITOR && UNITY_IOS
    private const string PLUGIN_NAME = "__Internal";
#else
    private const string PLUGIN_NAME = "sampleplugin";
#endif

    [DllImport(PLUGIN_NAME)]
    public static extern void intArray(IntPtr ptr, int length);

    [DllImport(PLUGIN_NAME)]
    public static extern void sampleStruct(IntPtr intPtr);
}

int配列の連携

C#側

int arraySize = Marshal.SizeOf(typeof(int)) * 5;
IntPtr intPtr = Marshal.AllocCoTaskMem(arraySize);
PluginTest.intArray(intPtr, 5);

int[] intArray = new int[5];
Marshal.Copy(intPtr, intArray, 0, 5);
for (int i = 0; i < intArray.Length; i++)
{
    Debug.Log($"index:{i} value:{intArray[i]}");
}
Marshal.FreeCoTaskMem(intPtr);

結果

image.png

構造体の連携

C#側

PluginTest.SampleStruct sampleStruct = new PluginTest.SampleStruct();
IntPtr pStruct = Marshal.AllocCoTaskMem(Marshal.SizeOf(sampleStruct));
Marshal.StructureToPtr(sampleStruct, pStruct, false);

PluginTest.sampleStruct(pStruct);

sampleStruct = (PluginTest.SampleStruct)Marshal.PtrToStructure(pStruct, typeof(PluginTest.SampleStruct));

Debug.Log($"a:{sampleStruct.a}");
Debug.Log($"b:{sampleStruct.b}");
Debug.Log($"c:{sampleStruct.c}");

Marshal.FreeCoTaskMem(pStruct);

結果

image.png

補足

Marshal.StructureToPtr(sampleStruct, pStruct, false);

第3引数は第2引数のポインタが示す構造体を破棄する場合はtrue。

今回は破棄する必要が無いのでfalse。

注意点

C++側でnewしたものをreturnすると、メモリリークの原因になるので、C#側でメモリの確保と解放をしたほうが安全。
処理の都合上C++側でnewが必要なものに関しては、処理が終わるころにはすべて解放するようにするか、解放用の関数を別途作成してC#側から呼び出すという方法が必要。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2