如何将void *放入COM VARIANT,以便通过COM-Interop将其作为IntPtr编组到.NET?

时间:2012-05-27 17:35:02

标签: c++ .net com marshalling variant

如何将void指针(又名。void*或句柄)放入COM VARIANT - Type中。包装类_variant_t将其错误地转换为布尔值。但是我需要将它作为指针放入,以便.NET的COM-Marshaller将其识别为IntPtr

我读过的其中一个主题是this one at MSDN Social。他们提出了这样的解决方案:

VARIANTARG Arg; 
VariantInit(&Arg);
V_VT(&Arg) = VT_INT;
V_INT(&Arg) = (int)m_hWnd; 

此解决方案的问题是,V_INT(成员intVal)是32 bit integer并强制指针为32位指针。换句话说:我无法传输64位指针。该问题是否有任何解决方案?还有其他任何方式将其转换为64位整数吗?

我已经通过一些代码对此进行了测试。因此,我使用.NET方法接收任何System.Object并输出其值和类型。

public static void TakePtr(object ptr)
{
    Console.WriteLine("Received a " + ptr.GetType() + " with value " + ptr);
}

我的VARIANT已填充v.llVal = 0; v.byref = myPointer;的兼容性,因此应始终正确编译32/64位指针。 此外,我需要设置变体类型,以便.NET将其映射到System.IntPtr 而不进行。 (因为对于真正的程序集,我无法更改代码,也不想包装它。这会增加主要的复杂性。)

  • .NET将System.IntPtr向后转移为VT_INT,将mapp转发为System.Int32
  • VT_I8 mapps System.Int64但不是System.IntPtr

那么VARENUM标志会指定System.IntPtr

5 个答案:

答案 0 :(得分:5)

这是不可能的,VARIANT是一种自动化类型。自动化不喜欢处理未知类型的指针,没有安全的方法来取消引用它们。支持的唯一指针类型是IUnknown *和IDispatch *,接口指针。

充其量你可以将它存储为VT_I8,它可以长时间编组。然后您可以将其转换为IntPtr。

答案 1 :(得分:2)

目前我找到了一个解决完整问题的临时解决方案:要在调用方法时显式定义参数类型,我将使用另一种调用机制。因此,我使用以下方法,它几乎包装类型invoke方法的参数,但另外检查类型并相应地转换它们,以便System.IntPtr被识别为这样,而不是System.Int32或{ {1}}。

System.Int64

此方法的调用可能如下所示:

public static object InvokeMember(this Type type, object obj, String name, System.Reflection.BindingFlags invokeAttr, Type[] argTypes, object[] argValues)
{
    if (argTypes.Length != argValues.Length) throw new InvalidOperationException("Mismatching count of types an parameters.");
    for (int i = 0; i < argTypes.Length; i++) if (argTypes[i] == typeof(IntPtr)) argValues[i] = new IntPtr(Convert.ToInt64(argValues[i]));
    return type.InvokeMember(name, invokeAttr, null, obj, argValues);
}

最后必须从COM中使用它来传递指针VARIANTs,它们按照描述填充:typeof(ExampleLib.HelloNET).InvokeMember( null, "TakePtr", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, new Type[] { typeof(IntPtr) }, new object[] { 42 });

/已解决: - )

答案 2 :(得分:1)

变种的PVOID byref;成员看起来很有帮助。但我不确定应该设置哪种类型。

你可以像Hans建议的那样使用LONGLONG llVal,因为即使是32位平台也有IntPtr(Int64)构造函数。应该工作,直到有人发明128位指针。

答案 3 :(得分:0)

我有类似的问题。将64位指针放入PVOID变体类型时, 它被截断/编组为32位指针! 所以我然后使用VT_I8变体类型并将指针放入其llVal成员中,一切都运行良好。

答案 4 :(得分:0)

我使用VT_VOID和byref param几乎没有任何问题。几乎是因为在某些情况下,.NET引发了关于从本机到托管对象的错误转换的MDA错误(InvalidVariant错误)

我无法检查问题是否是byref是0,因为它总是不会出现。 :)