最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

P/Invoke之C#調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL

2023-03-29 11:23 作者:百寶門  | 我要投稿


  1. 本編所涉及到的工具以及框架:

  2. 1、Visual Studio 2022

  3. 2、.net 6.0

P/Invok是什么?

  1. P/Invoke全稱為Platform Invoke(平臺(tái)調(diào)用),

  2. 其實(shí)際上就是一種函數(shù)調(diào)用機(jī)制,通過(guò)P/Invoke就可以實(shí)現(xiàn)調(diào)用非托管Dll中的函數(shù)。

在開(kāi)始之前,我們首先需要了解C#中有關(guān)托管與非托管的區(qū)別

  1. 托管(Collocation),即在程序運(yùn)行時(shí)會(huì)自動(dòng)釋放內(nèi)存;

  2. 非托管,即在程序運(yùn)行時(shí)不會(huì)自動(dòng)釋放內(nèi)存。

廢話不多說(shuō),直接實(shí)操

第一步:

  1. 打開(kāi)VS2022,新建一個(gè)C#控制臺(tái)應(yīng)用


2.右擊解決方案,添加一個(gè)新建項(xiàng),新建一個(gè)"動(dòng)態(tài)鏈接庫(kù)(DLL)",新建完之后需要右擊當(dāng)前項(xiàng)目--> 屬性 --> C/C++ --> 預(yù)編譯頭 --> 選擇"不使用編譯頭"


3. 在新建的DLL中我們新建一個(gè)頭文件,用于編寫我們的方法定義,然后再次新建一個(gè)C++文件,后綴以.c 結(jié)尾

第二步:

  1. 在我們DLL中的頭文件(Native.h)中定義相關(guān)的Test方法,具體代碼如下:



    1. #pragma once

    2. // 定義一些宏

    3. #ifdef __cplusplus

    4. #define EXTERN extern "C"

    5. #else

    6. #define EXTERN

    7. #endif

    8. #define CallingConvention _cdecl

    9. // 判斷用戶是否有輸入,從而定義區(qū)分使用dllimport還是dllexport

    10. #ifdef DLL_IMPORT

    11. #define HEAD EXTERN __declspec(dllimport)

    12. #else

    13. #define ?HEAD EXTERN __declspec(dllexport)

    14. #endif

    15. HEAD int CallingConvention Sum(int a, int b);

  2. 之后需要去實(shí)現(xiàn)頭文件中的方法,在Native.c中實(shí)現(xiàn),具體實(shí)現(xiàn)如下:



    1. #include "Native.h" // 導(dǎo)入頭部文件

    2. #include "stdio.h"

    3. HEAD int Add(int a, int b)

    4. {

    5. ? ?return a+b;

    6. }

  3. 在這些步驟做完后,可以嘗試生成解決方案,檢查是否報(bào)錯(cuò),沒(méi)有報(bào)錯(cuò)之后,將進(jìn)入項(xiàng)目文件中,檢查是否生成DLL (../x64/Debug)



第三步:

  1. 在這里之后,就可以在C#中去嘗試調(diào)用剛剛所聲明的方法,以便驗(yàn)證是否調(diào)用DLL成功,其具體實(shí)現(xiàn)如下:


    運(yùn)行結(jié)果為: 68,證明我們成功調(diào)用了DLL動(dòng)態(tài)鏈庫(kù)


    1. using System.Runtime.InteropServices;

    2. class Program

    3. {

    4. ? [DllImport

    5. (@"C:\My_project\C#_Call_C\CSharp_P_Invoke_Dll\x64\Debug\NativeDll.dll")]

    6. ? public static extern int Add(int a, int b);

    7. ? public static void Main(string[] args)

    8. ? {

    9. ? ? ? int sum = Add(23, 45);

    10. ? ? ? Console.WriteLine(sum);

    11. ? ? ? Console.ReadKey();

    12. ? }

    13. }

