繁体   English   中英

如何在C#中将Byte *从C ++转换为Byte []

[英]How to convert a Byte* from C++ to Byte[] in C#

我在C ++中有一个包含返回Byte *的库的库:

typedef unsigned char Byte;
Byte* RotateImage90(Byte* data, int w, int h);

我在C#(Xamarin)的程序中使用此库:

[DllImport("libCpp", EntryPoint = "RotateImage90")]
public static extern IntPtr rotate90(byte[] data, int w, int h);

Byte[] test(Byte[] data, int w, int h)
{
    IntPtr ptr = rotate90(data, w, h);
    Byte[] img = ????;// <= function missing
    return img;
}

它工作正常,但我不知道如何将指针转换为Byte数组。 有人知道这样做的功能吗?

函数接口的问题在于,函数动态分配的内存必须返回与C#端(或任何客户端代码)将用于释放内存的相同的内存分配器,以动态分配返回的旋转图像字节数组。

换句话说,分配内存的模块和释放内存的模块必须使用相同的分配器。

当我需要在本机代码和C#代码之间传递一些数组数据时,我成功使用了安全数组 在C ++方面,可以使用ATL的CComSafeArray 简化安全数组的编程 另一方面,C#和CLR非常了解安全数组,因此很容易在C#中获取数组数据并在托管代码中使用它们。

您可以使用如下函数在C ++中生成一个安全的字节数组(在您的情况下,该安全数组将存储旋转的图像数据):

extern "C" HRESULT __stdcall ProduceSafeArrayOfBytes(/* [out] */ SAFEARRAY** ppsa)
{
    HRESULT hr = S_OK;

    try
    { 
        // Create the safe array to be returned to the caller
        CComSafeArray<BYTE> sa( /* Element count */);

        // Fill the safe array data.
        // You can use a simple sa[i] syntax,
        // where 'i' is a 0-based index
        ...

        // Return the safe array to the caller (transfer ownership)
        *ppsa = sa.Detach();
    }
    // Convert exceptions to HRESULT return codes
    catch (const CAtlException& e)
    {
        hr = e;
    }
    catch (const std::exception& )
    { 
        hr = E_FAIL;
    }

    return hr;
}

在C#端,您可以使用以下PInvoke签名:

[DllImport("NativeDll.dll", PreserveSig = false)]
public static extern void ProduceSafeArrayOfBytes(
    [Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
    out byte[] result
);

VT_UI1枚举字段告诉.NET Marshaller安全数组包含字节。

您可以使用以下简单代码在C#中获取数组数据:

byte[] data;
ProduceSafeArrayOfBytes(out data);

如您所见,在C#代码中,您处理了一个简单的byte[]数组; 所有适当的数据编组(包括释放内存)都会在后台自动进行。

您可以修改上述框架代码,添加其他功能参数,例如图像的宽度和高度。


作为替代方案,另一种选择是使用C ++ / CLI开发微小的桥接层,以从原始C样式数组转换为.NET托管数组。

无论如何,在DLL函数接口上使用公用内存分配器分配和释放数组内存的注释仍然有效。


作为第三个选择,如果可以修改DLL函数接口,则可以要求调用方分配一个数组并将其传递给DLL函数。 该函数将结果数据写入此调用方分配的数组中

这将简化内存管理,因为您为DLL函数提供了调用方已经分配的内存块。 调用方将负责分配和释放该内存。

因此,您的DLL函数将如下所示:

extern "C" void __cdecl RotateImage90(Byte* result, Byte* data, int width, int height);

结果数组由调用方分配,调用方还负责释放它。 该函数只是将其输出写入此调用方分配的数组中。

PInvoke将如下所示:

[DllImport("NativeDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void RotateImage90(byte[] result, byte[] data, int width, int height);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM