<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      跨語言調用C#代碼的新方式-DllExport

      簡介

      上一篇文章使用C#編寫一個.NET分析器文章發布以后,很多小伙伴都對最新的NativeAOT函數導出比較感興趣,今天故寫一篇短文來介紹一下如何使用它。

      在以前,如果有其他語言需要調用C#編寫的庫,那基本上只有通過各種RPC的方式(HTTP、GRPC)或者引入一層C++代理層的方式來調用。

      自從微軟開始積極開發和研究Native AOT以后,我們有了新的方式。那就是直接使用Native AOT函數導出的方式,其它語言(C++、Go、Java各種支持調用導出函數的語言)就可以直接調用C#導出的函數來使用C#庫。

      廢話不多說,讓我們開始嘗試。

      開始嘗試

      我們先來一個簡單的嘗試,就是使用C#編寫一個用于對兩個整數求和的Add方法,然后使用C語言調用它。

      1.首先我們需要創建一個新的類庫項目。這個大家都會了,可以直接使用命令行新建,也可以通過VS等IDE工具新建。

      dotnet new classlib -o CSharpDllExport
      

      2.為我們的項目加入Native AOT的支持,根據.NET的版本不同有不同的方式。

      • 如果你是.NET6則需要引入Microsoft.DotNet.ILCompiler這個Nuget包,需要指定為7.0.0-preview.7.22375.6,新版本的話只允許.NET7以上使用。更多詳情請看hez2010的博客 http://www.rzrgm.cn/hez2010/p/dotnet-with-native-aot.html

      • 如果是.NET7那么只需要在項目屬性中加入<PublishAot>true</PublishAot>即可,筆者直接使用的.NET7,所以如下配置就行。

      3.編寫一個靜態方法,并且為它打上UnmanagedCallersOnly特性,告訴編譯器我們需要將它作為函數導出,指定名稱為Add。

      using System.Runtime.InteropServices;
      
      namespace CSharpDllExport
      {
          public class DoSomethings
          {
              [UnmanagedCallersOnly(EntryPoint = "Add")]
              public static int Add(int a, int b)
              {
                  return a + b;
              }
          }
      }
      

      4.使用dotnet publish -p:NativeLib=Shared -r win-x64 -c Release命令發布共享庫。共享庫的擴展名在不同的操作系統上不一樣,如.dll.dylib.so。當然我們也可以發布靜態庫,只需要修改為-p:NativeLib=Static即可。

      5.使用DLL Export Viewer工具打開生成的.dll文件,查看函數導出是否成功,如下圖所示,我們成功的把ADD方法導出了,另外那個是默認導出用于Debugger的方法,我們可以忽略。工具下載鏈接放在文末。

      6.編寫一個C語言項目來測試一下我們的ADD方法是否可用。

      #define PathToLibrary "E:\\MyCode\\BlogCodes\\CSharp-Dll-Export\\CSharpDllExport\\CSharpDllExport\\bin\\Release\\net7.0\\win-x64\\publish\\CSharpDllExport.dll"
      
      // 導入必要的頭文件
      #include <windows.h>
      #include <stdlib.h>
      #include <stdio.h>
      
      int callAddFunc(char* path, char* funcName, int a, int b);
      
      int main()
      {
          // 檢查文件是否存在
          if (access(PathToLibrary, 0) == -1)
          {
              puts("沒有在指定的路徑找到庫文件");
              return 0;
          }
      
          // 計算兩個值的和
          int sum = callAddFunc(PathToLibrary, "Add", 2, 8);
          printf("兩個值的和是 %d \n", sum);
      }
      
      int callAddFunc(char* path, char* funcName, int firstInt, int secondInt)
      {
          // 調用 C# 共享庫的函數來計算兩個數的和
          HINSTANCE handle = LoadLibraryA(path);
      
          typedef int(*myFunc)(int, int);
          myFunc MyImport = (myFunc)GetProcAddress(handle, funcName);
      
          int result = MyImport(firstInt, secondInt);
      
          return result;
      }
      

      7.跑起來看看

      這樣我們就完成了一個C#函數導出的項目,并且通過C語言調用了C#導出的dll。同樣我們可以使用Go的syscall、Java的JNI、Python的ctypes來調用我們生成的dll,在這里就不再演示了。

      限制

      使用這種方法導出的函數同樣有一些限制,以下是在決定導出哪種托管方法時要考慮的一些限制:

      • 導出的方法必須是靜態方法。
      • 導出的方法只能接受或返回基元或值類型(即結構體,如果有引用類型,那必須像P/Invoke一樣封送所有引用類型參數)。
      • 無法從常規托管C#代碼調用導出的方法,必須走Native AOT,否則將引發異常。
      • 導出的方法不能使用常規的C#異常處理,它們應改為返回錯誤代碼。

      數據傳遞引用類型

      如果是引用類型的話注意需要傳遞指針或者序列化以后的結構體數據,比如我們編寫一個方法連接兩個string,那么C#這邊就應該這樣寫:

      [UnmanagedCallersOnly(EntryPoint = "ConcatString")]
      public static IntPtr ConcatString(IntPtr first, IntPtr second)
      {
          // 從指針轉換為string
          string my1String = Marshal.PtrToStringAnsi(first);
          string my2String = Marshal.PtrToStringAnsi(second);
          // 連接兩個string 
          string concat = my1String + my2String;
          // 將申請非托管內存string轉換為指針
          IntPtr concatPointer = Marshal.StringToHGlobalAnsi(concat);
          // 返回指針
          return concatPointer;
      }
      

      對應的C代碼也應該傳遞指針,如下所示:

      // 拼接兩個字符串
      char* result = callConcatStringFunc(PathToLibrary, "ConcatString", ".NET", " yyds");
      printf("拼接符串的結果為 %s \n", result);
      
      ....
      
      char* callConcatStringFunc(char* path, char* funcName, char* firstString, char* secondString)
      {
      
          HINSTANCE handle = LoadLibraryA(path);
          typedef char* (*myFunc)(char*, char*);
      
          myFunc MyImport = (myFunc)GetProcAddress(handle, funcName);
      
          // 傳遞指針并且返回指針
          char* result = MyImport(firstString, secondString);
      
          return result;
      }
      
      

      運行一下,結果如下所示:

      附錄

      posted @ 2022-09-16 09:48  InCerry  閱讀(8948)  評論(32)    收藏  舉報
      主站蜘蛛池模板: 国产女人在线视频| 中文字幕人妻少妇引诱隔壁| 偷拍精品一区二区三区| 国产va免费精品观看| 中文字幕无码不卡免费视频| 武强县| 亚洲av色精品一区二区| 精选国产av精选一区二区三区| 国产福利社区一区二区| 国产精品色哟哟成人av| 买车| 国产成人无码免费视频在线| 亚洲精品电影院| 亚洲国产成人AⅤ毛片奶水| 十八禁国产精品一区二区| 色窝窝免费一区二区三区| 一级做a爰片在线播放| 亚洲欧美中文日韩在线v日本| 999国产精品一区二区| 国产偷窥熟女高潮精品视频| 亚洲综合精品第一页| 97国产揄拍国产精品人妻| 亚洲熟女乱综合一区二区三区 | 成人午夜激情在线观看| 国产在线无码不卡播放| 国产真实乱对白精彩久久老熟妇女 | 国内精品人妻一区二区三区| 亚洲国产精品午夜福利| 无套后入极品美女少妇| 一本久道中文无码字幕av| 国产成人精品无码一区二区老年人| 亚洲av一本二本三本| 新版天堂资源中文8在线| 色吊丝二区三区中文写幕| 国产AV福利第一精品| 狠狠色丁香婷婷综合尤物| 日本久久久久亚洲中字幕| 亚洲AV日韩AV激情亚洲 | 亚洲精品成人老司机影视| 久久久精品94久久精品| 亚洲精品国产av一区二区|