如何将 Byte* 从 C++ 转换为 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;
}
效果很好,但我不知道如何将指针转换为字节数组。有人知道这样做的功能吗?
函数接口的一个问题是函数动态分配给 return 旋转图像字节数组的内存必须使用 same 内存分配器分配C# 端(或任何客户端代码)将用于释放内存。
换句话说,分配内存的模块和释放内存的模块必须使用相同的分配器。
当我需要在本机代码和 C# 代码之间传递一些数组数据时,我成功地使用了 Safe Arrays。在C++端,可以使用ATL的CComSafeArray
到simplify the safe array programming;另一方面,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 编组器安全数组包含字节。
您可以使用如下简单的代码在 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);
我有一个 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;
}
效果很好,但我不知道如何将指针转换为字节数组。有人知道这样做的功能吗?
函数接口的一个问题是函数动态分配给 return 旋转图像字节数组的内存必须使用 same 内存分配器分配C# 端(或任何客户端代码)将用于释放内存。
换句话说,分配内存的模块和释放内存的模块必须使用相同的分配器。
当我需要在本机代码和 C# 代码之间传递一些数组数据时,我成功地使用了 Safe Arrays。在C++端,可以使用ATL的CComSafeArray
到simplify the safe array programming;另一方面,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 编组器安全数组包含字节。
您可以使用如下简单的代码在 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);