C#史上最难调用C++DLL 问题

问题描述

调取这个C++dll中的某个函数,这个函数返回回来的是个结构体指针,而我需要获取的值在这个结构体里面的联合体(Value)中,如何做处理呢,C++原型:typedefstruct_TAG_VALUE_OUT_{unsignedintID;//TagIDunsignedcharType;//类型unsignedcharQuality;//质量TIMESTAMPTimestamp;//时间戳PointValueValue;//值联合体}PointData;typedefunion_TAG_VALUE_GROUP_OUT_{unsignedchardigitalVal;//Digital(8bits)shortint16Val;//short(16bits)intint32Val;//int(32bits)floatfloatVal;//float(4Bytes)doubledoubleVal;//double(8Bytes)char*stringVal;//stringpoint(4Bytes)->778BytesBuffer}PointValuetypedefstruct_RYTHON_TIMESTAMP_//毫秒级时间戳类型定义{RYTHON_TIME_SEC_LEVELtimeStamp;//秒shortms;//毫秒}TIMESTAMP;调用函数为:intRYTHONAPIDBSN_GetValue(INRYTHON_SRV_HANDLEnHandle,INTAG_IDnTagID,OUTPointData*pPointData);前两个值我是保证正确的,但是如何接受这个返回的结构体指针,然后从里面读取数据呢?返回回来的指针值跟TagID号是一样的,显然Value不是这个值,估计要从指针指向的内存块中读取这个结构体里面的联合体,请问如何处理???

解决方案

解决方案二:
这个问题不难,注意一点:在C#中联合这种类型是不能直接封送到非托管内存的,因为内存边界对不齐。换句话说,每一个可能的联合类型都需要在C#中声明相应的类,并根据需要补充数据进行对齐。
解决方案三:
这个是标准的capi,把需要的结构体一一对应好,就应该没有问题[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Ansi,Pack=1)]publicstructTIMESTAMP{///<summary>///秒级时间戳///</summary>publicintSecond;//这个应该是Int类型,具体应该看.h文件中的定义///<summary>///毫秒///</summary>publicshortMilliSecond;}[System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]publicstructValue{[FieldOffset(0)]publicbyteByte;[FieldOffset(0)]publicshortShort;[FieldOffset(0)]publicintInteger;[FieldOffset(0)]publicfloatFloat;[FieldOffset(0)]publicdoubleDouble;///<summary>///字符串///</summary>[FieldOffset(0)]publicIntPtrString;}[StructLayout(LayoutKind.Explicit,CharSet=CharSet.Ansi,Pack=1)]publicstructPointData{[FieldOffset(0)]publicuintID;[FieldOffset(4)]publicbyteType;[FieldOffset(5)]publicbyteStatus;[FieldOffset(6)]publicTIMESTAMPTime;[FieldOffset(12)]publicValueValue;}

解决方案四:
C#里有指针,你C++怎么声明的,C#就怎么调用,C#里pPointData.Value就是联合体的值,具体要啥值你自己强转就行了
解决方案五:
函数定义使用DllImport[DllImport("yourdllname",EntryPoint="DBSN_GetValue",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]publicstaticexternintGetValue(intnHandle,uinttagID,outPointDatapDate);

这个PointData需要在调用前申请,使用后释放
解决方案六:
这个函数无法进行P/INVOKE,因为返回值包含了非托管的指针,必定会造成内存泄漏。这个函数即使在C内部也是危险的,因为结构体内部包含了指针,这意味着你释放这个结构体内存时,必须要先释放内部指针的内存,否则就会造成内存泄漏,因此一般不会定义这样的结构体,除非是自己内部的调用,自己清楚释放过程。
解决方案七:
这东西我只能说呵呵了两种语言要相互调用,起码数据类型要统一,要使用2种语言都支持的某种数据类型你C#里定义个返回DataTable的函数,C++里能认识才怪了,除非你自己在C++里实现这个DataTable类型你这个问题也一样,C里定义的结构体里带指针,C#要想用,就得自己先实现完全相同的类型
解决方案八:
定义相同类型也没用,方法返回的不是结构体而是结构体的指针!尼玛又没给出内存地址,C#怎么知道你给指在什么地方?
解决方案:
引用6楼Z65443344的回复:

这东西我只能说呵呵了两种语言要相互调用,起码数据类型要统一,要使用2种语言都支持的某种数据类型你C#里定义个返回DataTable的函数,C++里能认识才怪了,除非你自己在C++里实现这个DataTable类型你这个问题也一样,C里定义的结构体里带指针,C#要想用,就得自己先实现完全相同的类型

标准C的话,C#使用毫无压力啊。各种语言交互都使用纯C的接口或者COM。
解决方案:
引用5楼qldsrx的回复:

这个函数无法进行P/INVOKE,因为返回值包含了非托管的指针,必定会造成内存泄漏。这个函数即使在C内部也是危险的,因为结构体内部包含了指针,这意味着你释放这个结构体内存时,必须要先释放内部指针的内存,否则就会造成内存泄漏,因此一般不会定义这样的结构体,除非是自己内部的调用,自己清楚释放过程。

这个API设计是没问题的,不牵涉到内存分配释放。Win32API中传递结构体指针的API太多了。
解决方案:
很简单的问题,MSDN中有现成的例子。
解决方案:
返回指针,就用IntPtr接受,然后Marshal.PtrToStructure把指针指向数据拷贝到托管结构体里不久好了
解决方案:
引用10楼akirya的回复:

很简单的问题,MSDN中有现成的例子。

你的示例我看了,定义的类型中不含指针,那样肯定不会有问题,而楼主的则不同,他那个是要两次分配内存,我虽然没写过C++,但我写过C。我不清楚C#的非托管内存和C++里面的内存地址是否重叠,如果重叠,则可以使用Marshal类来释放这个结构体内指针的内存,也可以去读取它,如果内存地址是独立的,那C#在调用C++函数后,就得不到那个指针所指向内存的内容,且会造成内存泄漏。毕竟这个是P/INVOKE,和C++里面直接include不同。
解决方案:
引用12楼qldsrx的回复:

Quote: 引用10楼akirya的回复:
很简单的问题,MSDN中有现成的例子。

你的示例我看了,定义的类型中不含指针,那样肯定不会有问题,而楼主的则不同,他那个是要两次分配内存,我虽然没写过C++,但我写过C。我不清楚C#的非托管内存和C++里面的内存地址是否重叠,如果重叠,则可以使用Marshal类来释放这个结构体内指针的内存,也可以去读取它,如果内存地址是独立的,那C#在调用C++函数后,就得不到那个指针所指向内存的内容,且会造成内存泄漏。毕竟这个是P/INVOKE,和C++里面直接include不同。

char*么?lz的问题是取结构体中的union。
解决方案:
引用9楼akirya的回复:

Quote: 引用5楼qldsrx的回复:
这个函数无法进行P/INVOKE,因为返回值包含了非托管的指针,必定会造成内存泄漏。这个函数即使在C内部也是危险的,因为结构体内部包含了指针,这意味着你释放这个结构体内存时,必须要先释放内部指针的内存,否则就会造成内存泄漏,因此一般不会定义这样的结构体,除非是自己内部的调用,自己清楚释放过程。

这个API设计是没问题的,不牵涉到内存分配释放。Win32API中传递结构体指针的API太多了。

+1同意,自己申请,自己释放,没有问题的
解决方案:
引用4楼xian_wwq的回复:

函数定义使用DllImport[DllImport("yourdllname",EntryPoint="DBSN_GetValue",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]publicstaticexternintGetValue(intnHandle,uinttagID,outPointDatapDate);

这个PointData需要在调用前申请,使用后释放

兄弟,你这里调用GetValue函数时,定义的参数是outPointData,实际上,他返回来的应该是个结构体指针啊,取得位置应该不对。
解决方案:
引用11楼wjq的回复:

返回指针,就用IntPtr接受,然后Marshal.PtrToStructure把指针指向数据拷贝到托管结构体里不久好了

按照这个API的函数介绍,返回来的应该是个结构体指针,我用outIntPtr回来能得到一个值,但是如何通过指针来访问到该指针指向的内存内容呢?Marshal.PtrToStructure怎么用
解决方案:
标题很劲爆,进来看看,纯支持
解决方案:
引用15楼aqjwqrllw的回复:

Quote: 引用4楼xian_wwq的回复:
函数定义使用DllImport[DllImport("yourdllname",EntryPoint="DBSN_GetValue",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]publicstaticexternintGetValue(intnHandle,uinttagID,outPointDatapDate);

这个PointData需要在调用前申请,使用后释放

兄弟,你这里调用GetValue函数时,定义的参数是outPointData,实际上,他返回来的应该是个结构体指针啊,取得位置应该不对。

指针就是个地址呀,c#中的out和ref类型传的一样也是地址你按照dll的约定定义对应的结构体,传给dll因为结构体已经处理了字节对齐问题dll把数据返回给调用者,会有什么问题呢?
解决方案:
引用18楼xian_wwq的回复:

Quote: 引用15楼aqjwqrllw的回复:
Quote: 引用4楼xian_wwq的回复:
函数定义使用DllImport[DllImport("yourdllname",EntryPoint="DBSN_GetValue",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]publicstaticexternintGetValue(intnHandle,uinttagID,outPointDatapDate);

这个PointData需要在调用前申请,使用后释放

兄弟,你这里调用GetValue函数时,定义的参数是outPointData,实际上,他返回来的应该是个结构体指针啊,取得位置应该不对。

指针就是个地址呀,c#中的out和ref类型传的一样也是地址你按照dll的约定定义对应的结构体,传给dll因为结构体已经处理了字节对齐问题dll把数据返回给调用者,会有什么问题呢?

intsize=Marshal.SizeOf(typeof(PointData));IntPtrPointDataPtr=Marshal.AllocHGlobal(size);intcc=DBSN_GetValue(pnServerHandle,pTagID,outPointDataPtr);PointDatapPointData=(PointData)Marshal.PtrToStructure(PointDataPtr,typeof(PointData));Console.WriteLine(pPointData.Value.Float+"=="+PointDataPtr+"=="+pTagID);Marshal.FreeHGlobal(PointDataPtr);Console.WriteLine("结束");Console.Read();我是这样写的,out回来一个指针,然后通过指针找结构体,但是问题依旧
解决方案:
引用19楼aqjwqrllw的回复:

Quote: 引用18楼xian_wwq的回复:
Quote: 引用15楼aqjwqrllw的回复:
Quote: 引用4楼xian_wwq的回复:
函数定义使用DllImport[DllImport("yourdllname",EntryPoint="DBSN_GetValue",CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]publicstaticexternintGetValue(intnHandle,uinttagID,outPointDatapDate);

这个PointData需要在调用前申请,使用后释放

兄弟,你这里调用GetValue函数时,定义的参数是outPointData,实际上,他返回来的应该是个结构体指针啊,取得位置应该不对。

指针就是个地址呀,c#中的out和ref类型传的一样也是地址你按照dll的约定定义对应的结构体,传给dll因为结构体已经处理了字节对齐问题dll把数据返回给调用者,会有什么问题呢?

intsize=Marshal.SizeOf(typeof(PointData));IntPtrPointDataPtr=Marshal.AllocHGlobal(size);intcc=DBSN_GetValue(pnServerHandle,pTagID,outPointDataPtr);PointDatapPointData=(PointData)Marshal.PtrToStructure(PointDataPtr,typeof(PointData));Console.WriteLine(pPointData.Value.Float+"=="+PointDataPtr+"=="+pTagID);Marshal.FreeHGlobal(PointDataPtr);Console.WriteLine("结束");Console.Read();我是这样写的,out回来一个指针,然后通过指针找结构体,但是问题依旧

思路不对,按照我上面定义的结构体,用DllImport,除了string类型不需要Marshal的转换
解决方案:
引用12楼qldsrx的回复:

Quote: 引用10楼akirya的回复:
很简单的问题,MSDN中有现成的例子。

你的示例我看了,定义的类型中不含指针,那样肯定不会有问题,而楼主的则不同,他那个是要两次分配内存,我虽然没写过C++,但我写过C。我不清楚C#的非托管内存和C++里面的内存地址是否重叠,如果重叠,则可以使用Marshal类来释放这个结构体内指针的内存,也可以去读取它,如果内存地址是独立的,那C#在调用C++函数后,就得不到那个指针所指向内存的内容,且会造成内存泄漏。毕竟这个是P/INVOKE,和C++里面直接include不同。

引用1楼LargeSkyMensk的回复:

这个问题不难,注意一点:在C#中联合这种类型是不能直接封送到非托管内存的,因为内存边界对不齐。换句话说,每一个可能的联合类型都需要在C#中声明相应的类,并根据需要补充数据进行对齐。

couldyouguyspleaseexplainwhatthehellthishasanythingtodowithaddressalignment?Or"addressoverlap"?Whatthehackisthat?couldyoupleaseelaborateabit?

时间: 2024-08-03 18:52:06

C#史上最难调用C++DLL 问题的相关文章

史上最难的面试谜题

史上最难的面试谜题 你曾经在应聘一份编程工作的面试中被问及一些解谜类的问题吗?反正我碰到过.我被问到的那个问题是: 你最喜欢的那个牌子的苏打,有多少是在这个州被消费的? 拜托,正确的答案不能是"关我什么事",除非你不想得到这份工作了.我当时对这个问题毫无头绪,后来才知道这是一个"费米 问题"(Fermi Question). 谜题作为一种新生事物,在20世纪90年代的程序员面试里风靡一时.这在<如何移动富士山?>(<How Would You Mo

大学生就业遭遇史上最难季培训机构有新商机?

多知网4月28日消息 有关大学生今年就业形势的报道近日频繁出现,在整体经济增速放缓,就业岗位需求减少的情况下,今年被称为"史上最难毕业季".2013年大学毕业生达到699万,创建国以来新高.不过,就业问题已经显现.据<北京日报>报道,截至四月中旬,北京地区高校毕业生签约率尚不足三成.学生对于整个学习环节而言,拥有一份好工作才是最终极的目标.如果能辅导学生找到一份好的工作,从市场来讲,显然不是一个小生意.这似乎是培训业的一个商机.IT培训业就是个不错的参考.由于中国大学的教材

史上最难的游戏2图文攻略(1-10关)

第1关] 第一关最简单容易,只需要玩家按下电视右下角的红色圆形开关即可通关,可不要看小人手上有老虎钳要去修电线,那样会被电死. [第2关] 第二关的通关技巧就是点击主角的眼睛,就可以看到主角拿起墨镜男手上两个药丸放在眼睛上面就跑了,这样就成功通关了.   第3关] 第三关的通关技巧就是点击右边厕所的标志,就可以看到图中的三角形图标向下了,然后再点击右边厕所门的把手就通关了. [第4关] 第四关的通关技巧就是点击主角的头,他会切换不同道具,你点击让他切换到防毒面罩,在把左边的管道接起来,即可通关.

史上最难连连看游戏:韩国小姐连连看iOS版

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;   近日,iTunes上的一款名为"韩国小姐连连看"突然之间火了起来,游戏打出了"不红不革命!!不火不高兴!!史上最难连连看,挑战你极限!"的口号,究竟这款游戏有何特别之处呢? 原来,这款游戏的创意源自前段时间被广大网友吐槽众"佳丽"集体撞脸的"2013第57届韩国小姐大选",游戏中的图

史上最难游戏攻略第1、2、3关

[史上最难游戏攻略第1关] 本关比较简单,如下图点击中间的嘴巴即可过关,没有任何的难度. [史上最难游戏攻略第2关] 首先把靶子移动到前面来(如下图),然后点击枪即可射击,这样就可以过关了! [史上最难游戏攻略第3关] 本关比较简单,点击中间的乌云并向右拖动,让月亮露出来即可. [史上最难游戏攻略第4关] 本关没有任何难度,连续点击左边的矮个子,直到出现救护车.

绝对是精髓!!史上最难跑步游戏 QWOP 错误版模仿,你已经超神了!!

class="post_content" itemprop="articleBody"> 不知道大家有没有玩过 QWOP 游戏,这个游戏是堪称史上最难的跑步游戏,此游戏只能用到 Q.W.O.P 这四个按键,要跑一百公尺,中途还会碰到栅栏.沙坑,接近终点的时后还要大力跳跃才完成整个赛跑-- 但是很多玩家都没法继续这个游戏,因为实在是太难了!!基本上你都走不了几步,就直接倒下了.最近,有位日本网友模仿了 QWOP 的错误版,模仿得太传神了! QWOP 的错误版模仿

“史上最难抢票季”已开幕 抢票软件成勒索“利器”

号称"史上一票难求"的春运抢票季今日开启,抢票软件也自然成为抢客们的获胜利器.然而,很多抢票软件表面上标榜着高成功率,实际上却是山寨软件,一旦感染消费者操作系统,就会窃取联系人.短信.通话记录等个人信息,还可能推送恶意广告或是执行其它恶意行为.趋势科技建议用户在使用这些抢票软件的时候,要注意核实软件的安全性,并使用安全可靠的防护软件.  由于抢票软件的广泛使用,因此很少会有不法分子会"另起灶炉",制作新的恶意软件,而是会通过仿造知名抢票软件的方式,诱导用户下载,这些

挑战你的IQ 史上最难游戏合辑篇

测量你的反应力<极难游戏2>近日有一款名为<史上最牛的游戏2>的益智游戏是相当的火热,这款游戏是在清明节前期间上架,上架后就受到了很多益智玩家们的追捧,小编坐地铁时都能看到很多朋友在玩.游戏主要是考验玩家的反应时间和分辨力,看来这种具有一定难度的益智游戏相当能勾起玩家们的挑战欲望.今天小编就给朋友们推荐几款益智IQ游戏,如果你觉得<史上最牛的游戏2>还不够牛的话,不妨都挑战下吧! 游戏名称:<史上最牛的游戏2>价格:免费点击下载更新日期:2013年4月23日

史上最难开发软件54年终发布 曾能取代WEB

6月8日消息在软件行业,软件的延期跳票不算新闻,但是最近,美国的一个软件创造了产品跳票的新纪录--这款1960年开发的软件,开发了54年才最终发布,开发者发明了超文本概念,他也错过了取代互联网WEB的大好机会.这款软件的名称叫做OpenXanadu,其实也是一种文档形式,用户可以看到最终的文档,以及所有文字来源的原始文档.文档保存和呈现的原理,类似于互联网万维网WEB的工作模式,只不过在WEB中,其他的HTML文档分布在不同的服务器上,只需要通过URL链接,标注出位置.今年四月份,在美国Chap