You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 11:12:19