【问题标题】:C# P/Invoked function from BPL returns same pointer to Delphi record regardless of input无论输入如何,BPL 中的 C# P/Invoked 函数都返回指向 Delphi 记录的相同指针
【发布时间】:2022-01-07 13:19:24
【问题描述】:

我正在尝试使用我无法访问其代码的外部 BPL 包中的函数。

虽然我在 Delphi 中取得了成功,但在 C# 中,无论输入如何,我仍然获得相同的价值。

BPL在Delphi中的外部使用

type
  PRecord = ^TRecord;
  TRecord = packed record
      S: string;
      LW: LongWord;
  end;    

function GetValue(W : Word) : PRecord; external 'package.bpl' name '@Unit@Function$qqrus';

用不同的输入调用GetValue()返回不同的记录,这是正确的。

BPL 在 C# 中的外部使用

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TRecord
{
    public string S;
    public int LW;
}
        
[DllImport("package.bpl", EntryPoint = "@Unit@Function$qqrus", CharSet = CharSet.Unicode)]
static extern IntPtr GetValue(ushort number);
    
public static TRecord GetDelphiValue(ushort number)
{
    var ptr = GetValue(number);
    return (TRecord) Marshal.PtrToStructure(ptr, typeof(TRecord))
}

使用不同的输入调用GetDelphiValue() 总是返回相同的指针,因此返回结构。

我错过了什么?

【问题讨论】:

    标签: c# delphi


    【解决方案1】:
    function GetValue(W : Word) : PRecord; 
      external 'package.bpl' name '@Unit@Function$qqrus';
    

    这个函数使用Delphi的默认调用约定,即register。其他工具不支持此功能,因此无法从您的 C# 代码中调用此函数。

    您需要在您的 C# 代码和 Delphi 包之间放置一个 Delphi DLL。该Delphi DLL 将能够调用register 调用约定函数,并且可以导出具有stdcall 调用约定的函数供您的C# 代码调用。

    此外,您还有机会解决因使用 Delphi string 类型而导致的任何潜在问题,这也是 Delphi 私有的。

    对于它的价值,我非常怀疑该函数是否确实返回了指向记录的指针。我认为这更有可能是一个将记录作为varout 参数的过程。而且我确实认为很可能存在与该字符串的生命周期有关的问题。实际上,您不能期望使用没有关于其接口信息的二进制模块。

    【讨论】:

    • 这段代码在非 Delphi 工具中不能工作的另一个原因是它是 BPL 而不是 DLL。 BPL 是一种特殊类型的 DLL,在通过 LoadLibrary() 加载到内存后需要额外的初始化。正是出于这个原因,Delphi 有一个LoadPackage() 函数。其他工具没有。
    • 令我困惑的是,在 C# 中,我实际上看到了由该函数处理的数组中的真实记录,尽管仍然相同。我看到了那个 Delphi 函数的旧源代码,它实际上是返回一个指向记录的指针。我以为我可以省略 Delphi“中间”DLL,但显然我不能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 2020-04-29
    • 2013-04-10
    • 2021-06-25
    • 1970-01-01
    • 2012-02-02
    相关资源
    最近更新 更多