C++通过Callback向C#传递数据

2、C++ Callback

在运行中输入control
userpasswords2命令,可以收回开机以默许账户登录时不须求输入用户名和密码

3、C#方必须说美赞臣(Nutrilon)个变量,用来指向C++的回调指针函数,防止被C#回收掉。

在运转中输入lusrmgr.msc命令,调出账户管理的装置

public delegate void EKFRenderCallback(string data, string colors);

public class EKFLib
{
    [DllImport("EKFLib.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    public static extern void SetRenderCallback(EKFRenderCallback render);

在运作中输入devmgmt.msc命令,调出设备管理器

C++通过callback向C#传递数据必须小心以下几点:

在运转中输入diskmgmt.msc命令,调出磁盘管理

即所谓的C调用规则,按从右至左的各类压参数入栈,由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来敬爱的。重返值在EAX中。因而,对于象printf那样变参数的函数必须用那种规则。编译器在编译的时候对那种调用规则的函数生成修饰名的饿时候,仅在输出函数名前增进一个下划线前缀,格式为_functionname。

调出任务管理器的快捷键:ctrl+shift+esc

from:http://www.roboby.com/

调出运行命令的飞快键:Windows+r

typedef void (*CalibrationProgressCallback)(double percent);

在运作中输入appwiz.cpl命令,调出添加删除程序

对“MotionCapture!MotionCapture.EKFRenderCallback::Invoke”类型的已垃圾回收委托进行了回调。那恐怕会招致应用程序崩溃、损坏和数量丢失。向非托管代码传递委托时,托管应用程序必须让那几个委托保持活动状态,直到确信不会重新调用它们。

在运行中输入compmgmt.msc命令,调出总计机管理

2、如果是数组,必须用 [MarshalAs(UnmanagedType.LPArray, SizeConst =
23)]标志参数,指定为数组且标记数老董度;

在运转中输入firewall.cpl命令,调出系统默许的防火墙设置

public void RenderCallback(string data, string color)
{
    // rendering
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    EKFLib.SetRenderCallback(RenderCallback);
    EKFLib.Init();
}

 

那种情形下,参数堆栈是由调用者(C++一侧)维护的,在C++调用此回调函数后,会把参数弹出堆栈而释放,导致C#读取数据时出现无缘无故的失实。

锁定当前用户,并脱离到拔取用户登录验证页面的快速键:Windows+L

造成难点的由来是,默许情状下,C++中如下概念的函数指针,默许是以_cdecl格局调用的:

微软官网的例证是决定GC回收机制,那是个比较鲁钝的主意,尤其自然的法门是把信托定义成一个性质,指向一个new出来的callback,然后再把这么些callback传递进C++dll中,那样,在C#端有目标引用,保障了GC不会回收此callback:

当今可比流行C#与C++融合:C#做GUI,开发功用高,C++做运算,运行作用高,二者兼得。

typedef  void(__stdcall *Render)(double* data, BOOL* color);

据此,从C++
dll中回调函数给C#传递数据,必须由C#函数在运用完数据后(退出函数时)自己清空堆栈!所C++中的回调函数指针应该如下概念:

改为__stdcall的点子即可解决难题,注明如下:

1、如何在C#中有限支撑C++的函数指针

 

typedef  void(*Render)(double* data, BOOL* color);

 

回调函数的另一个注意事项是向C++ dll传递回调函数指针的难点

管理,以下来自网络的一段_cdecl和__stdcall的表达,必须铭记:

  

多年来一个类型是由此C++ 的
dll做高速运算,然后把结果数据通过Callback的主意回调给C#(界面部分),结果总是在C#中收取回调事件后就平昔挂掉(程序直接在并非提示的事态下退出,没有任何调试信息或者擢升)。

那即使没什么难题,可是经过SetRenderCallback()传入到C++的指针不受托管代码管理,在C#中觉得此指针对象未被其他代码引用,GC做垃圾回收时,将会把C#地面的空指针回收,导致C++不可能执行回调,出现“CallbackOnCollectedDelegate”错误:

其他注意事项:

  

typedef  void(*Render)(double* data, BOOL* color);

1、C#调用C++函数

但是C++与C#一定存在多少交互,C#与C++dll的数目交互一贯都是一个令人胃疼的标题。

那种气象是C++中经过Callback的不二法门调用C#代码,类似于C++做过一些拍卖后向C#出殡事件,事件能够教导数量(如处理后的数额)。则C++中定义函数指针的法门是:

纯属注意,delegate中的double[]数组一定要丰盛马尔斯halAs标记,标记为传送数组,而且必须指定传递的数额,若是不标记数量,则每一趟只传递一个数值,那几个题材折磨我很久才搞定!

那种情形用的可比多,数据流向可以是C#流向C++,通过参数将数据传递给C++(如:SetData(double[]
data));也足以是C++流向C#(如:GetData(double[] data))。

typedef void (_stdcall *CalibrationProgressCallback)(double percent);
  1. __cdecl

总结:

从调用方式看也有二种情景:

public void RenderCallback(string data, string color)
{
    // rendering
}

private EKFRenderCallback render;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    render = new EKFRenderCallback(RenderCallback);
    EKFLib.SetRenderCallback(render);
    EKFLib.Init();
}

以上是回调函数传递数组可能出现的气象,而正如所示,只传递一个参数的景观,甚至会在C#方莫明其妙的卡死:

C#用作委托,定义的函数被C++ callback:

2、__stdcall与_cdecl传递数据

按从右至左的相继压参数入栈,由被调用者把参数弹出栈。_stdcall是Pascal程序的缺省调用形式,平常用于Win32
Api中,切记:函数自己在脱离时清空堆栈,重回值在EAX中。  __stdcall调用约定在输出函数名前增加一个下划线前缀,前面加上一个“@”符号和其参数的字节数,格式为_functionname@number。如函数int
func(int a, double b)的修饰名是_func@12

1、C++中的回调函数必须用_stdcall标记,使用stdcall方式回调;

  1. __stdcall

如若有个函数向C++dll传递指针:

C#中如下传递被回调的函数:

public delegate void RenderCallback([MarshalAs(UnmanagedType.LPArray,
SizeConst =23)]double[] data, [MarshalAs(UnmanagedType.LPArray,
SizeConst = 23)]int[] colors);

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注