You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Delphi调用NativeAOT编译的C# DLL方法?

调用NativeAOT编译的C# DLL(带UnmanagedCallersOnly特性)的正确方法

问题背景

使用NativeAOT编译带有UnmanagedCallersOnly特性的C#类库为NativeLibrary.dll后,通过Delphi调用时遇到两个问题:

  1. 动态加载DLL后,GetProcAddress无法获取Add函数指针;
  2. 静态引用DLL时,程序启动报错Application Error - The application was unable to start correctly (0xc000007b)。

解决步骤

一、修正NativeAOT编译配置

NativeAOT默认不会将标记UnmanagedCallersOnly的函数导出为DLL导出函数,且部分编译选项不适用于共享库场景,需修改项目文件:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <SelfContained>true</SelfContained>
    <PublishTrimmed>true</PublishTrimmed>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <Platforms>x64</Platforms>
    <!-- 关键:指定生成共享原生库,确保函数被导出 -->
    <NativeLib>Shared</NativeLib>
    <!-- 移除不适用于共享库的选项 -->
    <!-- <PublishSingleFile>true</PublishSingleFile> -->
    <!-- <PublishReadyToRun>true</PublishReadyToRun> -->
  </PropertyGroup>

</Project>

修改后重新发布DLL:

dotnet publish -c Release

二、Delphi调用的核心注意事项

  1. 平台匹配:必须使用x64架构的Delphi项目编译运行,否则会因32/64位不兼容触发0xc000007b错误;
  2. 调用约定:UnmanagedCallersOnly特性默认使用Cdecl调用约定,Delphi声明函数时必须显式指定cdecl;
  3. 内存管理:sumstring函数返回的是C#通过Marshal.StringToHGlobalAnsi分配的内存,Delphi调用后需调用LocalFree手动释放,避免内存泄漏。

具体调用示例

方式1:动态加载DLL

unit NativeLibraryDynamicCaller;

interface

uses
  Winapi.Windows, System.SysUtils;

type
  // 定义函数类型,匹配C#函数的参数、返回值和调用约定
  TAddFunc = function(a, b: Integer): Integer; cdecl;
  TWriteLineFunc = function(pString: PAnsiChar): Integer; cdecl;
  TSumStringFunc = function(first, second: PAnsiChar): PAnsiChar; cdecl;

procedure TestDynamicCall;

implementation

procedure TestDynamicCall;
var
  hLib: THandle;
  AddFunc: TAddFunc;
  WriteLineFunc: TWriteLineFunc;
  SumStringFunc: TSumStringFunc;
  ResultStr: PAnsiChar;
begin
  hLib := LoadLibrary('NativeLibrary.dll');
  if hLib = 0 then
  begin
    Writeln('加载DLL失败: ' + SysErrorMessage(GetLastError));
    Exit;
  end;

  try
    // 获取add函数地址并调用
    @AddFunc := GetProcAddress(hLib, 'add');
    if Assigned(AddFunc) then
      Writeln('add(2, 3) = ', AddFunc(2, 3))
    else
      Writeln('获取add函数地址失败: ' + SysErrorMessage(GetLastError));

    // 获取write_line函数地址并调用
    @WriteLineFunc := GetProcAddress(hLib, 'write_line');
    if Assigned(WriteLineFunc) then
      Writeln('write_line执行结果: ', WriteLineFunc(PAnsiChar(AnsiString('Hello from Delphi 动态调用!'))))
    else
      Writeln('获取write_line函数地址失败: ' + SysErrorMessage(GetLastError));

    // 获取sumstring函数地址并调用
    @SumStringFunc := GetProcAddress(hLib, 'sumstring');
    if Assigned(SumStringFunc) then
    begin
      ResultStr := SumStringFunc(PAnsiChar(AnsiString('Delphi ')), PAnsiChar(AnsiString('Dynamic')));
      try
        Writeln('sumstring结果: ', String(AnsiString(ResultStr)));
      finally
        // 释放C#分配的内存
        Winapi.Windows.LocalFree(HLOCAL(ResultStr));
      end;
    end
    else
      Writeln('获取sumstring函数地址失败: ' + SysErrorMessage(GetLastError));
  finally
    FreeLibrary(hLib);
  end;
end;

end.

方式2:静态链接DLL

unit NativeLibraryStaticCaller;

interface

uses
  System.SysUtils, Winapi.Windows;

// 直接声明外部函数,指定DLL路径和导出函数名(与C# EntryPoint一致)
function add(a, b: Integer): Integer; cdecl; external 'NativeLibrary.dll' name 'add';
function write_line(pString: PAnsiChar): Integer; cdecl; external 'NativeLibrary.dll' name 'write_line';
function sumstring(first, second: PAnsiChar): PAnsiChar; cdecl; external 'NativeLibrary.dll' name 'sumstring';

procedure TestStaticCall;

implementation

procedure TestStaticCall;
var
  ResultStr: PAnsiChar;
begin
  Writeln('add(5, 7) = ', add(5, 7));
  Writeln('write_line执行结果: ', write_line(PAnsiChar(AnsiString('Hello from Delphi 静态调用!'))));
  
  ResultStr := sumstring(PAnsiChar(AnsiString('Delphi ')), PAnsiChar(AnsiString('Static Link')));
  try
    Writeln('sumstring结果: ', String(AnsiString(ResultStr)));
  finally
    // 释放C#分配的内存
    Winapi.Windows.LocalFree(HLOCAL(ResultStr));
  end;
end;

end.

静态链接注意:确保NativeLibrary.dll位于Delphi程序的运行目录下,且项目编译目标为x64。

内容的提问来源于stack exchange,提问作者Greg Bishop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 19:05:25