激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C++通過Callback向C#傳遞數據的方法

C++通過Callback向C#傳遞數據的方法

2022-02-17 16:21特務小強 C/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++中定義函數指針的方式是:

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

C#作為委托,定義的函數被C++ callback:

?
1
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傳遞指針:

?
1
2
3
4
5
6
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#中如下傳遞被回調的函數:

?
1
2
3
4
5
6
7
8
9
10
11
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
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#方莫名其妙的卡死:

?
1
typedef void (*CalibrationProgressCallback)(double percent);

改為__stdcall的方式即可解決問題,申明如下:

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

以下來自網絡的一段_cdecl和__stdcall的解釋,必須牢記:

1. __cdecl

即所謂的C調用規則,按從右至左的順序壓參數入棧,由調用者把參數彈出棧。切記:對于傳送參數的內存棧是由調用者來維護的。返回值在EAX中。因此,對于象printf這樣變參數的函數必須用這種規則。編譯器在編譯的時候對這種調用規則的函數生成修飾名的餓時候,僅在輸出函數名前加上一個下劃線前綴,格式為_functionname。

2. __stdcall

按從右至左的順序壓參數入棧,由被調用者把參數彈出棧。_stdcall是Pascal程序的缺省調用方式,通常用于Win32 Api中,切記:函數自己在退出時清空堆棧,返回值在EAX中。  __stdcall調用約定在輸出函數名前加上一個下劃線前綴,后面加上一個“@”符號和其參數的字節數,格式為_functionname@number。如函數int func(int a, double b)的修飾名是_func@12

所以,從C++ dll中回調函數給C#傳遞數據,必須由C#函數在使用完數據后(退出函數時)自己清空堆棧!所C++中的回調函數指針應該如下定義:

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

總結:

C++通過callback向C#傳遞數據必須注意以下幾點:

1、C++中的回調函數必須用_stdcall標記,使用stdcall方式回調;

2、如果是數組,必須用 [MarshalAs(UnmanagedType.LPArray, SizeConst = 23)]標記參數,指定為數組且標記數組長度;

3、C#方必須申明一個變量,用來指向C++的回調指針函數,避免被C#回收掉。

以上這篇C++通過Callback向C#傳遞數據的方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://www.cnblogs.com/tewuapple/archive/2018/01/05/8205893.html

延伸 · 閱讀

精彩推薦
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
主站蜘蛛池模板: 49vvv| 99re热精品视频 | 久久精品之 | 国产又粗又爽又深的免费视频 | 国产精品岛国久久久久久久 | 精品久久久一二三区播放播放播放视频 | 国产精品久久久久久久久久久天堂 | 亚洲爱爱网站 | 国产一区毛片 | 久久久久久久久久久亚洲 | 一区二区三区视频在线 | h网站在线观看 | 免费黄色在线电影 | 爱看久久| 特级西西444www大精品视频免费看 | 永久久久| 日本在线不卡一区二区 | chinesexxxx刘婷hd| 一级在线观看 | 国产麻豆交换夫妇 | 久草在线观看福利 | 国产精品岛国久久久久久 | 日韩毛片一区二区三区 | 九色新网址 | 久久久视频免费观看 | 精品一区二区三区在线观看国产 | 精品一二三区视频 | 久久精品国产亚洲7777 | 国产精品成人一区二区三区电影毛片 | 久久久久久久久久网 | 91看片. | 草草免费视频 | xxxx8| 色婷婷久久久久久 | 久久久日韩精品一区二区三区 | 国产一区二区国产 | 国产成人精品一区在线播放 | 美女视频免费一区二区 | 久久影院国产精品 | 看91| 亚洲成人自拍电影 |