如何编组此C ++类型?
ABS_DATA结构用于将任意长的数据块与长度信息相关联。 Data
数组的声明长度为1,但实际长度由Length
成员给出。
typedef struct abs_data {
ABS_DWORD Length;
ABS_BYTE Data[ABS_VARLEN];
} ABS_DATA;
我尝试了以下代码,但它无效。数据变量总是空的,我确定它中有数据。
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
public struct abs_data
{
/// ABS_DWORD->unsigned int
public uint Length;
/// ABS_BYTE[1]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 1)]
public string Data;
}
答案 0 :(得分:6)
不可能编组包含可变长度数组的结构(但 可能将可变长度数组编组为函数参数)。您必须手动读取数据:
IntPtr nativeData = ... ;
var length = Marshal.ReadUInt32 (nativeData) ;
var bytes = new byte[length] ;
Marshal.Copy (new IntPtr ((long)nativeData + 4), bytes, 0, length) ;
答案 1 :(得分:5)
如果保存的数据不是字符串,则不必将其存储在字符串中。除非原始数据类型是char*
,否则我通常不会编组为字符串。否则byte[]
应该这样做。
尝试:
[MarshalAs(UnmanagedType.ByValArray, SizeConst=[whatever your size is]]
byte[] Data;
如果您需要稍后将其转换为字符串,请使用:
System.Text.Encoding.UTF8.GetString(your byte array here).
显然,您需要根据需要改变编码,但UTF-8通常就足够了。
我现在看到问题,你必须编组一个VARIABLE长度数组。 MarshalAs不允许这样做,并且必须通过引用发送数组。
如果数组长度是可变的,那么byte[]
需要是一个IntPtr,所以你会使用,
IntPtr Data;
而不是
[MarshalAs(UnmanagedType.ByValArray, SizeConst=[whatever your size is]]
byte[] Data;
然后,您可以使用Marshal类访问基础数据。
类似的东西:
uint length = yourABSObject.Length;
byte[] buffer = new byte[length];
Marshal.Copy(buffer, 0, yourABSObject.Data, length);
你可能需要在完成后清理你的内存以避免泄漏,但我怀疑当你的SOSObject超出范围时GC会清理它。无论如何,这是清理代码:
Marshal.FreeHGlobal(yourABSObject.Data);
答案 2 :(得分:2)
你试图整理一些byte[ABS_VARLEN]
的东西,好像它是长度为1的string
。你需要弄清楚ABS_VARLEN常量是什么,并将数组编组为:< / p>
[MarshalAs(UnmanagedType.LPArray, SizeConst = 1024)]
public byte[] Data;
(1024有一个占位符;填写ASB_VARLEN的实际值。)
答案 3 :(得分:0)
在我看来,固定数组并获取其地址更简单,更有效。
假设您需要将abs_data
传递给myNativeFunction(abs_data*)
:
public struct abs_data
{
public uint Length;
public IntPtr Data;
}
[DllImport("myDll.dll")]
static extern void myNativeFunction(ref abs_data data);
void CallNativeFunc(byte[] data)
{
GCHandle pin = GCHandle.Alloc(data, GCHandleType.Pinned);
abs_data tmp;
tmp.Length = data.Length;
tmp.Data = pin.AddrOfPinnedObject();
myNativeFunction(ref tmp);
pin.Free();
}