C#调用C封装dll结构体指针

时间:2022-05-27 10:30:47
原来一直用MFC做,最近项目要用C#学了学基本的东西还是有差距啊,调用底层函数的时候卡主了,求路过大神帮忙
先是C++的定义:
typedef struct TagData_struct{
    double value; //返回点的数值
    long     time; //返回点的时间,秒
    int  status; //返回点的状态
}TagData;

初始化:
char *tagNames[MEM_PAGE_ITEMS];
for ( int i=0; i<MEM_PAGE_ITEMS; i++ )
{
tagNames[i]=(char*)malloc( TAGNAME_LENGTH*sizeof(char) );
memset(tagNames[i],0,TAGNAME_LENGTH);
strcpy( tagNames[i], PtName[i].GetBuffer());
PtName[i].ReleaseBuffer();
}

TagData *g_pTagData;
g_pTagData =(TagData *)malloc( MEM_PAGE_ITEMS*sizeof(TagData) );
memset( g_pTagData, 0, MEM_PAGE_ITEMS*sizeof(TagData) );
调用:
iRet =RTDBDao.GetRTDataByBatch( tagNames , g_pTagData, g_iPtCount );
函数原型:
int GetRTDataByBatch( char* tagNames[],TagData * pTagData,long nCount )

下面是我写的C#的:
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct TagData
    {
        public double value; //返回点的数值
        public long time; //返回点的时间,秒
        public int status; //返回点的状态
    };

 class LibWrapper
    {
        [DllImport("DataInterface.dll", CharSet = CharSet.Ansi, EntryPoint = "GetRTDataByBatch", CallingConvention = CallingConvention.Cdecl)]
        public extern static int GetRTDataByBatch([In] string[] tagName, IntPtr tgs, long nCount);
    }

main函数中:

 string[] tagNames = new string[2];
            tagNames[0] = "Dev_Test00";
            tagNames[1] = "Dev_Test01";
         
            IntPtr[] ptArray = new IntPtr[1];
            ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TagData)) * 10);
            IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * 1);
            Marshal.Copy(ptArray, 0, pt, 1);

            iRet = LibWrapper.GetRTDataByBatch(tagNames, pt, 2);

            for (int i = 0; i < 2; i++)
            {
                TagData tagInfo = (TagData)Marshal.PtrToStructure((IntPtr)((UInt32)ptArray[0] + i * Marshal.SizeOf(typeof(TagData))), typeof(TagData));
                double val = tagInfo.value;
                long tm =  tagInfo.time;
                int state = tagInfo.status;
            }
             
            Marshal.FreeHGlobal(ptArray[0]);
            Marshal.FreeHGlobal(pt);

取不到数据为什么呢? 哪里写错了?

11 个解决方案

#1


