C#调用动态链接库的结构体数组指针问题

最后一只恐龙 2010-01-26 01:03:10
C++做的动态链接库,一个接口函数使用了结构体数组指针,而这个结构体中还包括了一个联合数据结构,下面是C#中定义的结果体,可以确认这个结构体已经完全对齐了C++中的结构体。

[StructLayout(LayoutKind.Explicit, Pack=1)]
public struct tagRealData
{
[FieldOffset(0)]
public byte byA;
[FieldOffset(1)]
public byte byB;
[FieldOffset(2)]
public UInt16 uC;
[FieldOffset(4)]
public float fD;
[FieldOffset(4)]
public byte byE;
[FieldOffset(4)]
public double dF;
}


而后在C#中调用接口函数,却只能得到第0个元素的值,后面的值都不对,望高手指点:

public int ReadStatus()
{
// 获得访问数组,并初始化
TAInterface.tagRealData[] rData = GetRealDataStruct();
if (rData == null)
return 0;
if (rData.Length == 0)
return 0;

// 结构体类型和IntPtr类型的大小
int nSizeofRD = Marshal.SizeOf(typeof(TAInterface.tagRealData));
int nSizeofIntPtr = Marshal.SizeOf(typeof(IntPtr));

// 转换为指针,首先建立一个与之同样大小的数组
IntPtr[] pArray = new IntPtr[rData.Length];
for (int i = 0; i < rData.Length; i++)
pArray[i] = Marshal.AllocHGlobal(nSizeofRD * rData.Length);

// 将数组转换为一个指针
IntPtr pRD = Marshal.AllocHGlobal(nSizeofIntPtr * rData.Length);

// 把C#结构体数组拷贝至这个指针
Marshal.Copy(pArray, 0, pRD, 1);
for (int i = 0; i < rData.Length; i++)
Marshal.StructureToPtr(rData[i], (IntPtr)((UInt32)pRD + i * nSizeofIntPtr), true);

// 获取数据
int nRead = TAInterface.GetRealData(1, pRD, rData.Length);

// 得到结果分析
Equipment equip;
TAInterface.tagRealData r;

for (int i = 0; i < rData.Length; i++ )
{
r = (TAInterface.tagRealData)Marshal.PtrToStructure((IntPtr)((UInt32)pRD + i * nSizeofIntPtr), typeof(TAInterface.tagRealData));
if ((equip = Get(r.uC)) == null)
continue;
equip.SetStatus((byte)(r.byE % 2));
}

// 清理内存
Marshal.DestroyStructure(pRD, typeof(TAInterface.tagRealData));
Marshal.FreeHGlobal(pRD);

return nRead;
}

...全文
3103 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
sub7v21 2011-08-03
  • 打赏
  • 举报
回复
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.I1)]
public byte[] Data = new byte[8];

错误 1 “CANTest.CANApi.VCI_CAN_OBJ.Data”: 结构中不能有实例字段初始值 D:\我的资料库\Documents\Visual Studio 2010\Projects\CANTest\CANTest\CANApi.cs 95 27 CANTest


“ = new byte[8]”这个不能添加进去,我也在想为什么
H_noob 2010-06-03
  • 打赏
  • 举报
回复
帮顶 ~ 学习了~
xujiaoxiang 2010-01-26
  • 打赏
  • 举报
回复
为什么一定要使用指针呢?
[DllImport("GetRData.dll", EntryPoint = "#4")] // 测试
public static extern int GetRealData(int type, [IN,OUT,MarshalAs(UnmanagedType.LPArray)]tagRealData[] pRD, int num);
这样使用起来多方便。

手头没有C++的dll,不然测试一下。
最后一只恐龙 2010-01-26
  • 打赏
  • 举报
回复
pRD是指向pArray的指针,因此长度应为1,修改后的代码如下