C#中通過(guò)P/Invoke調(diào)用DLL動(dòng)態(tài)鏈庫(kù)的流程

??通過(guò)上述一個(gè)簡(jiǎn)單的例子,我們大致了解到了在C#中通過(guò)P/Invoke調(diào)用DLL動(dòng)態(tài)鏈庫(kù)的流程,接下我們將對(duì)C#中的代碼塊做一些改動(dòng),便于維護(hù)

  1. 在改動(dòng)中我們將用到?NativeLibrary類中的一個(gè)方法,用于設(shè)置回調(diào),解析從程序集進(jìn)行的本機(jī)庫(kù)導(dǎo)入,并實(shí)現(xiàn)通過(guò)設(shè)置DLL的相對(duì)路徑進(jìn)行加載,其方法如下:



    1. public static void SetDllImportResolver

    2. (System.Reflection.Assembly assembly,

    3. System.Runtime.InteropServices.DllImportResolver resolver);

  2. 在使用這個(gè)方法前,先查看一下其參數(shù)


    a、assembly: 主要是獲取包含當(dāng)前正在執(zhí)行的代碼的程序集(不過(guò)多講解)
    b、resolber: 此參數(shù)是我們要注重實(shí)現(xiàn)的,我們可以通過(guò)查看他的元代碼,發(fā)現(xiàn)其實(shí)現(xiàn)的是一個(gè)委托,因此我們對(duì)其進(jìn)行實(shí)現(xiàn)。
    原始方法如下:


    1. public delegate IntPtr DllImportResolver

    2. (string libraryName, Assembly assembly, DllImportSearchPath? searchPath);

  3. 實(shí)現(xiàn)resolver方法:


    該方法主要是用于區(qū)分在加載DLL時(shí)不一定只能是設(shè)置絕對(duì)路徑,也可以使用相對(duì)路徑對(duì)其加載,本區(qū)域代碼是通過(guò)使用委托去實(shí)現(xiàn)加載相對(duì)路徑對(duì)其DLL加載,這樣做的好處是,便于以后需要更改DLL的路徑時(shí),只需要在這個(gè)方法中對(duì)其相對(duì)路徑進(jìn)行修改即可。


    1. const string NativeLib = "NativeDll.dll";

    2. static IntPtr DllImportResolver

    3. (string libraryName, Assembly assembly, DllImportSearchPath? searchPath)

    4. {

    5. ? ?string dll = Path.Combine(new DirectoryInfo(Environment.CurrentDirectory)

    6. ? .Parent.Parent.Parent.Parent.ToString(), "x64","Release", "NativeDll.dll");

    7. ? // 此處為Dll的路徑

    8. ? ?//Console.WriteLine(dll);

    9. ? ?return libraryName switch

    10. ? ?{

    11. ? ? ? ?NativeLib => NativeLibrary.Load(dll, assembly, searchPath),

    12. ? ? ? ?_ => IntPtr.Zero

    13. ? ?};

    14. }

  4. 更新C#中的代碼,其代碼如下:



    1. using System.Reflection;

    2. using System.Runtime.InteropServices;

    3. class Program

    4. {

    5. ? ?const string NativeLib = "NativeDll.dll";

    6. ? ?[DllImport(NativeLib)]

    7. ? ?public static extern int Add(int a, int b);

    8. ? ?static IntPtr DllImportResolver

    9. ? (string libraryName, Assembly assembly, DllImportSearchPath? searchPath)

    10. ? ?{

    11. ? ? ? ?string dll = Path.Combine(new DirectoryInfo(Environment.CurrentDirectory)

    12. ? ? ? ?.Parent.Parent.Parent.Parent.ToString(), "x64","Release", "NativeDll.dll");

    13. ? ? ? ?Console.WriteLine(dll);

    14. ? ? ? ?return libraryName switch

    15. ? ? ? ?{

    16. ? ? ? ? ? ?NativeLib => NativeLibrary.Load(dll, assembly, searchPath),

    17. ? ? ? ? ? ?_ => IntPtr.Zero

    18. ? ? ? ?};

    19. ? ?}

    20. ? ?public static void Main(string[] args)

    21. ? ?{

    22. ? ? ? ?NativeLibrary.SetDllImportResolver

    23. ? ? ? (Assembly.GetExecutingAssembly(), DllImportResolver);

    24. ? ? ? ?int sum = Add(23, 45);

    25. ? ? ? ?Console.WriteLine(sum);

    26. ? ? ? ?Console.ReadKey();

    27. ? ?}

    28. }

  5. 最后重新編譯,檢查其是否能順利編譯通過(guò),最終我們的到的結(jié)果為:?68

