public struct SASK //股票报价返回
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 603)]
public Ask[] m_ask; //股票报价
}
C#中,请问怎么将SizeConst 设置成动态变化的,就是封送给C++ dll是,这个结构体的m_ask这次可能是603,下次可能是600,下次可能是500.
SizeConst 好像是接收特性形参类型的常量表达式、typeof 表达式或数组创建表达式
有没有办法,望高手指导。
再不行换其他思路。
25 个解决方案
#1
除非在运行时动态编译代码,否则attrbute是不能更改的。
#2
用数组和指针就行了,那个成员定义成指针,指向一个动态分配的数组
#3
动态编译代码好像很烦啊,有没有其他思路能解决这个问题,我就是封送这个结构体给dll,但结构体里面的数组元素个数是不确定的。
#4
你直接传数组不就可以了,为什么要用结构体?
#5
2楼的用数组和指针,在C#怎么用,关键这个数组还要加上面那个属性啊,具体语法能不能给我举个例子
#6
这个结构体完整的应该是这样的
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK //股票报价返回
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 603)]
public Ask[] m_ask; //股票报价
public int m_a;
public byte m_b;
}
然后转成C#的IntPtr类型 对应那边是void *info C# void test(IntPtr info) C++ void test(void * info)
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK //股票报价返回
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 603)]
public Ask[] m_ask; //股票报价
public int m_a;
public byte m_b;
}
然后转成C#的IntPtr类型 对应那边是void *info C# void test(IntPtr info) C++ void test(void * info)
#7
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK //股票报价返回
{
public Ask* m_ask; //股票报价
public int m_a;
public byte m_b;
}
static void TestAsk()
{
SASK sa;
var askList = new List<Ask>();
//askList.add(xxxx);
var asks=askList.ToArray();
fixed (Ask* pask = asks)
{
sa.m_ask = pask;
//调用函数......
}
}
#8
soaringbird 高手,如果这个方法可行,请问结构体里面public Ask* m_ask; 这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了
#9
你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。
#10
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK //股票报价返回
{
public intptr
}
public struct SASK //股票报价返回
{
public intptr
}
#11
C++发送给服务器结构体: struct base
{
unsigned char a;
short b;
};
struct AA: public base
{
unsigned short c;
BB d[603];
};
struct BB
{
unsigned short e;
CC f;
};
struct CC
{
unsigned char g;
char h[10];
};
调用的接口函数 sendmsg(void *msg)
C++从服务器接收的结构体:
struct base
{
unsigned char a;
short b;
};
struct DD: public base
{
unsigned short o;
EE p[603];
};
struct EE
{
unsigned short q;
FF r;
};
struct FF
{
unsigned char s;
char t[10];
};
接收的话给的是内存地址,通过Marshal.PtrToStructure来转,问题关键是接收和发送的两大结构体里面有个类型数组,譬如现在我写的 603这个大小,翻译成C#应该就是我在1楼写的SizeConst = 603。
问题就是 这个603是动态的,可能下次发送的大小是500或400。在C++里面,可以把它设置成1,然后动态申请n*sizeof(BB)的空间,请问C#要怎么使它成动态的
#12
soaringbird 高手,如果这个方法可行,请问结构体里面public Ask* m_ask; 这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了
你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。
C++发送给服务器结构体: struct base
{
unsigned char a;
short b;
};
struct AA: public base
{
unsigned short c;
BB d[603];
};
struct BB
{
unsigned short e;
CC f;
};
struct CC
{
unsigned char g;
char h[10];
};
调用的接口函数 sendmsg(void *msg)
C++从服务器接收的结构体:
struct base
{
unsigned char a;
short b;
};
struct DD: public base
{
unsigned short o;
EE p[603];
};
struct EE
{
unsigned short q;
FF r;
};
struct FF
{
unsigned char s;
char t[10];
};
接收的话给的是内存地址,通过Marshal.PtrToStructure来转,问题关键是接收和发送的两大结构体里面有个类型数组,譬如现在我写的 603这个大小,翻译成C#应该就是我在1楼写的SizeConst = 603。
问题就是 这个603是动态的,可能下次发送的大小是500或400。在C++里面,可以把它设置成1,然后动态申请n*sizeof(BB)的空间,请问C#要怎么使它成动态的
先去了解一下在struct 里面数组如何存储的
#13
使用用数组和指针,把那个成员定义成指针,指向一个动态分配的数组应该就可以了
#14
使用用数组和指针,把那个成员定义成指针,指向一个动态分配的数组应该就可以了
能不能举一个例子啊,语法写上后有报错。
#15
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
这个在c++里是BB d[1]还是 BB*d ?
#16
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
#17
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
我怎么没见过这种用法,通常是用指针动态分配空间的
#18
#19
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
用intptr
传递的时候用Marshal.UnsafeAddrOfPinnedArrayElement
如果你能确定尺寸,也可以用Marshal.AllocHGlobal
#20
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
我怎么没见过这种用法,通常是用指针动态分配空间的
它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做
#21
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
用intptr
传递的时候用Marshal.UnsafeAddrOfPinnedArrayElement
如果你能确定尺寸,也可以用Marshal.AllocHGlobal
你的意思是写成这样?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK
{
public intptr m_ask;
public int m_a;
public byte m_b;
}
static void TestAsk()
{
SASK sa;
var askList = new List<Ask>();
//askList.add(xxxx);
var asks=askList.ToArray();
fixed (Ask* pask = asks)
{
sa.m_ask = pask;
//调用函数......
}
}
#22
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
我怎么没见过这种用法,通常是用指针动态分配空间的
它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做
难道是 BB d[1]; d=malloc(603*sizeof(BB)); 这样编译都过不了啊
#23
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
我怎么没见过这种用法,通常是用指针动态分配空间的
它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做
难道是 BB d[1]; d=malloc(603*sizeof(BB)); 这样编译都过不了啊
可以的,本来想贴出来,上次有个人qq发我的,一时找不到了,最终肯定是动态申请,malloc刚才我也有问题,是怎么个语法c++里有点不清楚了。
#24
struct AA
{
int size;
BB d[1];
};
在C++里面,之所有有BB d[1]这种写法,它表示至少有一个BB, 紧跟在一个size后面。因此在内存布局上,他们必须是 连续的。
struct Point
{
int X, Y;
};
struct PointList
{
int Length;
Point Points[1]; //<--
};
extern "C" _declspec(dllexport) Point Sum(PointList& pointList)
{
Point result = {};
for(int i = 0; i < pointList.Length; i++)
{
result.X += pointList.Points[i].X;
result.Y += pointList.Points[i].Y;
}
return result;
}
void Test()
{
PointList* ptr = (PointList*)malloc(4 + sizeof(Point) * 3);
ptr->Length = 3;
ptr->Points[0].X = 1;
ptr->Points[0].Y = 2;
ptr->Points[1].X = 11;
ptr->Points[1].Y = 22;
ptr->Points[2].X = 111;
ptr->Points[3].Y = 222;
// ptr指向的内存为: [3,1,2,11,22,111,222]
Point sum = Sum(*ptr); // sum.X=123, sum.Y=246
free(ptr);
}
对C#来说,带有的关键就是内存布局的兼容,你可以用IntPtr,也可以用byte[],但是,要提供一段连续的内存[3,1,2,11,22,111,222]。例子可以这样写:
private void button1_Click(object sender, EventArgs e)
{
Point[] points = new Point[]
{
new Point(1,2),
new Point(11,22),
new Point(111,222),
};
int int32InBytes = Marshal.SizeOf(typeof(int));
int arrayInBytes = Marshal.SizeOf(typeof(Point)) * points.Length;
// 写PointList.Length
byte[] buffer = new byte[int32InBytes + arrayInBytes];
BitConverter.GetBytes(points.Length).CopyTo(buffer, 0);
// 写PointList.Points
GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);
Marshal.Copy(gc.AddrOfPinnedObject(), buffer, 4, buffer.Length - 4);
gc.Free();
Point sum = Sum(buffer); // X=123, Y=246
}
[DllImport("xxx", CallingConvention = CallingConvention.Cdecl)]
extern static Point Sum(byte[] buffer);
#25
struct AA
{
int size;
BB d[1];
};
在C++里面,之所有有BB d[1]这种写法,它表示至少有一个BB, 紧跟在一个size后面。因此在内存布局上,他们必须是 连续的。
struct Point
{
int X, Y;
};
struct PointList
{
int Length;
Point Points[1]; //<--
};
extern "C" _declspec(dllexport) Point Sum(PointList& pointList)
{
Point result = {};
for(int i = 0; i < pointList.Length; i++)
{
result.X += pointList.Points[i].X;
result.Y += pointList.Points[i].Y;
}
return result;
}
void Test()
{
PointList* ptr = (PointList*)malloc(4 + sizeof(Point) * 3);
ptr->Length = 3;
ptr->Points[0].X = 1;
ptr->Points[0].Y = 2;
ptr->Points[1].X = 11;
ptr->Points[1].Y = 22;
ptr->Points[2].X = 111;
ptr->Points[3].Y = 222;
// ptr指向的内存为: [3,1,2,11,22,111,222]
Point sum = Sum(*ptr); // sum.X=123, sum.Y=246
free(ptr);
}
对C#来说,带有的关键就是内存布局的兼容,你可以用IntPtr,也可以用byte[],但是,要提供一段连续的内存[3,1,2,11,22,111,222]。例子可以这样写:
private void button1_Click(object sender, EventArgs e)
{
Point[] points = new Point[]
{
new Point(1,2),
new Point(11,22),
new Point(111,222),
};
int int32InBytes = Marshal.SizeOf(typeof(int));
int arrayInBytes = Marshal.SizeOf(typeof(Point)) * points.Length;
// 写PointList.Length
byte[] buffer = new byte[int32InBytes + arrayInBytes];
BitConverter.GetBytes(points.Length).CopyTo(buffer, 0);
// 写PointList.Points
GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);
Marshal.Copy(gc.AddrOfPinnedObject(), buffer, 4, buffer.Length - 4);
gc.Free();
Point sum = Sum(buffer); // X=123, Y=246
}
[DllImport("xxx", CallingConvention = CallingConvention.Cdecl)]
extern static Point Sum(byte[] buffer);
请问:
报了Object contains non-primitive or non-blittable data错误,在GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);这句话。
我的结构体在Point还有个自定义类型参数,是不是这个引起的, 没查出来,然后这个头还要不要写 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Point
{
int X, Y;
TT _t;
};
public struct TT
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string str;
}
#1
除非在运行时动态编译代码,否则attrbute是不能更改的。
#2
用数组和指针就行了,那个成员定义成指针,指向一个动态分配的数组
#3
动态编译代码好像很烦啊,有没有其他思路能解决这个问题,我就是封送这个结构体给dll,但结构体里面的数组元素个数是不确定的。
#4
你直接传数组不就可以了,为什么要用结构体?
#5
2楼的用数组和指针,在C#怎么用,关键这个数组还要加上面那个属性啊,具体语法能不能给我举个例子
#6
这个结构体完整的应该是这样的
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK //股票报价返回
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 603)]
public Ask[] m_ask; //股票报价
public int m_a;
public byte m_b;
}
然后转成C#的IntPtr类型 对应那边是void *info C# void test(IntPtr info) C++ void test(void * info)
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK //股票报价返回
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 603)]
public Ask[] m_ask; //股票报价
public int m_a;
public byte m_b;
}
然后转成C#的IntPtr类型 对应那边是void *info C# void test(IntPtr info) C++ void test(void * info)
#7
2楼的用数组和指针,在C#怎么用,关键这个数组还要加上面那个属性啊,具体语法能不能给我举个例子
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK //股票报价返回
{
public Ask* m_ask; //股票报价
public int m_a;
public byte m_b;
}
static void TestAsk()
{
SASK sa;
var askList = new List<Ask>();
//askList.add(xxxx);
var asks=askList.ToArray();
fixed (Ask* pask = asks)
{
sa.m_ask = pask;
//调用函数......
}
}
#8
soaringbird 高手,如果这个方法可行,请问结构体里面public Ask* m_ask; 这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了
#9
soaringbird 高手,如果这个方法可行,请问结构体里面public Ask* m_ask; 这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了
你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。
#10
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK //股票报价返回
{
public intptr
}
public struct SASK //股票报价返回
{
public intptr
}
#11
soaringbird 高手,如果这个方法可行,请问结构体里面public Ask* m_ask; 这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了
你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。
C++发送给服务器结构体: struct base
{
unsigned char a;
short b;
};
struct AA: public base
{
unsigned short c;
BB d[603];
};
struct BB
{
unsigned short e;
CC f;
};
struct CC
{
unsigned char g;
char h[10];
};
调用的接口函数 sendmsg(void *msg)
C++从服务器接收的结构体:
struct base
{
unsigned char a;
short b;
};
struct DD: public base
{
unsigned short o;
EE p[603];
};
struct EE
{
unsigned short q;
FF r;
};
struct FF
{
unsigned char s;
char t[10];
};
接收的话给的是内存地址,通过Marshal.PtrToStructure来转,问题关键是接收和发送的两大结构体里面有个类型数组,譬如现在我写的 603这个大小,翻译成C#应该就是我在1楼写的SizeConst = 603。
问题就是 这个603是动态的,可能下次发送的大小是500或400。在C++里面,可以把它设置成1,然后动态申请n*sizeof(BB)的空间,请问C#要怎么使它成动态的
#12
soaringbird 高手,如果这个方法可行,请问结构体里面public Ask* m_ask; 这句话如何表示, 定义m_ask指针类型 语法上报错,如果加unsafe 怎么加啊 谢谢了
你先把C++原型贴出来,确定一下怎么改写.
unsafe加在类、结构、方法的声明前面。在项目属性里还有一个开关,选上。
C++发送给服务器结构体: struct base
{
unsigned char a;
short b;
};
struct AA: public base
{
unsigned short c;
BB d[603];
};
struct BB
{
unsigned short e;
CC f;
};
struct CC
{
unsigned char g;
char h[10];
};
调用的接口函数 sendmsg(void *msg)
C++从服务器接收的结构体:
struct base
{
unsigned char a;
short b;
};
struct DD: public base
{
unsigned short o;
EE p[603];
};
struct EE
{
unsigned short q;
FF r;
};
struct FF
{
unsigned char s;
char t[10];
};
接收的话给的是内存地址,通过Marshal.PtrToStructure来转,问题关键是接收和发送的两大结构体里面有个类型数组,譬如现在我写的 603这个大小,翻译成C#应该就是我在1楼写的SizeConst = 603。
问题就是 这个603是动态的,可能下次发送的大小是500或400。在C++里面,可以把它设置成1,然后动态申请n*sizeof(BB)的空间,请问C#要怎么使它成动态的
先去了解一下在struct 里面数组如何存储的
#13
使用用数组和指针,把那个成员定义成指针,指向一个动态分配的数组应该就可以了
#14
使用用数组和指针,把那个成员定义成指针,指向一个动态分配的数组应该就可以了
能不能举一个例子啊,语法写上后有报错。
#15
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
这个在c++里是BB d[1]还是 BB*d ?
#16
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
#17
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
我怎么没见过这种用法,通常是用指针动态分配空间的
#18
#19
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
用intptr
传递的时候用Marshal.UnsafeAddrOfPinnedArrayElement
如果你能确定尺寸,也可以用Marshal.AllocHGlobal
#20
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
我怎么没见过这种用法,通常是用指针动态分配空间的
它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做
#21
BB d[603];
这个在c++里是BB d[1]还是 BB*d ?
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
用intptr
传递的时候用Marshal.UnsafeAddrOfPinnedArrayElement
如果你能确定尺寸,也可以用Marshal.AllocHGlobal
你的意思是写成这样?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct SASK
{
public intptr m_ask;
public int m_a;
public byte m_b;
}
static void TestAsk()
{
SASK sa;
var askList = new List<Ask>();
//askList.add(xxxx);
var asks=askList.ToArray();
fixed (Ask* pask = asks)
{
sa.m_ask = pask;
//调用函数......
}
}
#22
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
我怎么没见过这种用法,通常是用指针动态分配空间的
它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做
难道是 BB d[1]; d=malloc(603*sizeof(BB)); 这样编译都过不了啊
#23
在c++里面的原型是BB d[1]。
然后要603个元素,就动态分配,先计算大小603*sizeof(BB),在分配内存,C++里面这样可以的吧。但是C#要怎么做呢 赐教
我怎么没见过这种用法,通常是用指针动态分配空间的
它就是先构造一个一元素数组,相当于一个单位,然后603*一个单位的空间 ,不就是BBd[603]了吗。
指针动态分配 C#怎么做
难道是 BB d[1]; d=malloc(603*sizeof(BB)); 这样编译都过不了啊
可以的,本来想贴出来,上次有个人qq发我的,一时找不到了,最终肯定是动态申请,malloc刚才我也有问题,是怎么个语法c++里有点不清楚了。
#24
struct AA
{
int size;
BB d[1];
};
在C++里面,之所有有BB d[1]这种写法,它表示至少有一个BB, 紧跟在一个size后面。因此在内存布局上,他们必须是 连续的。
struct Point
{
int X, Y;
};
struct PointList
{
int Length;
Point Points[1]; //<--
};
extern "C" _declspec(dllexport) Point Sum(PointList& pointList)
{
Point result = {};
for(int i = 0; i < pointList.Length; i++)
{
result.X += pointList.Points[i].X;
result.Y += pointList.Points[i].Y;
}
return result;
}
void Test()
{
PointList* ptr = (PointList*)malloc(4 + sizeof(Point) * 3);
ptr->Length = 3;
ptr->Points[0].X = 1;
ptr->Points[0].Y = 2;
ptr->Points[1].X = 11;
ptr->Points[1].Y = 22;
ptr->Points[2].X = 111;
ptr->Points[3].Y = 222;
// ptr指向的内存为: [3,1,2,11,22,111,222]
Point sum = Sum(*ptr); // sum.X=123, sum.Y=246
free(ptr);
}
对C#来说,带有的关键就是内存布局的兼容,你可以用IntPtr,也可以用byte[],但是,要提供一段连续的内存[3,1,2,11,22,111,222]。例子可以这样写:
private void button1_Click(object sender, EventArgs e)
{
Point[] points = new Point[]
{
new Point(1,2),
new Point(11,22),
new Point(111,222),
};
int int32InBytes = Marshal.SizeOf(typeof(int));
int arrayInBytes = Marshal.SizeOf(typeof(Point)) * points.Length;
// 写PointList.Length
byte[] buffer = new byte[int32InBytes + arrayInBytes];
BitConverter.GetBytes(points.Length).CopyTo(buffer, 0);
// 写PointList.Points
GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);
Marshal.Copy(gc.AddrOfPinnedObject(), buffer, 4, buffer.Length - 4);
gc.Free();
Point sum = Sum(buffer); // X=123, Y=246
}
[DllImport("xxx", CallingConvention = CallingConvention.Cdecl)]
extern static Point Sum(byte[] buffer);
#25
struct AA
{
int size;
BB d[1];
};
在C++里面,之所有有BB d[1]这种写法,它表示至少有一个BB, 紧跟在一个size后面。因此在内存布局上,他们必须是 连续的。
struct Point
{
int X, Y;
};
struct PointList
{
int Length;
Point Points[1]; //<--
};
extern "C" _declspec(dllexport) Point Sum(PointList& pointList)
{
Point result = {};
for(int i = 0; i < pointList.Length; i++)
{
result.X += pointList.Points[i].X;
result.Y += pointList.Points[i].Y;
}
return result;
}
void Test()
{
PointList* ptr = (PointList*)malloc(4 + sizeof(Point) * 3);
ptr->Length = 3;
ptr->Points[0].X = 1;
ptr->Points[0].Y = 2;
ptr->Points[1].X = 11;
ptr->Points[1].Y = 22;
ptr->Points[2].X = 111;
ptr->Points[3].Y = 222;
// ptr指向的内存为: [3,1,2,11,22,111,222]
Point sum = Sum(*ptr); // sum.X=123, sum.Y=246
free(ptr);
}
对C#来说,带有的关键就是内存布局的兼容,你可以用IntPtr,也可以用byte[],但是,要提供一段连续的内存[3,1,2,11,22,111,222]。例子可以这样写:
private void button1_Click(object sender, EventArgs e)
{
Point[] points = new Point[]
{
new Point(1,2),
new Point(11,22),
new Point(111,222),
};
int int32InBytes = Marshal.SizeOf(typeof(int));
int arrayInBytes = Marshal.SizeOf(typeof(Point)) * points.Length;
// 写PointList.Length
byte[] buffer = new byte[int32InBytes + arrayInBytes];
BitConverter.GetBytes(points.Length).CopyTo(buffer, 0);
// 写PointList.Points
GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);
Marshal.Copy(gc.AddrOfPinnedObject(), buffer, 4, buffer.Length - 4);
gc.Free();
Point sum = Sum(buffer); // X=123, Y=246
}
[DllImport("xxx", CallingConvention = CallingConvention.Cdecl)]
extern static Point Sum(byte[] buffer);
请问:
报了Object contains non-primitive or non-blittable data错误,在GCHandle gc = GCHandle.Alloc(points, GCHandleType.Pinned);这句话。
我的结构体在Point还有个自定义类型参数,是不是这个引起的, 没查出来,然后这个头还要不要写 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Point
{
int X, Y;
TT _t;
};
public struct TT
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string str;
}