public int ReadStatus()
{
// 获得访问数组,并初始化
TAInterface.tagRealData[] rData = GetRealDataStruct();
if (rData == null)
return 0;
if (rData.Length == 0)
return 0;

// 结构体类型和IntPtr类型的大小
int nSizeofRD = Marshal.SizeOf(typeof(TAInterface.tagRealData));
int nSizeofIntPtr = Marshal.SizeOf(typeof(IntPtr));

// 转换为指针,首先建立一个与之同样大小的数组
IntPtr[] pArray = new IntPtr[rData.Length];
//for (int i = 0; i < rData.Length; i++)
pArray[0] = Marshal.AllocHGlobal(nSizeofRD * rData.Length);

// 将数组转换为一个指针
IntPtr pRD = Marshal.AllocHGlobal(nSizeofIntPtr * 1);

// 把C#结构体数组拷贝至这个指针
Marshal.Copy(pArray, 0, pRD, 1);
for (int i = 0; i < rData.Length; i++)
Marshal.StructureToPtr(rData[i], (IntPtr)((UInt32)pRD + i * nSizeofRD), true);

// 获取数据
int nRead = TAInterface.GetRealData(1, pRD, rData.Length);

// 得到结果分析
Equipment equip;
TAInterface.tagRealData r;

for (int i = 0; i < rData.Length; i++ )
{
r = (TAInterface.tagRealData)Marshal.PtrToStructure((IntPtr)((UInt32)pRD + i * nSizeofRD), typeof(TAInterface.tagRealData));
// 此处略去......
}

// 清理内存
Marshal.DestroyStructure(pRD, typeof(TAInterface.tagRealData));
Marshal.FreeHGlobal(pRD);

return nRead;
}
最后一只恐龙 2010-01-26
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 wuyq11 的回复:]
C/C++函数声明是什么样子
Marshal.FreeHGlobal();
使用unsafe
http://topic.csdn.net/u/20090716/10/1388ad60-4968-400f-ab65-8a1fffe72e16.html
[/Quote]
非常感谢,成功了,一会儿整理一下
xujiaoxiang 2010-01-26
  • 打赏
  • 举报
回复
问题应该出在IntPtr pRD上,只有sizeof(intPtr)的数据返回了。
直接用定义的结构做参数吧
[MarshalAs(UnmanagedType.LPStruct)]tagRealData pRD
最后一只恐龙 2010-01-26
  • 打赏
  • 举报
回复
C++中的接口函数:

int __declspec(dllexport) GetRealData(int type, PRealData pRD, int num);

其中PRealData是tagRealData的指针类型。

C#中的写法为:

[DllImport("GetRData.dll", EntryPoint = "#4")] // 测试
public static extern int GetRealData(int type, IntPtr pRD, int num);
xujiaoxiang 2010-01-26
  • 打赏
  • 举报
回复
C++做的动态链接库,一个接口函数的声明怎么写的?
可能有问题。

对于结构体数组指针可以使用UnmanagedType.LPStruct声明接口函数的参数
khjian 2010-01-26
  • 打赏
  • 举报
回复
友情帮顶
wuyq11 2010-01-26
  • 打赏
  • 举报
回复
C/C++函数声明是什么样子
Marshal.FreeHGlobal();
使用unsafe
http://topic.csdn.net/u/20090716/10/1388ad60-4968-400f-ab65-8a1fffe72e16.html
saturn4263195 2010-01-26
  • 打赏
  • 举报
回复
uP, 帮顶.
aboluoyuren 2010-01-26
  • 打赏
  • 举报
回复


unsafe struct tagRealData
{
[FieldOffset(0)]
public byte byA;
[FieldOffset(1)]
public byte byB;
[FieldOffset(2)]
public UInt16 uC;
[FieldOffset(4)]
public float fD;
[FieldOffset(4)]
fixed public byte byE;
[FieldOffset(4)]
fixed public double dF;
}
试试看
最后一只恐龙 2010-01-26
  • 打赏
  • 举报
回复
我写的代码中多次出现了nSizeofIntPtr和nSizeofRD这两个变量,请帮忙看一下这两个用的对不对,在什么情况下用哪一个,这有可能是问题的关键。
Thr21ough 2010-01-26
  • 打赏
  • 举报
回复
up~
qq497525725 2010-01-26
  • 打赏
  • 举报
回复
UP, 帮顶.
qqiuzaihui 2010-01-26
  • 打赏
  • 举报
回复
UP, 帮顶.
FrankSun80 2010-01-26
  • 打赏
  • 举报
回复
微软msdn网站上好像有于此相关的内容
不是很懂这个,如果楼主直接用c#搞不定
不妨试一试用c++/cli包装下c++
然后再用c#调用cli的函数
最后一只恐龙 2010-01-26
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 liuqian4243 的回复:]
            // 获得访问数组,并初始化
            TAInterface.tagRealData[] rData = GetRealDataStruct();

这个返回的,本来就只有一个元素吧?

先,看一下初始化方法的定义
[/Quote]
是3个元素,跟踪了。目前的问题是,调用动态链接库后返回也是3个元素,这个结果正确,但每个元素的值只有第一个正确,其它两个都是固定值。应该在数组转换为指针时出问题了。
Ny-6000 2010-01-26
  • 打赏
  • 举报
回复
// 获得访问数组,并初始化
TAInterface.tagRealData[] rData = GetRealDataStruct();

这个返回的,本来就只有一个元素吧?

先,看一下初始化方法的定义

110,546

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