至此,我們就完成了一個(gè)簡(jiǎn)單的C#調(diào)用動(dòng)態(tài)鏈接庫(kù)的案例

??下面將通過(guò)一個(gè)具體實(shí)例,講述為什么要這樣做?(本實(shí)例通過(guò)從性能方面進(jìn)行對(duì)比)

  1. 在DLL中的頭文件中,加入如下代碼:



    1. HEAD void CBubbleSort(int* array, int length);

  2. 在.c文件中加入如下代碼:



    1. HEAD void CBubbleSort(int* array, int length)

    2. {

    3. ? ?int temp = 0;

    4. ? ?for (int i = 0; i < length; i++)

    5. ? ?{

    6. ? ? ? ?for (int j = i + 1; j < length; j++)

    7. ? ? ? ?{

    8. ? ? ? ? ? ?if (array[i] > array[j])

    9. ? ? ? ? ? ?{

    10. ? ? ? ? ? ? ? ?temp = array[i];

    11. ? ? ? ? ? ? ? ?array[i] = array[j];

    12. ? ? ? ? ? ? ? ?array[j] = temp;

    13. ? ? ? ? ? ?}

    14. ? ? ? ?}

    15. ? ?}

    16. }

  3. C#中的代碼修改:



    1. using System.Diagnostics;

    2. using System.Reflection;

    3. using System.Runtime.InteropServices;

    4. class Program

    5. {

    6. ? ?const string NativeLib = "NativeDll.dll";

    7. ? ?[DllImport(NativeLib)]

    8. ? ?public unsafe static extern void CBubbleSort(int* arr, int length);

    9. ? ?static IntPtr DllImportResolver

    10. ? (string libraryName, Assembly assembly, DllImportSearchPath? searchPath)

    11. ? ?{

    12. ? ? ? ?string dll = Path.Combine(new DirectoryInfo(Environment.CurrentDirectory)

    13. ? ? ? ?.Parent.Parent.Parent.Parent.ToString(), "x64", "Release", "NativeDll.dll");

    14. ? ? ? ?//Console.WriteLine(dll);

    15. ? ? ? ?return libraryName switch

    16. ? ? ? ?{

    17. ? ? ? ? ? ?NativeLib => NativeLibrary.Load(dll, assembly, searchPath),

    18. ? ? ? ? ? ?_ => IntPtr.Zero

    19. ? ? ? ?};

    20. ? ?}

    21. ? ?public unsafe static void Main(string[] args)

    22. ? ?{

    23. ? ? ? ?int num = 1000;

    24. ? ? ? ?int[] arr = new int[num];

    25. ? ? ? ?int[] cSharpResult = new int[num];

    26. ? ? ? ?//隨機(jī)生成num數(shù)量個(gè)(0-10000)的數(shù)字

    27. ? ? ? ?Random random = new Random();

    28. ? ? ? ?for (int i = 0; i < arr.Length; i++)

    29. ? ? ? ?{

    30. ? ? ? ? ? ?arr[i] = random.Next(10000);

    31. ? ? ? ?}

    32. ? ? ? ?//利用冒泡排序?qū)ζ鋽?shù)組進(jìn)行排序

    33. ? ? ? ?Stopwatch sw = Stopwatch.StartNew();

    34. ? ? ? ?Array.Copy(arr, cSharpResult, arr.Length);

    35. ? ? ? ?cSharpResult = BubbleSort(cSharpResult);

    36. ? ? ? ?Console.WriteLine($"\n C#實(shí)現(xiàn)排序所耗時(shí):{sw.ElapsedMilliseconds}ms\n");

    37. ? ? ? ?// 調(diào)用Dll中的冒泡排序算法

    38. ? ? ? ?NativeLibrary.SetDllImportResolver

    39. ? ? ? (Assembly.GetExecutingAssembly(), DllImportResolver);

    40. ? ? ? ?fixed (int* ptr = &arr[0])

    41. ? ? ? ?{

    42. ? ? ? ? ? ?sw.Restart();

    43. ? ? ? ? ? ?CBubbleSort(ptr, arr.Length);

    44. ? ? ? ?}

    45. ? ? ? ?Console.WriteLine($"\n C實(shí)現(xiàn)排序所耗時(shí):{sw.ElapsedMilliseconds}ms");

    46. ? ? ? ?Console.ReadKey();

    47. ? ?}

    48. ? ?//冒泡排序算法

    49. ? ?public static int[] BubbleSort(int[] array)

    50. ? ?{

    51. ? ? ? ?int temp = 0;

    52. ? ? ? ?for (int i = 0; i < array.Length; i++)

    53. ? ? ? ?{

    54. ? ? ? ? ? ?for (int j = i + 1; j < array.Length; j++)

    55. ? ? ? ? ? ?{

    56. ? ? ? ? ? ? ? ?if (array[i] > array[j])

    57. ? ? ? ? ? ? ? ?{

    58. ? ? ? ? ? ? ? ? ? ?temp = array[i];

    59. ? ? ? ? ? ? ? ? ? ?array[i] = array[j];

    60. ? ? ? ? ? ? ? ? ? ?array[j] = temp;

    61. ? ? ? ? ? ? ? ?}

    62. ? ? ? ? ? ?}

    63. ? ? ? ?}

    64. ? ? ? ?return array;

    65. ? ?}

    66. }

  4. 執(zhí)行結(jié)果:


    在實(shí)現(xiàn)本案例中,可能在編譯后,大家所看到的結(jié)果不是很出乎意料,但這只是一種案例,希望通過(guò)此案例的分析,能給大家?guī)?lái)一些意想不到的收獲叭。


    1. C#實(shí)現(xiàn)排序所耗時(shí): 130ms

    2. C實(shí)現(xiàn)排序所耗時(shí):3ms

