将字节数组从c 不受管理的dll传递到c#unity

Passing byte array from C++ unmanaged dll to C# unity

本文关键字:dll c#unity 管理 字节数 字节 数组      更新时间:2023-10-16

我试图将字节数组从未管理的C DLL返回到C#Unity。非常感谢您花时间帮助><我真的是Unity的DLL新手,所以我非常困惑两种语言如何一起工作。

cpp

问题在这里,我已经完成了我的计算,但是我正在努力寻找一种以数组格式返回C#的方法。

当前,字节阵列持有颜色代码,例如RGBA(223,124,23,255,212,12,143,234,255(,并重复

#include "WebcamDLL.h"
#include <vector>
extern "C" {
int adjustBrightnesss(unsigned char* bytes, int sizeOfArray)
{
    std::vector<int> myvector;
    int alphaP = 0;
    for (int i = 0; i < sizeOfArray; i++) {
        switch (alphaP) {
        case 0:
        case 1:
        case 2:
            myvector[i] = bytes[i] / 2;
            alphaP++;
            break;
        case 3:
            alphaP = 0;
            break;
        }
    }
    return bytes;
}
}

标题文件

#ifdef TESTFUNCDLL_EXPORT
#define TESTFUNCDLL_API __declspec(dllexport) 
#else
#define TESTFUNCDLL_API __declspec(dllimport) 
#endif
extern "C" {
    TESTFUNCDLL_API int adjustBrightnesss(unsigned char* bytes, int sizeOfArray);
}

C#文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices; // Needed for custom DLL
using System;
public class WebcamManager : MonoBehaviour
{
    private RawImage ri; // Gets the RawImage component from script parent
    private WebCamTexture wct; // Object to hold the WebCamTexture add-on
    private AspectRatioFitter arf; // Ensures RawImage object has same scaling as Webcam
    private Color32[] pixels; // Keeps the pixels from webcamtexture
    Texture2D tex; // A placeholder for the texture2D
    [DllImport("WebcamBrightness", EntryPoint = "adjustBrightness")]
    public static extern int adjustBrightness(byte bytes, int b);
    void Start()
    {
        newBrightness = 1; // Default 1, if 0 will make image go super bright
        arf = GetComponent<AspectRatioFitter>(); // Gets the component AspectRatioFitter in script parent
        ri = GetComponent<RawImage>(); // Gets the component RawImage in script parent
        wct = new WebCamTexture(Screen.width, Screen.height); // Creates a new WebCamTexture in wct with the width and height of the current screen
        wct.Play(); // plays webcam
        //adjustBrightness(wct.GetPixels32());
    }
    // Update is called once per frame
    void Update()
    {
        float videoRatio = (float)wct.width / (float)wct.height; // Ensures that the scaling is the same as the webcam
        arf.aspectRatio = videoRatio; // applies webcam scaling to rawimage
        tex = new Texture2D(wct.width, wct.height, TextureFormat.ARGB32, false); // pass texture2D tex the information of webcamtexture height, width, ARGB32 (32 bit with alpha) and no mipmaps
        pixels = wct.GetPixels32();
// After getting the bytes, I wanna save it back to color32 or atleast an array format.
        tex.SetPixels32(pixels);
        tex.Apply();
        // Sets texture of rawimage from canvas to be web camera view
        ri.texture = tex;
    }
}

编辑的CPP文件

#include "WebcamDLL.h"
#include <vector>
extern "C" {
    unsigned char* adjustBrightness(unsigned char* bytes, int sizeOfArray)
    {
        int alphaP = 0;
        for (int i = 0; i < sizeOfArray; i++) {
            switch (alphaP) {
            case 0:
            case 1:
            case 2:
                bytes[i] = bytes[i] / 2;
                alphaP++;
                break;
            case 3:
                alphaP = 0;
                break;
            }
        }
        return bytes;
    }
    int freeMem(unsigned char* arrayPtr) {
        delete[] arrayPtr;
        return 0;
    }
}

编辑的标头文件

#ifdef TESTFUNCDLL_EXPORT
#define TESTFUNCDLL_API __declspec(dllexport) 
#else
#define TESTFUNCDLL_API __declspec(dllimport) 
#endif
extern "C" {
    TESTFUNCDLL_API unsigned char* adjustBrightness(unsigned char* bytes, int sizeOfArray);
    TESTFUNCDLL_API int freeMem(unsigned char* arrayPtr);
}

编辑C#文件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices; // Needed for custom DLL
using System;
public class WebcamManager : MonoBehaviour
{
    private RawImage ri; // Gets the RawImage component from script parent
    private WebCamTexture wct; // Object to hold the WebCamTexture add-on
    private AspectRatioFitter arf; // Ensures RawImage object has same scaling as Webcam
    private Color32[] pixels; // Keeps the pixels from webcamtexture
    Texture2D tex; // A placeholder for the texture2D
    public RawImage ri2;
    float timer;
    [DllImport("WebcamBrightness", EntryPoint = "adjustBrightness", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr adjustBrightness(byte[] bytes, int b);
    [DllImport("WebcamBrightness", EntryPoint = "freeMem", CallingConvention = CallingConvention.Cdecl)]
    public static extern int freeMem(IntPtr ptr);
    [SerializeField]
    int newBrightness;
    void Start()
    {
        newBrightness = 1; // Default 1, if 0 will make image go super bright
        arf = GetComponent<AspectRatioFitter>(); // Gets the component AspectRatioFitter in script parent
        ri = GetComponent<RawImage>(); // Gets the component RawImage in script parent
        wct = new WebCamTexture(Screen.width, Screen.height); // Creates a new WebCamTexture in wct with the width and height of the current screen
        wct.Play(); // plays webcam
        float videoRatio = (float)wct.width / (float)wct.height; // Ensures that the scaling is the same as the webcam
        arf.aspectRatio = videoRatio; // applies webcam scaling to rawimage
        tex = new Texture2D(wct.width, wct.height, TextureFormat.ARGB32, false); // pass texture2D tex the information of webcamtexture height, width, ARGB32 (32 bit with alpha) and no mipmaps
    }
    // Update is called once per frame
    void Update()
    {
        //timer += Time.deltaTime;
        pixels = wct.GetPixels32();
        IntPtr returnedPtr = adjustBrightness(Color32ArrayToByteArray(pixels), Color32ArrayToByteArray(pixels).Length);
        byte[] returnedResult = new byte[Color32ArrayToByteArray(pixels).Length];
        Marshal.Copy(returnedPtr, returnedResult, 0, Color32ArrayToByteArray(pixels).Length);
        freeMem(returnedPtr);
        Debug.Log(returnedResult[0]);
        tex.SetPixels32(pixels);
        ri.texture = tex;
        tex.Apply();
        // Sets texture of rawimage from canvas to be web camera view
    }
    public void AdjustBrightness(float b)
    {
        newBrightness = (int)b;
    }
    private static byte[] Color32ArrayToByteArray(Color32[] colors)
    {
        if (colors == null || colors.Length == 0)
            return null;
        int lengthOfColor32 = Marshal.SizeOf(typeof(Color32));
        int length = lengthOfColor32 * colors.Length;
        byte[] bytes = new byte[length];
        GCHandle handle = default(GCHandle);
        try
        {
            handle = GCHandle.Alloc(colors, GCHandleType.Pinned);
            IntPtr ptr = handle.AddrOfPinnedObject();
            Marshal.Copy(ptr, bytes, 0, length);
        }
        finally
        {
            if (handle != default(GCHandle))
                handle.Free();
        }
        return bytes;
    }
}

有很多方法可以从c#返回字节数组,而下面是其中之一。内存分配和脱位均在C 中完成。您必须调用该功能以使内存从C#释放。我使示例非常简单,以便您可以轻松地将其集成到当前的代码中。

IntPtr是此答案的关键。

C

char* getByteArray() 
{
    //Create your array(Allocate memory)
    char * arrayTest = new char[2];
    //Do something to the Array
    arrayTest[0]=3;
    arrayTest[1]=5;
    //Return it
    return arrayTest;
}

int freeMem(char* arrayPtr){
    delete[] arrayPtr;
    return 0;
}

c#

[DllImport("Test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr getByteArray();
[DllImport("Test.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int freeMem(IntPtr ptr);
//Test
void Start() {
 //Call and return the pointer
 IntPtr returnedPtr = getIntArray();
 //Create new Variable to Store the result
 byte[] returnedResult = new byte[2];
 //Copy from result pointer to the C# variable
 Marshal.Copy(returnedPtr, returnedResult, 0, 2);
 //Free native memory
 freeMem(returnedPtr);
 //The returned value is saved in the returnedResult variable
 byte val1 = returnedResult[0];
 byte val2 = returnedResult[1];
}

您可以将一个额外的参数传递给该函数,假设另一个字节数组,然后在Adjustbrightness函数中用该数组替换MyVector。据我所知,您将获得带有修改值的数组