为什么在编组之后,数组中只有一个元素包含值
Why after marshalling, just one element of the array contains a value?
我正在从我的c#代码调用c++函数。我正在使用编组,但是当从c++代码返回时,在我的c#代码中只有一个元素填充了这个数组。
我的c++结构体:
typedef struct DEV_SUB_STATE_ITEM_s
{
char err_text[NAME_MAX_LENGTH];
uint32_t state;
char obj_name[NAME_MAX_LENGTH];
char name[NAME_MAX_LENGTH];
} DEV_SUB_STATE_ITEM_t;
我的c#结构:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DEVICE_Sub_State_Item
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public String err_text;
public UInt32 state;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public String obj_name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public String name;
}
我的c++函数原型:
int COMSpClient::GetSubSlotList (UINT32 obj_rid, DEV_SUB_STATE_ITEM_t** subSlotItems);
我的c#函数原型:
[DllImport(@"xxx_OMSpClient.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?OMSpClient_GetSubSlotList@@YAHPAXHPAPAUDEV_SUB_STATE_ITEM_s@@@Z", CharSet = CharSet.Auto)]
public static unsafe extern Int32 GetSubSlotList(Int32 p_hHandle, UInt32 obj_rid,[MarshalAs(UnmanagedType.LPArray)] ref DEVICE_Sub_State_Item[] sub_slot_items);
在c#中的用法:
OMSpClientWrapper.DEVICE_Sub_State_Item[] sub_slots = new OMSpClientWrapper.DEVICE_Sub_State_Item[5];
// TODO : load subordinate list!!!
OMSpClientWrapper.GetSubSlotList(this.omsp_client_handle, MyDevice.DeviceRID, ref sub_slots);
这是一个有点笨拙的封送函数。非托管代码分配数组并将指向该数组的指针返回给调用方。因此在签名中使用双指针。您不能使用p/invoke自动封送。
您将需要使用IntPtr
,作为out
参数传递,然后自己执行其余的封送。
[DllImport(...)]
public static extern int GetSubSlotList(
IntPtr p_hHandle,
uint obj_rid,
out IntPtr sub_slot_items
);
此时,sub_slot_items
指向数组的第一个元素。然后,您需要使用Marshal.PtrToStructure
来读出每一项,并在读取过程中增加点。
并且您可能需要回调非托管代码以要求它释放内存。
当然,这很乱。如果您可以控制接口,那么更好的设计是让调用者分配数组。代码看起来像这样:
int COMSpClient::GetSubSlotList(
UINT32 obj_rid,
DEV_SUB_STATE_ITEM_t subSlotItems[]
);
你也可能希望传递数组的长度,除非有其他原因使它为双方都知道。
在c#方面,代码将是:
[DllImport(...)]
public static extern int GetSubSlotList(
IntPtr p_hHandle,
uint obj_rid,
[Out] DEVICE_Sub_State_Item[] sub_slot_items
);
编组到字符串比它最初看起来要烦人得多。将字符串封送到固定字节缓冲区中可能更容易,然后像这样构造字符串:
public unsafe struct DEVICE_Sub_State_Item
{
public fixed byte err_text[50];
public UInt32 state;
public fixed byte obj_name[50];
public fixed byte name[50];
public string ErrorText
{
get
{
byte[] buffer = new byte[50];
fixed (byte* b = err_text)
Marshal.Copy(new IntPtr(b), buffer, 0, buffer.Length);
return Encoding.UTF8.GetString(buffer);
}
}
}
实际的错误文本将作为结构体中的指针保存,只有在调用其ErrorText
属性时才能正确读取并转换为字符串。
如果您决定这样做,您将需要在项目的构建选项下启用不安全代码。
相关文章:
- lower_bound()返回最后一个元素
- 有一个打印语句的函数是一种糟糕的编程实践吗
- VSCode-有一个红色下划线,但程序构建和运行正确,并且出现配音错误
- 是否有一个 std::set 函数来确定不超过数字 x 的最大元素?
- 除了 std::vector 之外,是否有一个 std 容器不会复制和销毁作为类的元素?
- 我有一个嵌套数组,它由另一个数组中的元素组成,这些元素分组为2.之后,我想显示每个元素的属性
- 这种获取模板参数包中最后一个元素的方法是否有隐藏的开销?
- 如果我有一个指向矢量元素的指针,而不是迭代器,如何删除它?
- 为什么只有在向量中已经有一个元素时才调用移动构造函数?
- 我有一个包含几个重复元素的数组,我想找到最接近数组末尾的重复元素的索引
- 如何在C中获取char阵列的第一个X元素?提升效果是否有改进的方法
- 是否可以有一个带有模板元素的类成员数组
- 我需要一个 std 函数来检查有多少元素在向量中恰好出现一次
- 是否有一个标准容器允许在不使迭代器无效的情况下插入元素
- 在std::multiset中,如果找到一个元素,有一个函数或算法可以只擦除一个样本(单播或重复)
- 从Cocos2d::Layer派生的类有一个指针数据成员.这个元素也有一个向量容器.调用vector::push_bac
- 我有一个类的数组,我想访问它的元素
- 如何在Qt Creator 5.7中制作一个只有一个窗口的c++ GUI程序,但每次点击都会使窗口有其他元素-如设置向导
- 我有一个STL向量的列表,我想按照每个向量的第一个元素对它们进行排序
- 找出两个范围(其中一个已排序)是否有一个公共元素