Com*_*inu 3 c# delphi pinvoke marshalling
我在使用C#导入的dll中遇到变量类型的问题.它是用面向对象的pascal编写的,它说它是用Delphi开发工具开发的.
在库的手册上,它说shortstring是一个打包的字节数组.第一个字节是长度,以下是exaclty 255个字节,带有我需要的字符串数据.
所以在C#中导入dll后我写道:
[return: MarshalAs(UnmanagedType.LPArray)]
Run Code Online (Sandbox Code Playgroud)
然后从dll调用函数:
public static extern byte[] xxxx();
Run Code Online (Sandbox Code Playgroud)
但我收到以下错误:
无法封送"返回值":无效的托管/非托管类型组合
另一方面,我尝试了以下内容:
[return: MarshalAs(UnmanagedType.SafeArray)]
Run Code Online (Sandbox Code Playgroud)
这次我得到错误:
排名18727的SafeArray已传递给期望排名为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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
此类型不是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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这表明DLL导出Delphi短字符串的设计很差.这表明该库的作者并未将其设计为与其他编译器兼容.这反过来表明函数可能使用默认的Delphi调用约定.registerMicrosoft工具支持哪些功能,哪些功能不受支持.如果我的预感是正确的,那么这个DLL不能直接使用.您需要编写一个适配器DLL,它暴露了一个更友好的互操作接口.