C#中使用LibraryImport处理原生字符串输出参数的正确方式
问题描述
我有一个原生函数GetFooString(LPStr str, int strLen),它会将字符串写入调用时提供的缓冲区并指定其大小。此前使用DllImport搭配StringBuilder可实现调用,代码如下:
[DllImport("foo.dll", EntryPoint = "GetFooString")] public static extern void GetFooString( [MarshalAs(UnmanagedType.LPStr, SizeParamIndex = 1)] StringBuilder pBuff, ushort wBuffLen);
官方文档提到,StringBuilder在P/Invoke中存在隐式内存分配,会影响性能,建议手动封送。现在想改用基于源代码生成的LibraryImport替代DllImport,但发现相同的MarshallAsAttribute下StringBuilder不被支持。请问如何正确使用LibraryImport调用该函数?能否写入栈分配的Span<char>并后续转换为字符串或进行其他Span操作?
解决方案
基于Simon Mourier的思路,我编写了一个P/Invoke包装函数,将Span<char>缓冲区转换为字节缓冲区传入,再将ANSI字符转换为UTF16。目前微软暂未支持P/Invoke字符串输出缓冲区场景,另一种方案是自定义封送器,但因文档不足且使用复杂,故选择包装方案。代码如下:
[LibraryImport("foo.dll", EntryPoint = "GetFooString")] private static partial void GetFooStringImpl( Span<byte> pBuff, ushort wBuffLen); public static void GetFooString(Span<char> pBuff) { Span<byte> span = MemoryMarshal.Cast<char, byte>(pBuff)[(pBuff.Length - 1)..]; GetFooStringImpl(span, (ushort)(pBuff.Length + 1)); Encoding.ASCII.GetChars(span[..^1], pBuff); }
内容的提问来源于stack exchange,提问作者patvax
相关产品推荐
相关产品推荐

