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

而今较流行C#与C++融合:C#开GUI,开发效率高,C++做运算,运行效率高,二者兼顾得。

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

现比较流行C#与C++融合:C#开GUI,开发效率高,C++做运算,运行效率高,二者兼顾得。

但是C++与C#自然在数据交互,C#跟C++dll的数目交互从来都是一个叫人头疼的问题。

打调用方式看吗产生个别种情况:

1、C#调用C++函数

这种景象于是底比较多,数据流向可以是C#流向C++,通过参数将数据传递让C++(如:SetData(double[]
data));也得是C++流向C#(如:GetData(double[] data))。

2、C++ Callback

这种情景是C++中经Callback的办法调用C#代码,类似于C++做了一些甩卖后朝C#出殡事件,事件可以带数量(如处理后的数目)。则C++中定义函数指针的法是:

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

 

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

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

切注意,delegate中的double[]数组一定要是抬高MarshalAs标记,标记为传送数组,而且必须指定传递的数目,如果未记数量,则每次只有传递一个数值,这个问题折磨我挺遥远才为定!

其它注意事项:

1、如何在C#蒙维系C++的函数指针

回调函数的外一个注意事项是于C++ dll传递回调函数指针的题目

假设来只函数向C++dll传递指针:

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);

  

C#备受如下传递给回调的函数:

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

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

  

眼看则没什么问题,但是通过SetRenderCallback()传入到C++的指针不深受托管代码管理,在C#遭受以为这指针对象非给另外代码引用,GC做垃圾回收时,将会晤把C#地方的空指针回收,导致C++无法尽回调,出现“CallbackOnCollectedDelegate”错误:

对“MotionCapture!MotionCapture.EKFRenderCallback::Invoke”类型的曾垃圾回收委托进行了回调。这恐怕会见招应用程序崩溃、损坏以及多少丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会见再调用它们。

微软官网的例证是决定GC回收机制,这是独比笨的措施,更加自然的艺术是将信托定义成一个性,指向一个new出来的callback,然后再次将这callback传递进C++dll中,这样,在C#掬起对象引用,保证了GC不会见回收此callback:

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();
}

2、__stdcall与_cdecl传递数据

近来一个列是通过C++ 的
dll做高速运算,然后把结果数据通过Callback的方式回调给C#(界面部分),结果连在C#被接受回调事件后哪怕直挂掉(程序直接在毫不提示的气象下退出,没有其余调试信息或者提醒)。

造成问题之因由是,默认情况下,C++中如下概念的函数指针,默认是因_cdecl方式调用的:

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

这种情形下,参数堆栈是出于调用者(C++一侧)维护的,在C++调用之回调函数后,会管参数弹出堆栈而自由,导致C#读取数据时出现莫名其妙的荒谬。

上述是回调函数传递数组可能出现的状,而正如所示,只传递一个参数的事态,甚至会见于C#方莫名其妙的卡死:

typedef void (*CalibrationProgressCallback)(double percent);

改为__stdcall的方即可缓解问题,申明如下:

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

以下来自网络的同等段落_cdecl和__stdcall的说明,必须记住:

  1. __cdecl

就是所谓的C调用规则,按自右侧至左的顺序压参数入栈,由调用者把参数弹出栈。切记:对于传送参数的内存栈是出于调用者来维护的。返回值在EAX中。因此,对于象printf这样变参数的函数必须用这种规则。编译器在编译的早晚对这种调用规则的函数生成修饰名的饥饿时,仅在输出函数称作前增长一个下划线前缀,格式为_functionname。

  1. __stdcall

按自右边至左的各个压参数入栈,由为调用者把参数弹出栈。_stdcall是Pascal程序的缺省调用方式,通常用于Win32
Api中,切记:函数自己当离时清空堆栈,返回值在EAX中。  __stdcall调用约定以输出函数叫作前增长一个下划线前缀,后面长一个“@”符号和该参数的字节数,格式为[email protected]。如函数int
func(int a, double
b)的梳洗名是[email protected]

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

typedef void (_stdcall *CalibrationProgressCallback)(double percent);

总结:

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

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

2、如果是多次组,必须用 [MarshalAs(UnmanagedType.LPArray, SizeConst =
23)]记参数,指定为数组都标记数组长度;

3、C#方要说明一个变量,用来因于C++的回调指针函数,避免被C#回收掉。

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

