用AOT导出本地dll

本文介绍了如何使用C#通过UnmanagedCallersOnly和DllImport特性编译.NET应用并生成可以被C++或Delphi等语言调用的本地DLL,展示了对不同数据类型(如整数、字符串、自定义结构)的操作方法。
摘要由CSDN通过智能技术生成

记得之前在做医保接口时,经常要调一些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}";
    }
}

文章来源: https://blog.csdn.net/sD7O95O/article/details/135710045
版权声明: 本文为博主原创文章,遵循CC 4.0 BY-SA 知识共享协议,转载请附上原文出处链接和本声明。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值