c# - 为什么编码对象不保留在 native 代码中修改的值?

标签 c# marshalling

我确信有一个简单的答案,但经过一些研究后我找不到它。我阅读并证明(除非我写的是错误的)通过在托管内存中分配的引用(或类)传递的自动编码结构由 native 代码正确读取和写入,但是一旦代码执行返回到托管层, native 代码中更改的值不会保留。这里有一个例子:

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
public class DirtyWordsCheckResult
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
    public string replace_string;
    public EnumDirtyWordsType dirty_type;

    public DirtyWordsCheckResult()
    {
        replace_string = new string(' ', 1024);
    }
}

public enum EnumDirtyWordsType
{
    kDirtyWordsTypeNormalAllowWords = 0,   // normal allow words
    kDirtyWordsTypeEvil = 1,               // illegal,can not be displayed
    kDirtyWordsTypeSensitive = 2,          // legal, but contain sensitive
}

public override EResult DirtyWordsFilter(string words, bool replace_sensitive, out DirtyWordsCheckResult check_result)
{
    check_result = new DirtyWordsCheckResult();
    var result = Utils.DirtyWordsFilter(utils_, words, replace_sensitive, check_result);
    return result;
}

native 函数 DirtyWordsFilter 确实正确获取分配的对象并且可以毫无问题地写入其中,但是不会保留值。

现在我知道我可以使用 Marshal.AllocHGlobal 来传递预分配的 IntPTR,因此我不是在寻找解决方案,我只是想了解为什么原始机制不起作用。

最佳答案

您使用的结构不是blittable。一个昂贵的词,意味着 native 布局与托管布局不同。字符串导致它。不仅仅是因为 CharSet,.NET 字符串看起来一点也不像 char[]。这需要 pinvoke 编码器在将指针传递给 native 代码可以使用的指针之前创建正确大小的副本。

但默认情况下它不会将修改后的结构复制回去。您必须将 [Out] 放在参数上才能使其改变主意。我们看不到 [DllImport] 声明,但它应该类似于:

[DllImport(...)]
private static extern EResult DirtyWordsFilter(..., [Out] DirtyWordsCheckResult check_result);  

pinvoke 编码器没有数据流的具体知识,即使您在声明中使用 refout(通常出现在结构声明中)也是如此。它仅看到参数通过引用传递,并假定 [In] 为默认值。通常是正确且最佳的猜测,此处不适用。 Fwiw,请注意 Pack=1 几乎永远不会正确,它需要匹配 native 代码中使用的包装,它的默认值也是 8。在这种特定情况下碰巧无关紧要。

关于c# - 为什么编码对象不保留在 native 代码中修改的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43762241/

相关文章:

C#通过Gmail账户发送邮件

c# - 从 MVC 5.1 应用程序创建 MVC 3 ASPXAUTH cookie - 单点登录

java - 如何从服务器URL接收Json数据?

c# - 将结构体数组从 C# 编码到 VC++

Apache Camel 中的 JAXB 编码

c# - Entity.Attributes 和 Entity.FormattedValues 之间有什么区别?

c# - 使用 C# 在 Excel 中使用预期的签名者、电子邮件等制作签名行

c# - C++中字符串的L前缀

c# - 编码结构数组指针的方法

c# - 模型通常如何在 ViewModel 对象之间共享?