日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#委托实现C++ Dll中的回调函数

發布時間:2023/12/20 C# 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#委托实现C++ Dll中的回调函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

from:https://blog.csdn.net/ferrycooper/article/details/63261771

很多的Dll都是CC++寫的,那么如果C#想要調用Dll中的函數怎么辦,尤其是Dll函數其中一個參數是函數指針的,即里面有回掉函數的用C#怎么實現?

C中的回掉函數在C#中有中特殊的處理方式叫委托,即要實現的回掉函數委托給另一個和它返回值類型以及函數參數類型、數量一樣的方法來實現。


一、新建項目Visual C++??Win32控制臺應用,工程名為CcreateDll,解決方案名為Dlltest

?

確定—>下一步

?

?

應用程序類型選Dll>完成

?

新建頭文件Ccreate.h,聲明導出函數,其中API_DECLSPEC?int?CallPFun(addP?callback,?inta,?int?b)?第一個參數為函數指針,內容如下:

?

[cpp]?view plain?copy
  • #pragma?once??
  • ??
  • #ifndef?Ccreate_H_??
  • #define?Ccreatel_H_??
  • ??
  • typedef??int(*addP)(int,?int);??
  • ??
  • #ifdef?_EXPORTING???
  • #define?API_DECLSPEC?extern?"C"?_declspec(dllexport)???
  • #else???
  • #define?API_DECLSPEC??extern?"C"?_declspec(dllimport)???
  • #endif??
  • ??
  • API_DECLSPEC?int?Add(int?plus1,?int?plus2);??
  • API_DECLSPEC?int?mulp(int?plus1,?int?plus2);??
  • API_DECLSPEC?int?CallPFun(addP?callback,?int?a,?int?b);??
  • ??
  • #endif??
  • 頭文件有了,在CcreateDll.cppinclude頭文件,并實現相關函數。Ccreate.cpp如下

    ?

    [cpp]?view plain?copy
  • //?CcreateDll.cpp?:?定義?DLL?應用程序的導出函數。??
  • //??
  • ??
  • #include?"stdafx.h"??
  • #include?<iostream>???
  • #include?"Ccreate.h"??
  • ??
  • using?namespace?std;??
  • ??
  • int?Add(int?plus1,?int?plus2)??
  • {??
  • ????int?add_result?=?plus1?+?plus2;??
  • ????return?add_result;??
  • }??
  • int?mulp(int?plus1,?int?plus2)??
  • {??
  • ????int?add_result?=?plus1?*?plus2;??
  • ????return?add_result;??
  • }??
  • ??
  • int?CallPFun(int(*callback)(int,?int),?int?a,?int?b)?{??
  • ????return?callback(a,?b);??
  • }??

  • 函數CallPFun實際就是傳入函數指針及其參數,內部直接調用函數指針。

    Release模式下生成CcreateDll工程

    ?

    生成成功后在解決方案目錄的Release文件夾下會看到生成的CcreateDll.dll,使用Dll查看工具可以看到三個導出函數。

    ?

    二、新建C#控制臺工程CsharpCallDll實現調用Dll并使用委托實現回掉。

    ?

    ?

    CsharpCallDll工程Program.cs如下:

    ?

    [csharp]?view plain?copy
  • using?System;??
  • using?System.Collections.Generic;??
  • using?System.Linq;??
  • using?System.Text;??
  • using?System.Threading.Tasks;??
  • using?System.Runtime.InteropServices;??
  • ??
  • namespace?CsharpCallDll??
  • {??
  • ????public?class?Program??
  • ????{??
  • ????????[UnmanagedFunctionPointer(CallingConvention.Cdecl)]??
  • ????????public?delegate?int?DllcallBack(int?num1,?int?num2);??
  • ??
  • ????????[DllImport(@"../../../Release/CcreateDll.dll",?EntryPoint?=?"Add",?SetLastError?=?true,?CharSet?=?CharSet.Ansi,?ExactSpelling?=?false,?CallingConvention?=?CallingConvention.Cdecl)]??
  • ????????extern?static?int?Add(int?a,?int?b);??
  • ??
  • ????????[DllImport(@"../../../Release/CcreateDll.dll",?EntryPoint?=?"mulp",?SetLastError?=?true,?CharSet?=?CharSet.Ansi,?ExactSpelling?=?false,?CallingConvention?=?CallingConvention.Cdecl)]??
  • ????????extern?static?int?mulp(int?a,?int?b);??
  • ??
  • ????????[DllImport(@"../../../Release/CcreateDll.dll",?EntryPoint?=?"CallPFun",?SetLastError?=?true,?CharSet?=?CharSet.Ansi,?ExactSpelling?=?false,?CallingConvention?=?CallingConvention.Cdecl)]??
  • ????????public?extern?static?int?CallPFun(DllcallBack?pfun,?int?a,?int?b);??
  • ????????//[MarshalAs(UnmanagedType.FunctionPtr)]??
  • ????????static?void?Main(string[]?args)??
  • ????????{??
  • ????????????int?a?=?3;??
  • ????????????int?b?=?4;??
  • ????????????int?result;??
  • ????????????DllcallBack?mycall;??
  • ????????????mycall?=?new?DllcallBack(Program.CsharpCall);??
  • ????????????result?=?Add(a,?b);??
  • ????????????Console.WriteLine("Add?返回{0}",?result);??
  • ????????????result?=?mulp(a,?b);??
  • ????????????Console.WriteLine("mulp?返回{0}",?result);??
  • ????????????result?=?CallPFun(mycall,?a,?b);??
  • ????????????Console.WriteLine("dll回掉?返回{0}",?result);??
  • ????????????Console.ReadLine();??
  • ????????}??
  • ??
  • ????????public?static?int?CsharpCall(int?a,?int?b)??
  • ????????{??
  • ????????????return?a?*?a?+?b?*?b;??
  • ????????}??
  • ????}??
  • }??

  • ????

    通過DllImport導入相應的Dll并聲明Dll中的導出函數,CcreateDll.dll中導出函數CallPFun有三個參數,原型為

    ?

    [cpp]?view plain?copy
  • int?CallPFun(int(*callback)(int,?int),?int?a,?int?b)?{??
  • ????return?callback(a,?b);??
  • ???}??
  • ???

    參數1為一個帶兩個int參數的返回值為int型的函數指針,這里聲明一個委托

    public?delegate?int?DllcallBack(int?num1,?intnum2);

    該委托可以指向任何帶兩個int型參數且返回值為int型的方法,這里的CsharpCall方法可以看作是回掉函數的實現。

    ?

    [csharp]?view plain?copy
  • public?static?int?CsharpCall(int?a,?int?b)??
  • ???{??
  • ????????????return?a?*?a?+?b?*?b;??
  • ???}??
  • ???

    通過????????DllcallBack?mycall;

    ???????????mycall =?new?DllcallBack(Program.CsharpCall);

    ??把實際要完成的工作交給CsharpCall去完成。

    ????運行CsharpCallDll,結果如下:

    ??

    ?

    是不是實現了C#委托實現回掉

    ?

    最后還有如果聲明委托時在public delegate int DllcallBack(int num1, int num2);上面沒有[UnmanagedFunctionPointer(CallingConvention.Cdecl)]這一句,那么運行時將會出現System.AccessViolationException異常,如下

    ?

    ?

    還有Dll調用約定,CallingConvention.有五種調用方式

    CallingConvention= CallingConvention.StdCall

    CallingConvention= CallingConvention.Cdecl

    CallingConvention= CallingConvention.FastCall

    CallingConvention= CallingConvention.ThisCall

    CallingConvention= CallingConvention.Winapi

    到底使用哪種方式,網上有說"Bydefault, C and C++ use cdecl - but marshalling uses stdcall to match theWindows API."即默認情況下,CC++使用的Cdecl調用,但編組使用StdCall調用匹配的Windows API,對于FastCallThisCallWinapi這三種調用方式尚不清楚。

    這里將CallingConvention= CallingConvention.Cdecl改成CallingConvention = CallingConvention.StdCall,重新運行導致堆棧不對稱如下

    ?



    總結

    以上是生活随笔為你收集整理的C#委托实现C++ Dll中的回调函数的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。