最后

簡(jiǎn)單做一下總結(jié)叭,通過(guò)上述所描述的從第一步如何創(chuàng)建一個(gè)DLL到如何通過(guò)C#去調(diào)用的一個(gè)簡(jiǎn)單實(shí)例,也應(yīng)該能給正在查閱相關(guān)資料的你有所收獲,也希望能給在這方面有所研究的你有一些相關(guān)的啟發(fā),同時(shí)也希望能給目前對(duì)這方面毫無(wú)了解的你有一個(gè)更進(jìn)一步的學(xué)習(xí)。


原文地址:P/Invoke之C#調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL - 百寶門的博客 (baibaomen.com)


P/Invoke之C#調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
延长县| 昌黎县| 南漳县| 平泉县| 高碑店市| 井陉县| 盐源县| 衡东县| 靖安县| 蚌埠市| 运城市| 蓝田县| 济宁市| 虹口区| 黔南| 堆龙德庆县| 西昌市| 博爱县| 东丰县| 凤冈县| 上虞市| 林周县| 黑河市| 通江县| 辽中县| 德阳市| 曲周县| 襄樊市| 江永县| 峨边| 沂南县| 中牟县| 离岛区| 如东县| 崇左市| 石林| 普兰店市| 威海市| 天长市| 阳春市| 弥勒县|