如何使用 p/invoke 编组 Delphi 短字符串?

How can I marshal a Delphi short string using p/invoke?

我在 C# 中导入的 dll 中的变量类型有问题。它是用面向对象的 Pascal 编写的,它说它是用 Delphi 开发工具开发的。

在库的手册上说 shortstring 是一个打包的字节数组。第一个字节是长度,后面是 exaclty 255 个字节,其中包含我需要的字符串数据。

所以在用 C# 导入 dll 之后我写道:

[return: MarshalAs(UnmanagedType.LPArray)]

然后调用dll中的函数:

public static extern byte[] xxxx();

但我收到以下错误:

Cannot marshal 'return value': invalid managed/unmanaged type combination

另一方面,我尝试了以下方法:

[return: MarshalAs(UnmanagedType.SafeArray)]

这次我得到错误:

SafeArray of rank 18727 has been passed to a method expecting an array of rank 1

你能告诉我我做错了什么吗,首先这样从编译库中获取短字符串是正确的吗?

此致

我认为整理 Delphi 短字符串的最简洁方法是将其包装在结构中。

[StructLayout(LayoutKind.Sequential)]
public struct DelphiShortString
{
    private byte length;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=255)]
    private byte[] payload;

    public string Value 
    {
        get 
        { 
            return Encoding.Default.GetString(payload, 0, length); 
        }
        set 
        {
            length = (byte)Math.Min(value.Length, 255);
            payload = Encoding.Default.GetBytes(value.Substring(0, length));
        }
    }
}

此类型不可 blittable,因此不能用作函数 return 值。如果您可以控制 Delphi 代码,那么您可以确保不使用短字符串作为函数 return 类型。但是,我怀疑您无法控制它。在这种情况下,您需要结构的 blittable 版本。看起来像这样:

[StructLayout(LayoutKind.Sequential)]
public unsafe struct DelphiShortString
{
    private byte length;

    private fixed byte payload[255];

    public string Value 
    {
        get 
        {
            {
                byte[] bytes = new byte[length];
                fixed (byte* ptr = payload)
                {
                    Marshal.Copy((IntPtr)ptr, bytes, 0, length);
                }
                return Encoding.Default.GetString(bytes, 0, length); 
            }
        }
        set 
        {
            byte[] bytes = Encoding.Default.GetBytes(value);
            length = (byte)Math.Min(bytes.Length, 255);
            fixed (byte* ptr = payload)
            {
                Marshal.Copy(bytes, 0, (IntPtr)ptr, length);
            }
        }
    }
}

DLL 导出 Delphi 短字符串表明设计不当。这表明该库的作者并未将其设计为与其他编译器兼容。这反过来表明这些函数可能会使用默认的 Delphi 调用约定。这是 register 并且不受 Microsoft 工具支持。如果我的预感是正确的,那么这个 DLL 是不能直接使用的。您需要编写一个适配器 DLL 来公开一个更易于互操作的界面。