各位大家好!我现在在做一个调用第三方接口的程序!其dll为c++写的,定义如下:
结构体:typedef struct tagDownDepInfo
{
char DPCODE1[6]; //一级部门
char DPCODE2[6]; //二级部门
char DPCODE3[8]; //三级部门
char DPCODE4[8]; //四级部门
char DPNAME1[60]; //
char DPNAME2[60]; //
char DPNAME3[60]; //
char DPNAME4[60]; //
}DOWNDEPINFO, FAR *PDOWNDEPINFO;
函数:int CapGetDepList(DOWNDEPINFO ** pINFO)
我在c#中的写法是:
结构体: [StructLayout(LayoutKind.Sequential)]
internal struct tagDownDepInfo
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string DPCODE1; //一级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string DPCODE2; //二级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string DPCODE3; //三级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string DPCODE4; //四级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
public string DPNAME1; //
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
public string DPNAME2; //
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
public string DPNAME3; //
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
public string DPNAME4; //
}
函数: [DllImport("Change.dll", CharSet = CharSet.Ansi)]
internal unsafe static extern int CapGetDepList(ref tagDownDepInfo[] downinfo);
调用: tagDownDepInfo[] downinfo = new tagDownDepInfo[100];//现已知道有100条数据
int ret = Class1.CapGetDepList(ref downinfo);
结果:返回正确,但downinfo 却变成了1行,这是为什么呢?请大家指教谢谢!在线等!分数不多,请谅解!
结构体:typedef struct tagDownDepInfo
{
char DPCODE1[6]; //一级部门
char DPCODE2[6]; //二级部门
char DPCODE3[8]; //三级部门
char DPCODE4[8]; //四级部门
char DPNAME1[60]; //
char DPNAME2[60]; //
char DPNAME3[60]; //
char DPNAME4[60]; //
}DOWNDEPINFO, FAR *PDOWNDEPINFO;
函数:int CapGetDepList(DOWNDEPINFO ** pINFO)
我在c#中的写法是:
结构体: [StructLayout(LayoutKind.Sequential)]
internal struct tagDownDepInfo
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string DPCODE1; //一级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public string DPCODE2; //二级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string DPCODE3; //三级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
public string DPCODE4; //四级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
public string DPNAME1; //
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
public string DPNAME2; //
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
public string DPNAME3; //
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 60)]
public string DPNAME4; //
}
函数: [DllImport("Change.dll", CharSet = CharSet.Ansi)]
internal unsafe static extern int CapGetDepList(ref tagDownDepInfo[] downinfo);
调用: tagDownDepInfo[] downinfo = new tagDownDepInfo[100];//现已知道有100条数据
int ret = Class1.CapGetDepList(ref downinfo);
结果:返回正确,但downinfo 却变成了1行,这是为什么呢?请大家指教谢谢!在线等!分数不多,请谅解!
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public char[] DPCODE1; //一级部门
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 6)]
public char[] DPCODE2; //二级部门
....
这个定义是说里面的DOWNDEPINFO是CapGetDepList分配的还是外面分配的?
如果内部分配 定义ok
不是 应改成int CapGetDepList(DOWNDEPINFO *pINFO)
看你程序的用法,ms是下面这种不说这个 你要知道这点 C#的数组的内存是manage的,而c++不是,所以当用ref传出去时,不知道传出去实际数组指针的大小,所以,internal unsafe static extern int CapGetDepList(ref tagDownDepInfo[] downinfo); 这种写法有点问题的
一般,遇到ref数组之类的 都得用IntPtr 如果数组是传入的,嗯,这有点麻烦,要首先申请一块对应的内存,调用Marshal.AllocHGlobal分配相应的内存,大小可以用Marshal.sizeof 自己调用Marshal.Copy 一个一个拷进去(我就是这么用的,没找到好的方法)用后释放内存
所以 我猜你的dll导入函数定义应为
[DllImport("Change.dll", CharSet = CharSet.Ansi)]
private static extern int CapGetDepList(IntPtr p);
用Marshal.PtrToStructure获得执行结果
还有传入指针,而没有大小,是一个不怎么好的函数定义方式
声明: [DllImport("Change.dll", CharSet = CharSet.Ansi)]
internal unsafe static extern int CapGetDepList(IntPtr downinfo);
调用: IntPtr p1 = new IntPtr();
p1 = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(tagDownDepInfo))*i);
int ret = Class1.CapGetDepList(p1);
出现:“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”的异常了!
还有 把dll里的函数定义改成上面的形式
这个函数是别人的,我没办法改的呢!只能按照他的说明调用,他这个是先通过别的函数取出有多少比数据,然后定义同样大小的一个结构数组传进去,我付上他的c++例子吧:
DOWNDEPINFO *pInfo=new DOWNDEPINFO[cou];
memset(pInfo, 0, sizeof(DOWNDEPINFO)*cou);
int nFlag=ccFun.CapGetDepList(&pInfo);
这个是可以的呢!在c#中就不明白了!还在郁闷中…………
这。
一定要这么做就定义IntPtr的数组啊
dllimport的声明还是
[DllImport("Change.dll", CharSet = CharSet.Ansi)]
private static extern int CapGetDepList(IntPtr p);
可能的一些步骤为
IntPtr[] ptArray = new IntPtr[1];
ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(tagDownDepInfo)) * 100);
IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * 1);
Marshal.Copy(ptArray, 0, pt, 1);
然后
CapGetDepList(pt);
拿到数据
ps:你可以说下写这个接口的人,定义个数组 尽然没有数组大小的参数,还有只需要1维的 搞个2维的,
那2维变3维 啊哈
for (int i = 0; i < size; i++)
{
tagDownDepInfo tagInfo = (tagDownDepInfo)Marshal.PtrToStructure((IntPtr)((UInt32)ptArray[0] + i * s), typeof(tagDownDepInfo));
}
Marshal.FreeHGlobal(ptArray[0]);
Marshal.FreeHGlobal(pt);试试上面的取数据方法
对此有的点想法不知道是否正确
1.当dll中的参数只是结构体时候可以选择传入参数 ref structureParam obj
2.当dll中参数是结构体指针或指向结构体数组的指针的时候选择intptr ptr传入参数
是这个意思吧?
extern "C" int _stdcall HSCAN_SendCANMessage(unsigned char nDevice,unsigned char nPort,HSCAN_MSG *msg,int nLength);
c#中的结构体申明:
[StructLayout(LayoutKind.Sequential)]
public struct HSCAN_MSG
{
[MarshalAs(UnmanagedType.U1)]
public byte Port;
/// <summary>
/// 节点标识,nEFF=1 时(扩展帧),为29 位nEFF=0(标准帧)时,为11 位;
/// </summary>
[MarshalAs(UnmanagedType.U4)]
public uint nId;
[MarshalAs(UnmanagedType.U1)]
public byte nCtrl;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] pData;
};
c#函数的调用:包含使用指针IntPtr替代结构体数组和读取IntPtr的方法
HSCAN_MSG[] msg1 = new HSCAN_MSG[10];
for (int i = 0; i < msg1.Length; i++)
{
msg1[i] = new HSCAN_MSG();
msg1[i].pData = new byte[8];
} IntPtr[] ptArray = new IntPtr[1];
ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)) * 10);
IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)));
Marshal.Copy(ptArray, 0, pt, 1);
int count = HSCAN_ReadCANMessage(0x0, 0,pt, 10);
textBoxStatus.Text += "\r\n" + "读取0口:" + count.ToString() + "帧数据";
for (int j = 0; j < 10; j++)
{
msg1[j] =
(HSCAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)pt+ j * Marshal.SizeOf(typeof(HSCAN_MSG)))
, typeof(HSCAN_MSG));
textBoxStatus.Text += "\r\n收到0口" + Convert.ToByte(msg1[j].pData[0]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[1]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[2]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[3]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[4]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[5]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[6]).ToString()
+ "|" + Convert.ToByte(msg1[j].pData[7]).ToString();
}
感谢你,感谢上面所有的人,感谢...
折腾了我一天了。