You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中C#与C++ DLL交互时字节数组及长度传递异常问题

Unity C# 与 C++ DLL 交互问题解决方案

核心问题定位

你的代码存在函数签名完全不匹配的致命问题:

  • C# 声明MyCppFunction返回byte[],但C++实现返回cv::Mat,两者的内存布局、返回机制完全不同,直接破坏了调用栈结构,导致messageSize参数被错误解析,出现长度值偏大的情况。
  • 此外,C#与C++的参数传递逻辑也需要对齐,避免内存解析错误。

步骤1:修复输入参数传递问题

修正后的C#代码

using System.Runtime.InteropServices;
using UnityEngine;

void OnMessageReceived(CommsMessage message) {
    byte[] frameDataByteArray = message.payload.ToByteArray();
    int frameDataLength = frameDataByteArray.Length;
    Debug.Log("Frame length in C# is: " + frameDataLength);

    // 初始化输出参数
    IntPtr outputPtr = IntPtr.Zero;
    int outputLength = 0;
    // 调用修正后的C++函数
    MyCppFunction(frameDataByteArray, frameDataLength, ref outputPtr, ref outputLength);

    // 后续处理返回的byte数组(见步骤2)
}

[DllImport("utility", CallingConvention = CallingConvention.Cdecl)]
// 调整签名:输入用byte数组+长度,输出用指针和长度的引用传递
public static extern void MyCppFunction(
    [In] byte[] inputData, 
    int inputSize,
    ref IntPtr outputData,
    ref int outputSize
);

修正后的C++代码

#include <opencv2/opencv.hpp>
#include <cstdlib>
#include <cstring>

// 必须加extern "C"避免C++名字混淆,同时显式指定__cdecl调用约定
extern "C" __cdecl void MyCppFunction(const unsigned char* inputData, int inputSize, unsigned char** outputData, int* outputSize) {
    std::cerr << "Received message size in C++: " << inputSize << std::endl;

    // 示例:将输入byte数组转为cv::Mat(根据你的实际数据格式调整构造逻辑)
    cv::Mat inputMat = cv::Mat(/* 替换为你的Mat尺寸/类型 */, inputData);

    // 业务处理逻辑...

    // 准备输出数据:分配内存并拷贝
    *outputSize = inputMat.total() * inputMat.elemSize();
    // 用malloc分配内存,方便C#端用Marshal.FreeHGlobal释放
    *outputData = (unsigned char*)malloc(*outputSize);
    memcpy(*outputData, inputMat.data, *outputSize);
}

步骤2:实现C++向C#返回byte数组

在C#中,需要将C++分配的指针转为byte数组,并手动释放内存避免泄漏:

// 在调用MyCppFunction后添加以下代码:
if (outputPtr != IntPtr.Zero && outputLength > 0) {
    byte[] outputByteArray = new byte[outputLength];
    Marshal.Copy(outputPtr, outputByteArray, 0, outputLength);
    // 必须释放C++中malloc的内存
    Marshal.FreeHGlobal(outputPtr);

    // 处理outputByteArray的业务逻辑...
}

关键注意事项

  • 调用约定一致性:C#指定CallingConvention.Cdecl,C必须显式声明__cdecl(MSVC默认是stdcall,会导致栈错误),同时用extern "C"避免C名字混淆。
  • 数据类型对齐:C#的int对应C++的int(32位,x86/x64平台一致),不要混用long或其他类型。
  • 内存管理规则:C用malloc分配的内存,必须在C#中用Marshal.FreeHGlobal释放;如果用new分配,需在C中提供专门的释放函数供C#调用。
  • 字节序问题:x86/x64平台都是小端字节序,你的问题核心不是字节序,而是函数签名不匹配导致的栈破坏,无需优先处理字节序。

验证流程

  1. 先修复函数签名,验证C++端打印的inputSize是否和C#端的frameDataLength一致;
  2. 对比输入数组的前几个字节值,确认C++收到的inputData正确;
  3. 测试返回数组的长度和内容,确保数据完整无损坏。

内容的提问来源于stack exchange,提问作者Lucas B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:30:57