Unity Native Plugin C# and C++ call each other

official link

1. The way of DLL:

C++ code: compiled into DLL, imported into Unity

#pragma once
#include <map>
#include <string>

//导出宏定义
#define _DllExport _declspec(dllexport)

//函数指针
typedef void (*NativeCallback)(const char*);

extern "C"
{
    
    
	//注意这里字符串不能用C++的std::string,和C#的string不等价,等价的是char*,即字符数组
	_DllExport void RegisterNativeCallback(const char* functionName, NativeCallback callback);
	_DllExport void UpdateNative();
}

//缓存C#函数的地址
std::map<std::string, NativeCallback> _callbackMap;

//导出让C#调用,注册C#端的函数,注册后就可以在C++端调用C#的函数,本质就职把C#函数的地址给到C++,C++调用。
_DllExport void RegisterNativeCallback(const char* functionName, NativeCallback callback)
{
    
    
	_callbackMap[std::string(functionName)] = callback;
}

//导出让C#调用
_DllExport void UpdateNative()
{
    
    
	//调用C#端的函数,可以在Unity性能分析界面看到Native update,用此方法可以在Unity界面查看C++代码的耗时
	_callbackMap[std::string("BeginSample")]("Native update");
	_callbackMap[std::string("Log")]("Native Log");
	_callbackMap[std::string("EndSample")]("Native update");
}

C# code:

using AOT;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;

namespace Haha
{
    
    
    public class TestCPPLib : MonoBehaviour
    {
    
    
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        delegate void NativeCallback(string args);

        [DllImport("CPPLib")]
        static extern void RegisterNativeCallback(string functionName, IntPtr callback);

        [DllImport("CPPLib")]
        static extern void UpdateNative();

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackLog(string args)
        {
    
    
            Debug.Log(args);
        }

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackBeginSample(string args)
        {
    
    
            Profiler.BeginSample(args);
        }

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackEndSample(string args)
        {
    
    
            Profiler.EndSample();
        }

        void Start()
        {
    
    
        	//调用C++函数,注册C#函数
            RegisterNativeCallback("Log", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackLog)));
            RegisterNativeCallback("BeginSample", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackBeginSample)));
            RegisterNativeCallback("EndSample", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackEndSample)));
        }

        private void Update()
        {
    
    
        	//调用C++函数
            UpdateNative();
        }
    }
}

2. There is also a C++ source code as a plug-in, which only supports il2cpp.

C++ code: put it directly in the Assets directory of Unity

C# source file: The difference is that you don’t write the specific file name when importing, just write: __Internal, because using the IL2CPP backend method will put the C++ source file inside the project and compile it together.

using AOT;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;

namespace Haha
{
    
    
    public class TestCPPLib : MonoBehaviour
    {
    
    
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        delegate void NativeCallback(string args);
		
		//区别在这里:
        [DllImport("__Internal")]
        static extern void RegisterNativeCallback(string functionName, IntPtr callback);

        [DllImport("__Internal")]
        static extern void UpdateNative();

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackLog(string args)
        {
    
    
            Debug.Log(args);
        }

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackBeginSample(string args)
        {
    
    
            Profiler.BeginSample(args);
        }

        [MonoPInvokeCallback(typeof(NativeCallback))]
        static void CallbackEndSample(string args)
        {
    
    
            Profiler.EndSample();
        }

        void Start()
        {
    
    
            RegisterNativeCallback("Log", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackLog)));
            RegisterNativeCallback("BeginSample", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackBeginSample)));
            RegisterNativeCallback("EndSample", Marshal.GetFunctionPointerForDelegate(new NativeCallback(CallbackEndSample)));
        }

        private void Update()
        {
    
    
            UpdateNative();
        }
    }
}

If you just look at the time-consuming C++ code, unity provides a C++ interface, which is more convenient, and the video is introduced at the end.
Unity official manual

//使用这两个原生接口,需要在C++项目属性配置:VC++目录->包含目录 或 C/C++->常规->附加包含目录,添加Unity这两个文件的文件路径
#include <IUnityInterface.h>
#include <IUnityProfiler.h>

static IUnityProfiler* s_UnityProfiler = NULL;
static const UnityProfilerMarkerDesc* s_MyPluginMarker = NULL;
static bool s_IsDevelopmentBuild = false;

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces * unityInterfaces)
{
    
    
	s_UnityProfiler = unityInterfaces->Get<IUnityProfiler>();
	if (s_UnityProfiler == NULL)
		return;
	s_IsDevelopmentBuild = s_UnityProfiler->IsAvailable() != 0;
	s_UnityProfiler->CreateMarker(&s_MyPluginMarker, "MyCustomMethod", kUnityProfilerCategoryOther, kUnityProfilerMarkerFlagDefault, 0);
}

extern "C"  void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
    
    
	s_UnityProfiler = NULL;
}

extern "C" void UNITY_INTERFACE_EXPORT InterfaceUpdate()
{
    
    
	if (s_IsDevelopmentBuild)
	{
    
    
		s_UnityProfiler->BeginSample(s_MyPluginMarker);
	}

	//测试耗时代码
	for (int i = 0; i < 100000; i++)
	{
    
    

	}

	if (s_IsDevelopmentBuild)
	{
    
    
		s_UnityProfiler->EndSample(s_MyPluginMarker);
	}
}

About the test of IL2CPP packaging:
1. Build directly through Unity, the structure is as follows: as follows: size 313M
insert image description here
2. By creating a VS solution (you can set breakpoints in VS, modify and debug C++ code), build in VS, and build in the interface Settings:
insert image description here
The structure is as follows: the bin directory contains the data directory of the software, and the specific generated exe is under their respective platforms:
insert image description hereinsert image description here

insert image description here
Finally, put the data folder of the bin directory and the exe of the corresponding platform together, as follows:
insert image description here
lib, pdb, and exp above the size of 162M can be deleted, and the test does not affect the operation. The simplified directory: size of 50.8M
insert image description here
Conclusion: the volume built with vs smaller.

Guess you like

Origin blog.csdn.net/weixin_41155760/article/details/128786825