http://www.bkjia.com/C\_jc/1261290.htmlwww.bkjia.comtruehttp://www.bkjia.com/C\_jc/1261290.htmlTechArticleC++通过Callback向C\#传递数据,
现在可比流行C#与C++融合:C#召开GUI,开发效率高,C++做运算,运行效率高,二者兼顾得。
但是C++与C#早晚有数据…

但是C++与C#毫无疑问是多少交互,C#与C++dll的数目交互从来都是一个让丁头疼的题材。

起调用方式看也时有发生少种植状态:

1、C#调用C++函数

这种状况用底比多,数据流向可以是C#流向C++,通过参数将数据传递给C++(如:SetData(double[]
data));也堪是C++流向C#(如:GetData(double[] data))。

2、C++ Callback

这种状态是C++中通过Callback的法子调用C#代码,类似于C++做了部分甩卖后为C#出殡事件,事件可以携带数量(如处理后底多少)。则C++中定义函数指针的措施是:

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

 

C#作为委托,定义之函数被C++ callback:

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

决注意,delegate中的double[]数组一定要是长MarshalAs标记,标记为传送数组,而且要指定传递的数码,如果不记数量,则每次就传递一个数值,这个问题折磨我杀长远才施定!

其余注意事项:

1、如何在C#备受保持C++的函数指针

掉调函数的其余一个注意事项是朝C++ dll传递回调函数指针的问题

若是发生只函数向C++dll传递指针:

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);

  

C#遭遇如下传递给回调的函数:

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

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

  

立虽然没什么问题,但是经过SetRenderCallback()传入到C++的指针不叫托管代码管理,在C#丁认为这个指针对象非让另外代码引用,GC做垃圾回收时,将见面把C#地面的空指针回收,导致C++无法推行回调,出现“CallbackOnCollectedDelegate”错误:

对“MotionCapture!MotionCapture.EKFRenderCallback::Invoke”类型的既垃圾回收委托开展了回调。这也许会见造成应用程序崩溃、损坏以及数量丢失。向非托管代码传递委托时,托管应用程序必须吃这些委托保持活动状态,直到确信不见面再度调用它们。

微软官网的事例是控制GC回收机制,这是只比较笨的点子,更加自然的主意是拿信托定义成一个特性,指向一个new出来的callback,然后再次管此callback传递进C++dll中,这样,在C#捧起目标引用,保证了GC不见面回收此callback:

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();
}

 

2、__stdcall与_cdecl传递数据

不久前一个类别是经C++ 的
dll做高速运算,然后将结果数据经过Callback的法门回调给C#(界面部分),结果总是在C#受到收回调事件后即便径直挂掉(程序直接在毫不提示的情下退出,没有其余调试信息或者提醒)。

造成问题的故是,默认情况下,C++中如下概念的函数指针,默认是为_cdecl方式调用的:

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

这种景象下,参数堆栈是出于调用者(C++一侧)维护的,在C++调用之回调函数后,会把参数弹出堆栈而自由,导致C#读取数据时出现莫名其妙的失实。

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

typedef void (*CalibrationProgressCallback)(double percent);

改为__stdcall的不二法门即可缓解问题,申明如下:

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

以下来自网络的同样截_cdecl和__stdcall的说,必须记住:

  1. __cdecl

便所谓的C调用规则,按自右侧至左的依次压参数入栈,由调用者把参数弹出栈。切记:对于传送参数的外存栈是出于调用者来保安的。返回值在EAX中。因此,对于象printf这样变参数的函数必须用这种规则。编译器在编译的时段对这种调用规则的函数生成修饰名的饥饿时,仅在输出函数称为前增长一个下划线前缀,格式为_functionname。

  1. __stdcall

依照自右边至左的相继压参数入栈,由为调用者把参数弹出栈。_stdcall是Pascal程序的缺省调用方式,通常用于Win32
Api中,切记:函数自己在离时清空堆栈,返回值在EAX中。  __stdcall调用约定以输出函数名为前增长一个下划线前缀,后面长一个“@”符号和夫参数的字节数,格式为_functionname@number。如函数int
func(int a, double b)的梳洗名是_func@12

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

typedef void (_stdcall *CalibrationProgressCallback)(double percent);

总结:

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

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

2、如果是累组,必须用 [MarshalAs(UnmanagedType.LPArray, SizeConst =
23)]号参数,指定为数组都标记数组长度;

3、C#方要说明一个变量,用来负于C++的回调指针函数,避免被C#回收掉。

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

相关文章