c# - ICustomMarshaler::MarshalNativeToManaged,从 native dll “looses” 它返回的对象接收正确的数据

标签 c# pinvoke

我正在使用自己的编码(marshal)拆收器,该编码(marshal)拆收器实现 ICustomMarshaler 以与 native (非托管)dll C 函数配合使用。

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

(看起来与之前讨论的问题完全相同“C#:具有自定义编码器的对象在 PInvoke 调用后不包含数据”) C#: Object with custom marshaller not containing data after PInvoke call

简单类:

    [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 来处理它,而不是“其他方式”:)

最佳答案

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

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

如果我们像这个 hack(ref CMA) 一样使用 ref ;//顺便说一句,感谢之前的回答 在本例中,它是 hack(CMA**pp) 并且 .NET 确实使用我们从 MarshalNativeToManaged *pp = oo; 返回的指针

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

关于c# - ICustomMarshaler::MarshalNativeToManaged,从 native dll “looses” 它返回的对象接收正确的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10745225/

相关文章:

c# - 如何将多线程与 "for"或 "foreach"循环一起使用?

c# - 允许编辑一列但不允许编辑另一列

c# - 如何从 O(1) 中匹配特定条件的数组中选择随机元素

c# - Xamarin 工作室 : Add UIimageView to UIView

.net - 来自 NuGet 包的 DllImport native 依赖项在 net472 上不起作用,但在 netcoreapp2.2 上有效

c# - 多线程与datagridview

.net - 检测从 .NET 调用的调用 dll 的崩溃

c# - P/invoke System.ExecutionEngineException 将数组作为 ref/out 传递时

c# - 将 C# 结构传递给 C++ 非托管 DLL 返回不正确的结果

C#位图比较(PinvokeStackimbalance异常)