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而不是"其他方式"来处理它:)
看起来我知道现在发生了什么。
诀窍在于,在处理对象时,我们实际上是在处理指针(无论 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# 语言要求将参数声明为 ref 或 out 以允许它返回新值。 修复:
[DllImport("first.dll", EntryPoint = "hack")]
public static extern int hack(
[In, Out]
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ZMarshal))]
ref CMA cma);