用AOT导出本地dll
记得之前在做医保接口时,经常要调一些C++或delphi写的本地dll(这些dll通常是用来读医保卡之类),这里简单介绍一下用C#生成本地可以直接调用dll,具体做法是通过UnmanagedCallersOnlyAttribute来完成。
dll项目文件如下
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <LangVersion>12</LangVersion> <PublishAot>true</PublishAot> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="8.0.0" /> </ItemGroup> </Project>
定义了几个简单的方法,如下:
using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; namespace classlib { //发布命令 dotnet publish /p:NativeLib=Shared --use-current-runtime public static class DllTest { [UnmanagedCallersOnly(EntryPoint = "int_add")] public static int Add(int a, int b) { return a + b; } [UnmanagedCallersOnly(EntryPoint = "string_add")] public static IntPtr StringTest(IntPtr ptr1, IntPtr ptr22) { var s = Marshal.PtrToStringUTF8(ptr1) + Marshal.PtrToStringUTF8(ptr22); return Marshal.StringToCoTaskMemUTF8(s); } [UnmanagedCallersOnly(EntryPoint = "get_doubles")] public static IntPtr StringTest() { return Marshal.UnsafeAddrOfPinnedArrayElement(new double[] { 1.1, 1.2 }, 0); } [UnmanagedCallersOnly(EntryPoint = "set_doubles", CallConvs = new[] { typeof(CallConvCdecl) })] public static double SetAll(IntPtr InItems, int InItemsLength) { var sum = 0d; for (int i = 0; i < InItemsLength; i++) { sum += Marshal.PtrToStructure<double>(InItems + i * Marshal.SizeOf<double>()); } return sum; } [UnmanagedCallersOnly(EntryPoint = "get_order")] public static IntPtr get_order() { var order = new Order { ID = 1, Name = "订单1" }; IntPtr structPtr = Marshal.AllocHGlobal(Marshal.SizeOf(order)); Marshal.StructureToPtr(order, structPtr, false); return structPtr; } } public struct Order { public int ID { get; set; } public string Name { get; set; } } }
然后在命令行中发布应用:
dotnet publish /p:NativeLib=Shared --use-current-runtime
现在创建测试的.NET项目,使用.NET中的P/Invocke来调用。把发布出来的dll,复制到当前项目,并设置文件“复制到输出目录”属性为始终复制。下面的代码就是分别调用上面方法的方式和用到的参数和类型 。
项目中分别测试了,int,double[],string,自定义结构等几种类型的进出。
// See https://aka.ms/new-console-template for more information using System.Reflection; using System.Runtime.InteropServices; using System.Text; Console.WriteLine(MyClass.int_add(1, 2)); Console.WriteLine(MyClass.string_add("abcd", "efg")); var resultPtr = MyClass.get_doubles(); var Items = new double[2]; for (int j = 0; j < 2; j++) { Items[j] = Marshal.PtrToStructure<double>(resultPtr + j * Marshal.SizeOf<double>()); Console.WriteLine(Items[j]); } var sum = MyClass.set_doubles(new double[] { 5.6, 6.7 }, 2); Console.WriteLine(sum); var orderP = MyClass.get_order(); var order = Marshal.PtrToStructure<Order>(orderP); Console.WriteLine(order); Console.ReadLine(); public class MyClass { // 定义非托管函数的签名 [DllImport("classlib.dll")] // 指定DLL文件名 public static extern int int_add(int a, int b); [DllImport("classlib.dll")] // 指定DLL文件名 public static extern string string_add(string a, string b); [DllImport("classlib.dll")] // 指定DLL文件名 public static extern IntPtr get_doubles(); [DllImport("classlib.dll")] // 指定DLL文件名 public static extern double set_doubles(double[] arr, int length); [DllImport("classlib.dll")] // 指定DLL文件名 public static extern IntPtr get_order(); } public struct Order { public int ID { get; set; } public string Name { get; set; } public override string ToString() { return $"Order ID:{ID},Name:{Name}"; } }
文章来源微信公众号
想要更快更方便的了解相关知识,可以关注微信公众号
****欢迎关注我的asp.net core系统课程****
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
2022-02-21 .net LTS3.1升5.0和LTS6.0隐蔽的坑
2022-02-21 应用内moniter