C#调用C++ dll 回调

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#调用C++ dll 回调相关的知识,希望对你有一定的参考价值。

c++原文定义:
回调函数,const char *strPerc为内部字符指针,回调函数返回测量数据
typedef void (*PercCallback)(const char *strPerc);
//注册回调函数
extern "C" _declspec(dllexport) void RegisterPercCallback(PercCallback Callback);
——————————————————————————————————————
我自己写的C#:
[DllImport("PR202_10Dll.dll", CharSet = CharSet.Auto, EntryPoint = "RegisterPercCallback", CallingConvention = CallingConvention.Cdecl)]
public static extern Boolean RegisterPercCallback(PercCallback Callback);
public delegate void PercCallback([MarshalAs(UnmanagedType.LPArray, SizeConst = 8000)]byte[] msg);
想显示 回调信息。该怎么下下面的语句?

参考技术A C#调用于windows平台或其他内部之类的调用,叫PInvoke或P-Invoke(Platform invoke,平台调用),有关这部分的知识在MSDN上描写的很详细的。涉及到的内容就是所谓的“平台封送”的问题,它并非简的类型对照,所有这方面的知识需要去MSDN上查询有关PInvoke的内容。
就目前来看,楼主所谓的以上两个定义基本上来说是正确的(其实回调用函数封送时也可以考虑使用StringBuilder去接收的),但这两个句代码只是表示你“定义”了调用,在没有调用时显然是不行的。所以你需要写委托对应的方式写完整,然后在调用主函数(RegisterPercCallback)即可。委托自会调用相应的方法。
所以你这里只是声明了委托,但委托真正的方法还没有写完。第一部分在入口或程序执行过程中执行平台调用的方法,该方面调用时会调用C++中的对应的方法(EntryPoint指明的方法,如果没有EntryPoint则使用的是同名方法),并加入委托(平台封送的委托也是正确的)。
其实在调用时与你正常程序的调用是一样的。只是必须使用static extent C来说明真正的平台调用而已,你写的声明其实真正的实现是在C中EntryPoint实现的,而委托其实只是被最终封送成指针到C中了!追问

非常感谢您的指点,下午摸索了一下。通过private void getdata()



callback = CallBackFunction;

RegisterPercCallback(callback);


取到了数据,但是又有保存。这块能麻烦您再指点一下吗?

报错。

另外,c++ const char*在c#中到底用什么代替呢?string 还是byte[]?现在是用string取到的。

追答

都能取出来数据,你还在乎保存什么的吗?平台调用初始情况经常会出现一些内存无法读取等情况的。这是因为你回调方法中不能直接操作封送数据的,因为封送数据并不是你真正的数据。也就是说如果你试图对byte[](那个封送数据进行写入的话往往是内存无法读写的错误)。如果你使用的是StringBuilder进行封送的话,也不能直接操作StringBuilder的。
只要注意封送的数据不去操作就可以了,所以你能显示出来的时候,那个值保存起来又有什么关系?

追问

是报错,打错打成保存了。

数据显示后点击确定就报错了。

追答

那么你又不给出代码,exception是能抛到最外面,所以就把最外层的代码让我看什么?把引用错误的代码发出来才能看到啊。又一个对Exception机制不熟悉的。

追问

代码贴不下,麻烦移步到csdn:http://bbs.csdn.net/wap/topics/392159585

麻烦您看看!

追答

原因我已经解释很清楚了,既然执行过ReadLastData怎么还会再去读取Byte呢?还有,你是哪个vs版本?我记着没错的错Byte[] m = new byte[]; m.ToString()的返回值应该是"System.Bytes",而如果是string类型的话,string.ToString()本身就是多余,若没值的话也会存在null.ToString()的空引用错误(System.ArgumentNullException),所以你的代码看起来本身就不对的。ReadLastData已经读取数据了,所以委托应该会自行被调用,而不是直接由程序调用的,否则委托还叫什么委托(委托的意思就是让其他程序委托执行,说白了是指针,其实有点象友元函数的概念)。所以应该是你重复执行了。你可以调用试一下!
顺便说一下,如果你的程序是专用驱动的话这种方案的选择是正确的。而如果是免驱(由windows自身提供驱动)的话,你要么直接调用windows底层(PInvoke)而不该直接调用人家的应该程序中的(免驱的意思是标准的windows驱动,你pinvoke到人家应该程序还不如直接使用tbl工具的方案,专用程序常用这个方案),粗看下来,基本上SerialPort通信,如果有通信参数的话应该使用SerialPort方式开发。所以我有点怀疑你不是选错开发方案了?

追问

原来代码是byte,后修改为String了。这个是个农残检测仪,没有sdk,只有个C++做的dll和一个简单的文档说明。看您这么说我觉得就是重复调用引起的报错,那么ReadLastData()是必须的,自定义的getdata这里如何处理才能避免重复调用呢?

ReadLastData是dll中定义用来取最后一次数据的,数据又需要通过回调才能输出,其实就是矛盾在执行ReadLastData后怎么才能把回调数据显示出来?

用的版本是vs2017 ,我自学的c#,基础不好,唯一的一点基础是au3和易语言。。。非常感谢您精彩的指导。给您添麻烦了!!

本回答被提问者和网友采纳

以上是关于C#调用C++ dll 回调的主要内容,如果未能解决你的问题,请参考以下文章

C++ dll 回调C# 程序总结

C#调用C++动态库接口函数和回调函数

C#调用C++动态库接口函数和回调函数

C++ 到 C# 回调结构编组

将带有参数的 c# 回调方法传递给 c++ dll 会导致 System.ExecutionEngineException

C#中调用C的DLL中的回调函数,想实现消息响应机制