3

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

我读过的主题之一是 MSDN Social上的主题。他们提出了这样的解决方案:

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

这个解决方案的问题是,V_INT(member intVal) 是一个32 位整数并强制指针为 32 位指针。换句话说:我不能传输 64 位指针。有没有解决这个问题的办法?还有其他方法可以将其作为 64 位整数传输吗?

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

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

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

  • .NETSystem.IntPtr向后传输一个 as VT_INT,将映射前向System.Int32.
  • VT_I8映射到System.Int64但不是System.IntPtr

那么什么VARENUM标志会指定一个System.IntPtr

4

5 回答 5

5

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

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

于 2012-05-27T17:48:48.460 回答
2

目前我找到了解决全部问题的临时解决方案:为了在调用方法时显式定义参数类型,我将使用另一种调用机制。因此我使用以下方法,它几乎包装了类型调用方法的参数,但另外检查类型并相应地转换它们,以便 aSystem.IntPtr被识别为此类而不是System.Int32or 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);
}

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

typeof(ExampleLib.HelloNET).InvokeMember(
    null,
    "TakePtr",
    BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod,
    new Type[] { typeof(IntPtr) },
    new object[] { 42 });

最后,必须从 COM 使用它来传递指针 VARIANT,如所述填充:v.llVal = 0; v.byref = myPointer; v.vt = VT_INT;

/解决了 :-)

于 2012-05-29T14:07:55.920 回答
1

变体的PVOID byref;成员看起来很有帮助。但我不确定应该设置什么类型来伴随它。

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

于 2012-05-27T18:51:03.520 回答
0

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

于 2012-06-21T19:06:28.217 回答
0

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

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

于 2013-02-22T20:39:58.253 回答