- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我未能定义正确的 C# 代码来与 C++ 库一起工作,该库定义了一个具有 union 和数组的复杂结构,我在执行 C++ 代码时不断遇到一些内存异常,我很确定这是由于这个原因造成的。
C++ 结构如下,忽略枚举和其他结构定义(如果需要我会发布它们,但它们非常广泛)
typedef struct
{
DG_CCTALK_APP_EVT_CODE eEventCode;
DG_CCTALK_APP_EVT_TYPE eEventType;
int iTime;
int iHandle;
unsigned char uchAddress;
DG_CCTALK_BILL_INFO sBillInfo;
int iBillAmount;
union
{
long lData;
int iData;
unsigned char ucArray[128];
char *cString;
void *pvoid;
} uData;
void *_private; // for use by cctalk app layer
} DG_CCTALK_APP_EVT, *PDG_CCTALK_APP_EVT;
C# 代码是这样的:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
public struct Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40
{
//deberian llevar todos 0, pero el array genera problemas al ponerle 0, y cambiandolo explota en otro lado...
/// int
[System.Runtime.InteropServices.FieldOffsetAttribute(0)]
public int lData;
/// int
[System.Runtime.InteropServices.FieldOffsetAttribute(0)]
public int iData;
/// unsigned char[128]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 128, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I1)]
[System.Runtime.InteropServices.FieldOffsetAttribute(4)]
public byte[] ucArray;
/// char*
[System.Runtime.InteropServices.FieldOffsetAttribute(0)]
public System.IntPtr cString;
/// void*
[System.Runtime.InteropServices.FieldOffsetAttribute(0)]
public System.IntPtr pvoid;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct DG_CCTALK_APP_EVT
{
/// DG_CCTALK_APP_EVT_CODE->_DG_CCTALK_APP_EVT_CODE
public DG_CCTALK_APP_EVT_CODE eEventCode;
/// DG_CCTALK_APP_EVT_TYPE->_DG_CCTALK_APP_EVT_TYPE
public DG_CCTALK_APP_EVT_TYPE eEventType;
/// int
public int iTime;
/// int
public int iHandle;
/// unsigned char
public byte uchAddress;
/// DG_CCTALK_BILL_INFO->_DG_CCTALK_BILL_INFO
public DG_CCTALK_BILL_INFO sBillInfo;
/// int
public int iBillAmount;
/// Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40
public Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40 uData;
/// void*
public System.IntPtr _private;
}
委托(delegate)和函数导入
public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);
[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_enable_device", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_enable_device(ref DG_CCTALK_APP_EVT param0);
更新:回答后的新代码,仍然无法正常工作:错误是:“尝试读取或写入 protected 内存这通常表明其他内存已损坏”
奇怪的是,我可以在第一次事件调用时使用该结构,我打印所有字段并且它们似乎是正确的(lData 和 iData 具有相同的值,cData 具有我发送的字符串)但是在事件之后结束程序死亡。好像我的 C# 代码破坏了结构或其他东西......
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct DG_CCTALK_APP_EVT
{
/// DG_CCTALK_APP_EVT_CODE->_DG_CCTALK_APP_EVT_CODE
public DG_CCTALK_APP_EVT_CODE eEventCode;
/// DG_CCTALK_APP_EVT_TYPE->_DG_CCTALK_APP_EVT_TYPE
public DG_CCTALK_APP_EVT_TYPE eEventType;
/// int
public int iTime;
/// int
public int iHandle;
/// unsigned char
public byte uchAddress;
/// DG_CCTALK_BILL_INFO->_DG_CCTALK_BILL_INFO
public DG_CCTALK_BILL_INFO sBillInfo;
/// int
public int iBillAmount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] uData;
#region setters y getters para mapeo
public int lData
{
set
{
Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
}
get
{
return BitConverter.ToInt32(uData, 0);
}
}
public int iData
{
set
{
Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
}
get
{
return BitConverter.ToInt32(uData, 0);
}
}
public byte[] ucArray
{
set
{
Array.Copy(value, uData, 128);
}
get
{
return uData;
}
}
public IntPtr cString
{
set
{
Array.Copy(BitConverter.GetBytes(value.ToInt32()), uData, 32);
}
get
{
return (IntPtr)BitConverter.ToInt32(uData, 0);
}
}
public IntPtr pvoid
{
set
{
Array.Copy(BitConverter.GetBytes(value.ToInt32()), uData, 32);
}
get
{
return (IntPtr)BitConverter.ToInt32(uData, 0);
}
}
#endregion
/// void*
public System.IntPtr _private;
}
C++ 声明:
typedef void (*DG_CCTALK_APP_EVT_HANDLER)(PDG_CCTALK_APP_EVT pEVT);
DGCCTALK_PREFIX DG_ERROR cctalk_app_init(DG_CCTALK_APP_EVT_HANDLER pfnHandler);
DGCCTALK_PREFIX DG_ERROR cctalk_app_add_link(char *szPortName);
注意爸爸 DGCCTALK_PREFIX 定义为 __declspec(dllexport)
那些的C#代码:
public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);
[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_init", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_init(DG_CCTALK_APP_EVT_HANDLER pfnHandler);
[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_add_link", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_add_link(System.IntPtr szPortName);
调用它们的 C# 代码
var handler = new DG_CCTALK_APP_EVT_HANDLER(this._handler);
var resultado = cctalk_app_init(handler);
cctalk_app_add_link(Marshal.StringToHGlobalAnsi("port=" + port));
C# 处理程序 header
private void _handler(ref DG_CCTALK_APP_EVT pEVT)
最佳答案
正如您所发现的,编码(marshal)拆收器不喜欢您在 union 转换中尝试将数组与其他字段叠加。您通过将数组的偏移量更改为 4 而不是 0 来抑制问题。但这没有帮助。
现在,由于编码(marshal)拆收器不会为您处理 union ,您必须手动进行。我会通过省略 union 的非数组成员来处理这个问题。
[StructLayout(LayoutKind.Sequential)]
public struct DG_CCTALK_APP_EVT
{
public DG_CCTALK_APP_EVT_CODE eEventCode;
public DG_CCTALK_APP_EVT_TYPE eEventType;
public int iTime;
public int iHandle;
public byte uchAddress;
public DG_CCTALK_BILL_INFO sBillInfo;
public int iBillAmount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] uData;
public IntPtr _private;
}
请注意,我已经删除了您声明中的大部分冗长内容。我怀疑该类型是由工具自动生成的。但是所有这些冗长的内容使其很难阅读。
这将为结构生成正确的布局,但会让您需要做一些工作才能访问 union 中的其他字段。
那么,我们如何读取这些字段呢?好吧,数据包含在字节数组 uData
中,因此只需从那里读取值即可。例如,您可以将以下属性添加到 DG_CCTALK_APP_EVT
结构中:
public int lData
{
get { return BitConverter.ToInt32(uData, 0); }
set { uData = BitConverter.GetBytes(value); }
}
public int iData
{
get { return BitConverter.ToInt32(uData, 0); }
set { uData = BitConverter.GetBytes(value); }
}
// etc.
请注意,setter 将删除数组的前 4 个字节以外的所有字节,因为它会覆盖 uData
。我对 native 代码的协议(protocol)知之甚少,无法确定这就是您想要的。如果这不是您想要的,那么您可以这样编写 setter:
Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
您现在已经添加了互操作边界的 C++ 端。最明显的问题是您的 C# 委托(delegate)似乎有错误的调用约定。它使用 stdcall
但 C++ 代码需要 cdecl
。这当然足以解释回调返回后的灾难性崩溃。您需要确保您的委托(delegate)指定了调用约定。
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);
你对cctalk_app_add_link
的翻译也是错误的。应该是:
[DllImport("cctalk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_add_link(string szPortName);
这样做你可以简单地传递一个字符串,从而避免你当前实现的内存泄漏。
关于C# pinvoke 具有 union 和数组的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20274284/
自从我的问题here无法自信地回答,我在这里再次询问,希望有人确切知道: 指向 union 的指针和包含指向其元素的指针的 union 之间有什么区别(除了语法之外)吗? this中生成的程序集示例是
在 C 语言中,是否可以在另一个 union 体中定义一个 union 体?如果不是,为什么不可能?或者如果可以,可以在哪里使用? 最佳答案 假设您要定义: union myun { int x;
在 C 中,是否可以在另一个 union 中定义一个 union ?如果不是,为什么不可能?或者如果是,它可以在哪里使用? 最佳答案 假设你想定义: union myun { int x; s
我正在阅读一些代码并发现如下内容: typedef union { int int32; int boolean; time_t date; char *string;
我正在学习Lua,我更愿意使用冒号(:)作为方法。不幸的是,它并非在所有地方都有效。看我的代码: 设置= {} 本地mt = {} 函数Set:new(m) 本地集= {} setmetatable(
我遇到了一些性能问题,我有如下查询: SELECT * FROM Foo UNION SELECT * FROM Boo UNION SELECT * FROM Koo 我确信 Koo 不会返回任何重
This question already has answers here: C++ Structure Initialization (16个答案) 上个月关闭。 我正在尝试将一些用于嵌入式目标的
UNION 和 UNION ALL 有什么区别? 最佳答案 UNION 删除重复记录(结果中的所有列都相同),UNION ALL 则不会。 使用 UNION 而不是 UNION ALL 时会影响性能,
我想在两个表上使用联合运算符。我希望结果集消除由联合创建的重复值,但不消除表中预先存在的重复值。考虑这段代码... select b from (values (1), (2), (2
我知道 UNION 会删除重复项,但即使没有重复项也会更改结果顺序。 我有两个 select 语句,任何地方都没有 order by 语句 我想将它们合并或不合并(全部) 即 SELECT A UNI
基本上,我有一个 struct foo { /* variable denoting active member of union */ enum whichmembe
我有一个大规模查询,用于对许多表(每个表有数千行)执行 UNION ALL,然后在返回之前输出到临时表。 旧形式: SELECT * FROM (SELECT `a` AS `Human rea
UNION 和 UNION ALL 有什么区别? 最佳答案 UNION 删除重复记录(结果中的所有列都相同),UNION ALL 则不会。 使用 UNION 而不是 UNION ALL 时会影响性能,
如果我有两个 union 行结构: struct A { A() {} ~A() {} union { vector vi; vector db
考虑下面的代码,我已经写了: #include #include union myAccess { uint16_t access16; struct { uint
我想弄清楚你从 C99 中对齐变量的地役权中得到了什么: Exception to strict aliasing rule in C from 6.5.2.3 Structure and union
我正在通过 UNION 或 UNION ALL 从多个表中选择一列外键。 当重复无关紧要时,通常建议使用 UNION ALL 而不是 UNION 来解决性能问题。但是,在我的调用 PHP 脚本中,循环
在 C++ 中,union 可以包含静态成员,在类的情况下,这些成员属于一个类,因此对所有对象都是通用的。 union U { long l; int i; static long
任何人都可以提及普通和匿名 union (或结构)之间的区别吗?我刚找到一个: 不能在匿名 union 中定义函数。 最佳答案 您不需要点运算符“.”访问匿名 union 元素。 #include
我可能把这个复杂化了.. 我正在尝试在 Arduino 上用 C 语言为嵌入式应用程序制作一个相当可重用的分层菜单系统。我有结构来表示不同类型的菜单项,包括那些子菜单,以及这些菜单项的 union 是
我是一名优秀的程序员,十分优秀!