VT_PTR
的VARIANT
。这会使默认的.NET封送处理器受到干扰,从而引发以下错误:
方法签名:“InvalidVariant”托管调试助手:“在从非托管的VARIANT转换为托管对象期间检测到无效的VARIANT。将无效的VARIANT传递给CLR可能会导致意外的异常、损坏或数据丢失。”
// (Unmanaged) IDL:
HRESULT getAttribute([in] BSTR strAttributeName, [retval, out] VARIANT* AttributeValue);
// C#:
[return: MarshalAs(UnmanagedType.Struct)]
object getAttribute([In, MarshalAs(UnmanagedType.BStr)] string strAttributeName);
有没有一种优雅的方法来绕过这样的马歇尔行为,在托管端获取底层未托管指针?
到目前为止,我所考虑/尝试的:
A custom marshaler:
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(IntPtrMarshaler))] object getAttribute([In, MarshalAs(UnmanagedType.BStr)] string strAttributeName);
I did implement
IntPtrMarshaler
, just to find the interop layer crashing the process even before any of myICustomMarshaler
methods gets called. Perhaps, theVARIANT*
argument type is not compatible with custom marshalers.Rewrite (or clone) the C# interface definition with
getAttribute
method redefined (like below) and do all the marshaling for outputVARIANT
manually:void getAttribute( [In, MarshalAs(UnmanagedType.BStr)], string strAttributeName, IntPtr result);
This doesn't seem nice (the interface itself has 30+ other methods). It'd also break existing, unrelated pieces of code which already make use of
getAttribute
without issues.Obtain an unmanaged method address of
getAttribute
from vtable (usingMarshal.GetComSlotForMethodInfo
etc), then do the manual invocation and marshaling against my own custom delegate type (usingMarshal.GetDelegateForFunctionPointer
etc).So far, I've taken this approach and it seem to work fine, but it feels as such an overkill for what should be a simple thing.
我是否忽略了其他可行的互操作选项?或者,也许有一种方法可以使 CustomMarshaler
在这里起作用吗?