引子
需求是Unity的项目调用C++动态库的逻辑,并进行调试,这时就需要能够通过Log,观测C++动态库中的逻辑是否正常运行。 这个需求的底层逻辑其实就是,在C++中做一个“信息发送器”,C#中有一个“接收器”。在Log信息时,就是C++将Log内容,发送给C#,从而在Unity中显示出来。 该文章中的代码经过实际项目检测,可以直接使用。
C++部分
直接上代码:
头文件UnityDebug.hpp
#ifndef UnityDebug_hpp
#define UnityDebug_hpp
#include <stdio.h>
#include "string.h"
#define UnityLog(acStr, ...) Debug::L(acStr, ##__VA_ARGS__);
class Debug
{
public:
static void (*Log)(char* message, int iSize);
static void L(const char* msg, ...);
};
extern "C" void InitCSharpDelegate(void (*Log)(char* message, int iSize));
#endif
源文件UnityDebug.cpp
#include <stdarg.h>
#include "UnityDebug.hpp"
void (*Debug::Log)(char* message, int iSize);
void Debug::L(const char* fmt, ...)
{
if(Debug::Log == NULL)return;
char acLogStr[512];
va_list ap;
va_start(ap, fmt);
vsprintf(acLogStr, fmt, ap);
va_end(ap);
Debug::Log(acLogStr, strlen(acLogStr));
}
void InitCSharpDelegate(void(*Log)(char* message, int iSize))
{
Debug::Log = Log;
UnityLog("Cpp Message:Log has initialized");
}
C++中的使用
创建完以上两个文件后,在需要Log的地方,调用UnityLog("*****"); 即可。具体用法与printd() 函数一样。
Unity的C#代码
using AOT;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class DllLog
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LogDelegate(IntPtr message, int iSize);
[DllImport("macVTA", CallingConvention = CallingConvention.Cdecl)]
public static extern void InitCSharpDelegate(LogDelegate log);
[MonoPInvokeCallback(typeof(LogDelegate))]
public static void LogMessageFromCpp(IntPtr message, int iSize)
{
Debug.Log(Marshal.PtrToStringAnsi(message, iSize));
}
public static void ShowLog()
{
InitCSharpDelegate(LogMessageFromCpp);
}
}
Unity端的使用
在程序运行的一开始调用一次ShowLog(); 即可,这样C++中的所有Log都会在相应的程序位置显示在Unity控制台中。
逻辑原理
将C++与C#的代码都写好,并测试成功后,再来对照着看一下其中的逻辑原理。
- 首先,在C++中调用的
UnityLog("*****"); ,通过头文件(UnityDebug.hpp)可以知道,它其实就是类Debug 的L 函数(Debug::L ); - 该函数方法的实现,就是将参数进行了一些转换/合并,最后传入了函数指针
Debug::Log ; - 而函数指针
Debug::Log ,则是在经过关键字extern "C" 声明后的外部函数方法void InitCSharpDelegate(void (*Log)(char* message, int iSize)); 的实现中进行了“赋值”; InitCSharpDelegate 作为外部方法,对应了C#代码中被声明的public static extern void InitCSharpDelegate(LogDelegate log); ,其中的参数LogDelegate ,则是对应了C++代码中的static void (*Log)(char* message, int iSize); 函数指针的public delegate void LogDelegate(IntPtr message, int iSize); 委托;- Unity的C#代码调用的
ShowLog(); ,就是将函数LogMessageFromCpp 作为委托(或函数指针)传入了外部方法(extern 关键字)InitCSharpDelegate 中; - 这样在C++程序调用
UnityLog 方法时,其实就是将信息进行转化/合并后,传入了委托/函数指针LogMessageFromCpp 中,从而显示在了Unity控制台上。
参考链接
https://blog.csdn.net/heima201907/article/details/106349104
|