从 Delphi 调用本机AOT C#动态链接库

6kkfgxo0  于 2023-02-19  发布在  C#
关注(0)|答案(1)|浏览(381)

NativeAOT提供了一个示例c#类,其中的方法标记为“UnmanagedCallersOnly”,我理解它是打算在非托管语言(如 Delphi )中使用的。提供的示例类是:

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.InteropServices;

namespace NativeLibrary
{
    public class Class1
    {
        [UnmanagedCallersOnly(EntryPoint = "add")]
        public static int Add(int a, int 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;
        }
    }
}

(from:Class1.cs
如何从 Delphi 调用方法(Add、WriteLine和sumstring)?

编辑2023年1月1日

我已经浏览了链接(也尝试了ChatGPT),但我仍然没有让它工作。我有一个从C#代码编译的NativeLibrary.DLL文件。使用dotPeek,我可以看到Add函数在DLL中。我使用的项目文件是:

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

  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <PublishSingleFile>true</PublishSingleFile>
    <SelfContained>true</SelfContained>
    <PublishTrimmed>true</PublishTrimmed>
    <PublishReadyToRun>true</PublishReadyToRun>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <Platforms>x64</Platforms>
  </PropertyGroup>

</Project>

我试过用两种不同的方法从 Delphi 调用Add函数。

方法1

unit TestClass;

interface

uses
  System.SysUtils,
  System.Classes, Windows;

const
  MY_DLL = 'NativeLibrary.dll';

type
  TAddFunc = function(a: Integer; b: Integer): Integer; stdcall;

  TTestClass = class
  public
    class function TestAdd(a: Integer; b: Integer): Integer; static;
  end;

implementation

class function TTestClass.TestAdd(a: Integer; b: Integer): Integer;
var
  Handle: HMODULE; // THandle
  Func: TAddFunc;
begin
  Handle := LoadLibrary(MY_DLL);
  try
    Func := GetProcAddress(Handle, 'Add');
    if Assigned(Func) then
    begin
      Result := Func(a, b);
    end;

  finally
    FreeLibrary(Handle);
  end;
end;

end.

调用此函数的方式为:

procedure TMainForm.Button1Click(Sender: TObject);
var
  StringFromDLL: string;
begin
  StringFromDLL := TTestClass.TestAdd(4,10);
  ShowMessage(StringFromDLL);
end;

应用程序运行,但是当调用TestAdd时,返回一个Handle,但是Func为nil,并且从未被赋值。

方法2

unit TestClass2;

interface

uses
  System.SysUtils,
  System.Classes, Windows;

const
  MY_DLL = 'NativeLibrary.dll';

  function Add(a: Integer; b: Integer): Integer; stdcall;
    external MY_DLL name 'Add';

type
  TTestClass2 = class
  public
    class function TestAdd(a: Integer; b: Integer): Integer; static;
  end;

implementation

class function TTestClass2.TestAdd(a: Integer; b: Integer): Integer;
begin
  Result:=Add(a,b);
end;

end.

当我使用这种技术调用TestClass2.TestAdd时,在应用程序启动时,我会得到一个提示阅读“应用程序错误-应用程序无法正确启动(0xc 000007 b)。单击OK关闭应用程序。”

jpfvwuh4

jpfvwuh41#

StringFromDLL := IntToStr(TTestClass.TestAdd(4,10));
  ShowMessage(StringFromDLL);

在拉撒路2.2.4(FPC 3.2.2)x86_64-win 64上进行测试
result
在Lazarus 2.2.0 FPC 3.2.2 i386-win32上,未加载“本机库. dll”(32位“测试应用程序”和64位“本机库. dll”不兼容)

相关问题