ICustomMarshaler::MarshalNativeToManaged,从本机dll接收正确的数据会“丢失”它

本文关键字:数据 丢失 MarshalNativeToManaged 本机 dll ICustomMarshaler | 更新日期: 2023-09-27 18:35:20

我正在使用我自己的封送拆收器来实现ICustomMarshaler与本机(非托管)dll C函数一起使用。

在函数 MarshalNativeToManaged 中,我确实看到了来自 dll 端的正确结果。问题是 MarshalNativeToManaged 返回的对象没有被"使用"。调用函数中带有 (In, Out) 参数的对象不会更改。

(看起来这与之前在这里讨论的问题完全相同"C#:具有自定义编组器的对象在 PInvoke 调用后不包含数据")C#:自定义封送处理器在调用后不包含数据的对象

简单类:

    [StructLayout(LayoutKind.Sequential)]
    class CMA { 
        public int a; 
        char b;
        public char get_b() { return b; }
    }

函数的签名如下所示:

[DllImport("first.dll", EntryPoint = "hack")]
    public static extern int hack([In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
                                            MarshalTypeRef=typeof(ZMarshal))] CMA cma);

在主要的某个地方,我这样称呼它:

int retcode = hack(cma);

在元帅本机到托管中,我确实看到了 dll 函数调用的正确结果。

    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        // everything is fine with pNativeData;
        // but let us even say I ignore it
        // and return the object in the following way:
        CMA cma = new CMA();
        cma.a = 999;
        return cma; // this will be lost. I mean cma object in the main will not be changed
    }

我在这里做错了什么?只是一个快速说明:我确实想知道如何使用CustomMarshaler而不是"其他方式"来处理它:)

ICustomMarshaler::MarshalNativeToManaged,从本机dll接收正确的数据会“丢失”它

好吧,

看起来我知道现在发生了什么。

诀窍在于,在处理对象时,我们实际上是在处理指针(无论 C# 多么努力地试图隐藏这一事实)并逐步处理:1) 黑客(CMA* pCMA);2) MarshalManagedToNative(void* pCMA)//C# 传递我们在这里传递的指针3) 无效* 元帅本机到托管(无效 *_some_PTR_to_memory_visible_to_managed_and_unmanaged_area)这是一个问题,.NET 如何处理此函数返回的这个 Void* ptr?如果不使用 ref,则无法更改 hack(cma) 中的对象。此指针根本不在任何地方使用。该函数可能无效。

    public class ZMarshal : System.Runtime.InteropServices.ICustomMarshaler
{
    static ZMarshal static_instance;
    object oo;
    public IntPtr MarshalManagedToNative(object o)
    {
        if (!(o is CMA))
           throw new System.Runtime.InteropServices.MarshalDirectiveException("Blabala");
        oo = o;

后来在元帅本地管理

    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        // some code that deals with the pNativeData really
        // but for our example only let us say we simply ignore what we just got
        // from the unmanaged world and simply change our object
        ((CMA)oo).a = 999;
        return oo; // this will not be lost now :)

如果我们像这个黑客一样使用参考(参考 CMA); 感谢之前的回答顺便说一句在这种情况下,它是hack(CMA**pp),.NET 确实使用我们从 MarshalNativeToManaged *pp = oo 返回的指针;

底线是我们要么必须保留指针并更改它指向的内存值,要么(使用 ref)将指针传递到指针(是的,老好**真的)并更改指针本身的值。

C# 语言要求将参数声明为 refout 以允许它返回新值。 修复:

[DllImport("first.dll", EntryPoint = "hack")]
public static extern int hack(
    [In, Out]
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ZMarshal))]
    ref CMA cma);