2

我正在使用我自己的实现 ICustomMarshaler 的编组器来使用本机(非托管)dll C 函数。

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

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

简单的类:

    [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);

在 MarshalNativeToManaged 中,我确实看到了 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 而不是“其他方式”来处理它:)

4

2 回答 2

2

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

诀窍在于,在处理 Object 时,我们实际上是在处理指针(无论 C# 多么努力地试图隐藏这一事实)并且一步一步地: 1) hack(CMA* pCMA); 2) MarshalManagedToNative(void* pCMA) // C# 传递我们传递给 hack 的指针 3) Void* MarshalNativeToManaged(void *_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;

后来在 MarshalNativeToManaged

    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 :)

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

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

于 2012-05-25T14:45:30.670 回答
1

C# 语言要求您将参数声明为refout以允许它返回新值。使固定:

[DllImport("first.dll", EntryPoint = "hack")]
public static extern int hack(
    [In, Out]
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ZMarshal))]
    ref CMA cma);
于 2012-05-25T00:27:15.523 回答