.Net 8 生成Native库,让C/C++调用
前言
这篇博文是 在.Net 6 中生成Native库,让C/C++调用 更新,在.Net 8使用Native AOT生成动态库(Native原生)更方便,下面一起看看如何使用吧!1. 创建C#类库
# 1. 创建目录名,这个不是必须的,
mkdir NativeLibrary
# 2. 创建c#类库
dotnet new classlib
2. 测试源码(没有调整)
using System;
using System.Runtime.InteropServices;
namespace NativeLibrary
{
public class Class1
{
[UnmanagedCallersOnly(EntryPoint = "add")]
public static int Add(int a, int b)
{
//Console.WriteLine($"a={a} b={b}");
return a + b;
}
[UnmanagedCallersOnly(EntryPoint = "write_line")]
public static int WriteLine(IntPtr pString)
{
// The marshalling code is typically auto-generated by a custom tool in larger projects.
try
{
// UnmanagedCallersOnly methods only accept primitive arguments. The primitive arguments
// have to be marshalled manually if necessary.
string str = Marshal.PtrToStringAnsi(pString);
Console.WriteLine(str);
}
catch
{
// Exceptions escaping out of UnmanagedCallersOnly methods are treated as unhandled exceptions.
// The errors have to be marshalled manually if necessary.
return -1;
}
return 0;
}
[UnmanagedCallersOnly(EntryPoint = "sumstring")]
public static IntPtr sumstring(IntPtr first, IntPtr second)
{
// Parse strings from the passed pointers
string my1String = Marshal.PtrToStringAnsi(first);
string my2String = Marshal.PtrToStringAnsi(second);
// Concatenate strings
string sum = my1String + my2String;
// Assign pointer of the concatenated string to sumPointer
IntPtr sumPointer = Marshal.StringToHGlobalAnsi(sum);
// Return pointer
return sumPointer;
}
}
}
3. 修改项目工程文件(重要)
在.Net 8如果想使用Native AOT,在项目工程文件,添加以下配置:<PublishAot>true</PublishAot>
4. 生成Native动态库
# -r 后跟win-x64 / linux-x64,.Net AOT目前好像不支持交叉编译(x86->arm/loongarch/risc-v)
# 如果有跨cpu AOT的话,最好准备好一个对应的真实环境,在该环境中编译
dotnet publish -r win-x64 -c Release
在生成Native动态库的时候,实际上还是需要ILCompiler,在.Net 8中只是简化配置,改为自动获取ILCompiler了.
5. 在C++中调用C#
#include <iostream>
#include <string>
#include <Windows.h>
int main(int argc, char* argv[])
{
int a = 100;
int b = 50;
std::cout << "a=" << a << " b=" << b << std::endl;
HMODULE handle = LoadLibraryA("NativeLibrary.dll");
if (handle != NULL)
{
//为add声明函数指针Add
typedef int (*Add)(int, int);
//为write_line声明函数指针Write_line
typedef int (*Write_Line)(std::string str);
//为sumstring声明函数指针Sumstring
typedef char* (*SumString)(const char* first, const char* second);
Add sum = (Add)GetProcAddress(handle, "add");
std::cout << "sum=" << sum(a, b) << std::endl;
char first[] = "hello";
Write_Line write_line = (Write_Line)GetProcAddress(handle, "write_line");
std::string result = write_line(first) > -1 ? "ok" : "error";
std::cout << "result=" << result << std::endl;
char second[] = " world";
SumString sumstring = (SumString)GetProcAddress(handle, "sumstring");
std::cout << "sumstring=" << sumstring(first, second) << std::endl;
//句柄使用结束,要记得释放,避免句柄泄露
CloseHandle(handle);
}
std::cout << std::cin.get();
return 0;
}
这里不直接使用VS编译,简化操作.使用VS中的命令行工具.找到这个工具:
#使用cl编译c++文件 /std:c++17 指定使用c++ 17
cl main.cpp /std:c++17
#使用cl编译c文件, /std:c11 指定使用c11
cl c.c /std:c11
c++调用c# AOT后的动态库:
c语言调用c# AOT后的动态库:
最后对比一下AOT后的文件大小
这两年,.Net Native AOT进步还是很明显的,不过目前AOT还不支持Asp.Net Core MVC/API,只支持minimal(最小)API.还有就是Native AOT不支持32位程序.
秋风
2023-08-23