前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >C++ 调用 C# - AOT 方案

C++ 调用 C# - AOT 方案

作者头像
jgrass
发布2024-12-25 18:37:33
发布2024-12-25 18:37:33
9200
代码可运行
举报
文章被收录于专栏:蔻丁杂记蔻丁杂记
运行总次数:0
代码可运行

一些 C# AOT 编译的笔记,整体感觉:简单很方便,但限制也很多,适用于比较单一的功能点。

跨语言调用C#代码的新方式-DllExport - InCerry - 博客园

在 .NET8 下,直接添加 <PublishAot>true</PublishAot> 就可以支持了, 需要注意一些限制,这里比较相关的是,不能使用 Newtonsoft.Json 做序列化,可以使用原生的 System.Text.Json 代替

更多说明和限制,可以看:

Native AOT deployment overview - .NET | Microsoft Learn

Create a single file for application deployment - .NET | Microsoft Learn

因为反射等特性受限,无法动态加载程序集,很多功能会用不了,如果是长期维护的项目,后续很有可能会遇到相关的坑。

比如 linq2db 就用不了

C# 端的 demo 代码

代码语言:javascript
代码运行次数:0
复制
[UnmanagedCallersOnly(EntryPoint = "Combine")]public static IntPtr Combine(IntPtr str, int num){    var name = Class1.Run();    string? myStr = Marshal.PtrToStringAnsi(str);    string result = $"{myStr} -- {num} -- {name}";    return Marshal.StringToHGlobalAnsi(result);}
[UnmanagedCallersOnly(EntryPoint = "Free")]public static void Free(IntPtr ptr){    Marshal.FreeHGlobal(ptr);}

csproj 设置

代码语言:javascript
代码运行次数:0
复制
<PropertyGroup>    <PublishAot>true</PublishAot>    <IsAotCompatible>true</IsAotCompatible>    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies></PropertyGroup>

CopyLocalLockFileAssemblies 是将依赖都输出到输出目录。

C# 编译结果:Accesser.dll 以及相关的依赖

C++ 端的 demo 代码

VisitByAot.h

代码语言:javascript
代码运行次数:0
复制
#pragma once
#define PathToLibrary L"SubFolder\\Accesser.dll"#define PathToLibraryFolder L"SubFolder"
#include <windows.h>#include <iostream>#include "PathHelper.h"
class VisitByAot{public:    int run();
private:    // 定义函数指针类型    typedef const char* (__stdcall* CombineFunc)(const char*, int);    typedef void(__stdcall* FreeFunc)(const char*);};

PathHelper.h 中的是一些辅助函数,见函数名知意。

PathToLibrary 和 PathToLibraryFolder 的配置,是为了将 C# 的 dll 放到 C++ 输出目录下的子文件夹中,让 DLL 更清晰一点。

VisitByAot.cpp

代码语言:javascript
代码运行次数:0
复制
#include "VisitByAot.h"
int VisitByAot::run(){    std::cout << "Hello World!\n";
    // 获取当前工作目录    std::wstring currentDirectory = PathHelper::GetExecutableDirectory();
    // 生成绝对路径    std::wstring pathToLibrary = PathHelper::CombinePath(currentDirectory, PathToLibrary);    std::wstring pathToDllFolder = PathHelper::CombinePath(currentDirectory, PathToLibraryFolder);
    // 设置 DLL 搜索路径    SetDllDirectory(pathToDllFolder.c_str());
    // 加载 DLL    HINSTANCE hinstLib = LoadLibrary(pathToLibrary.c_str());    if (hinstLib == NULL)    {        std::cerr << "Could not load the DLL." << std::endl;        return EXIT_FAILURE;    }
    // 获取 Combine 函数地址    CombineFunc Combine = (CombineFunc)GetProcAddress(hinstLib, "Combine");    if (Combine == NULL)    {        std::cerr << "Could not locate the function." << std::endl;        FreeLibrary(hinstLib);        return EXIT_FAILURE;    }
    // 获取 Free 函数地址    FreeFunc Free = (FreeFunc)GetProcAddress(hinstLib, "Free");    if (Free == NULL)    {        std::cerr << "Could not locate the Free function." << std::endl;        FreeLibrary(hinstLib);        return EXIT_FAILURE;    }
    // 调用函数    const char* result = Combine("example", 123);    if (result != NULL)    {        std::cout << "Result: " << result << std::endl;
        //// 使用 GlobalFree 释放内存        //GlobalFree((HGLOBAL)result);
        // 使用 C# 导出的 Free 方法释放        Free(result);    }    else    {        std::cerr << "Function returned NULL." << std::endl;    }
    // 释放 DLL    FreeLibrary(hinstLib);
    return EXIT_SUCCESS;
}

需要注意的是,需要 C++ 调用端释放不再使用的引用。

自动拷贝

可以看到,C# 端和 C++ 端是完全隔离的,C++ 端使用 LoadLibrary 的方式加载。所以就需要手动将 C# 的输出,拷贝到 C++ 端的调用目录。

以下是一个辅助脚本,供参考。

Terminal window

代码语言:javascript
代码运行次数:0
复制
cd /d "%~dp0"
set currentDir=%cd%echo current work dir: %currentDir%
set BuildRID=Debug
set AotPublishOutputPath=".\bin\%BuildRID%\net8.0\win-x64\publish"set CppUseTargetPath="..\x64\%BuildRID%\SubFolder"
rd /s /q %AotPublishOutputPath%
:: 生成 AOT 编译结果dotnet publish -p:NativeLib=Shared -r win-x64 -c %BuildRID%
if not exist "%CppUseTargetPath%" (    mkdir "%CppUseTargetPath%")xcopy "%AotPublishOutputPath%\*" "%CppUseTargetPath%\" /E /I /Y

原文链接: https://cloud.tencent.com/developer/article/2481586

本作品采用 「署名 4.0 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024年9月7日 |,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C# 端的 demo 代码
  • C++ 端的 demo 代码
  • 自动拷贝
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档