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

时间:2015-06-01 08:42:55

标签: c# delphi pinvoke marshalling

我在使用C#导入的dll中遇到变量类型的问题。它是用面向对象的pascal编写的,它表示它是用Delphi开发工具开发的。

在库的手册中,它说shortstring是一个打包的字节数组。第一个字节是长度,以下是exaclty 255个字节,带有我需要的字符串数据。

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

[return: MarshalAs(UnmanagedType.LPArray)]

然后从dll调用函数:

public static extern byte[] xxxx();

但我收到以下错误:

  

无法封送“返回值”:无效的托管/非托管类型组合

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

[return: MarshalAs(UnmanagedType.SafeArray)]

这次我收到错误:

  

排名18727的SafeArray已传递给期望排名为1的数组的方法

你能告诉我我做错了什么,首先是正确的,从编译的库中得到一个短串?

此致

1 个答案:

答案 0 :(得分:8)

我认为编组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,因此不能用作函数返回值。如果您可以控制Delphi代码,那么您可以确保不使用短字符串作为函数返回类型。但是,我怀疑你无法控制它。在这种情况下,您需要一个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,它暴露了一个更友好的互操作接口。

相关问题