typedef struct TagData_struct{
    double value; //返回点的数值
    long     time; //返回点的时间,秒
    int  status; //返回点的状态

数据类型没对应吧,C#里面是int C++里面是long的话

#2


引用 1 楼 wjfwd2010 的回复:
typedef struct TagData_struct{
    double value; //返回点的数值
    long     time; //返回点的时间,秒
    int  status; //返回点的状态

数据类型没对应吧,C#里面是int C++里面是long的话


并没有吧,int、long都是4个byte啊

#3


C#里面的long是C++中的LONGLONG,所以C#结构体中time应该是int型的

#4


引用 2 楼 zhenghaolan 的回复:
Quote: 引用 1 楼 wjfwd2010 的回复:

typedef struct TagData_struct{
    double value; //返回点的数值
    long     time; //返回点的时间,秒
    int  status; //返回点的状态

数据类型没对应吧,C#里面是int C++里面是long的话


并没有吧,int、long都是4个byte啊

好像不是吧?

#5


引用 3 楼 bigbaldy 的回复:
C#里面的long是C++中的LONGLONG,所以C#结构体中time应该是int型的


这样啊,谢谢你和1L可是改完了我得到的数据还是不对的
如果把函数声明成
 public extern static int GetRTDataByBatch([In] string[] tagName, ref TagData[] tgs, long nCount);
后面用结构体数组直接传参可以得到第一个值是正确的,可是后面又不对了

#6


引用 5 楼 zhenghaolan 的回复:
Quote: 引用 3 楼 bigbaldy 的回复:

C#里面的long是C++中的LONGLONG,所以C#结构体中time应该是int型的


这样啊,谢谢你和1L可是改完了我得到的数据还是不对的
如果把函数声明成
 public extern static int GetRTDataByBatch([In] string[] tagName, ref TagData[] tgs, long nCount);
后面用结构体数组直接传参可以得到第一个值是正确的,可是后面又不对了


C++的TagData_struct声明要加#pragma pack(1)

#7


谢谢楼上各位,不是对齐的问题
查了大半天MSDN
参考这里
http://msdn.microsoft.com/zh-cn/library/hk9wyw21.aspx

[DllImport("DataInterface.dll", CharSet = CharSet.Ansi, EntryPoint = "GetRTDataByBatch", CallingConvention = CallingConvention.Cdecl)]
public extern static int GetRTDataByBatch([In] string[] tagName, [In,Out] TagData[] tgs, long nCount);

注意第二个参数的[In,Out]属性,单独的in或者out都不行
调用时初始化结构体数组
 TagData[] tags = new TagData[2];
            for (int i = 0; i < tags.Length; i++)
            {
                tags[i] = new TagData();
            }

iRet = LibWrapper.GetRTDataByBatch(tagNames, tags, 2);
这样就可以了

#8


恭喜楼主,这个问题留着,有用!

#9


C#调用C封装dll结构体指针
返回结构滴头指针就可以
如果你觉得不爽那就不再
接收程序内定义结构体
玩指针一样很爽

#10


引用 9 楼 Windowsvipcuvs 的回复:
C#调用C封装dll结构体指针
返回结构滴头指针就可以
如果你觉得不爽那就不再
接收程序内定义结构体
玩指针一样很爽


能给段代码吗,还在入门。。

#11


引用 10 楼 zhenghaolan 的回复:
Quote: 引用 9 楼 Windowsvipcuvs 的回复:

C#调用C封装dll结构体指针
返回结构滴头指针就可以
如果你觉得不爽那就不再
接收程序内定义结构体
玩指针一样很爽


能给段代码吗,还在入门。。

RtlMoveMemory 会用吗

#1


typedef struct TagData_struct{
    double value; //返回点的数值
    long     time; //返回点的时间,秒
    int  status; //返回点的状态

数据类型没对应吧,C#里面是int C++里面是long的话

#2


引用 1 楼 wjfwd2010 的回复:
typedef struct TagData_struct{
    double value; //返回点的数值
    long     time; //返回点的时间,秒
    int  status; //返回点的状态

数据类型没对应吧,C#里面是int C++里面是long的话


并没有吧,int、long都是4个byte啊

#3


C#里面的long是C++中的LONGLONG,所以C#结构体中time应该是int型的

#4


引用 2 楼 zhenghaolan 的回复:
Quote: 引用 1 楼 wjfwd2010 的回复:

typedef struct TagData_struct{
    double value; //返回点的数值
    long     time; //返回点的时间,秒
    int  status; //返回点的状态

数据类型没对应吧,C#里面是int C++里面是long的话


并没有吧,int、long都是4个byte啊

好像不是吧?

#5


引用 3 楼 bigbaldy 的回复:
C#里面的long是C++中的LONGLONG,所以C#结构体中time应该是int型的


这样啊,谢谢你和1L可是改完了我得到的数据还是不对的
如果把函数声明成
 public extern static int GetRTDataByBatch([In] string[] tagName, ref TagData[] tgs, long nCount);
后面用结构体数组直接传参可以得到第一个值是正确的,可是后面又不对了

#6


引用 5 楼 zhenghaolan 的回复:
Quote: 引用 3 楼 bigbaldy 的回复:

C#里面的long是C++中的LONGLONG,所以C#结构体中time应该是int型的


这样啊,谢谢你和1L可是改完了我得到的数据还是不对的
如果把函数声明成
 public extern static int GetRTDataByBatch([In] string[] tagName, ref TagData[] tgs, long nCount);
后面用结构体数组直接传参可以得到第一个值是正确的,可是后面又不对了


C++的TagData_struct声明要加#pragma pack(1)

#7


谢谢楼上各位,不是对齐的问题
查了大半天MSDN
参考这里
http://msdn.microsoft.com/zh-cn/library/hk9wyw21.aspx

[DllImport("DataInterface.dll", CharSet = CharSet.Ansi, EntryPoint = "GetRTDataByBatch", CallingConvention = CallingConvention.Cdecl)]
public extern static int GetRTDataByBatch([In] string[] tagName, [In,Out] TagData[] tgs, long nCount);

注意第二个参数的[In,Out]属性,单独的in或者out都不行
调用时初始化结构体数组
 TagData[] tags = new TagData[2];
            for (int i = 0; i < tags.Length; i++)
            {
                tags[i] = new TagData();
            }

iRet = LibWrapper.GetRTDataByBatch(tagNames, tags, 2);
这样就可以了

#8


恭喜楼主,这个问题留着,有用!

#9


C#调用C封装dll结构体指针
返回结构滴头指针就可以
如果你觉得不爽那就不再
接收程序内定义结构体
玩指针一样很爽

#10


引用 9 楼 Windowsvipcuvs 的回复:
C#调用C封装dll结构体指针
返回结构滴头指针就可以
如果你觉得不爽那就不再
接收程序内定义结构体
玩指针一样很爽


能给段代码吗,还在入门。。

#11


引用 10 楼 zhenghaolan 的回复:
Quote: 引用 9 楼 Windowsvipcuvs 的回复:

C#调用C封装dll结构体指针
返回结构滴头指针就可以
如果你觉得不爽那就不再
接收程序内定义结构体
玩指针一样很爽


能给段代码吗,还在入门。。

RtlMoveMemory 会用吗