如何将 void* 放入 COM 变体中,以便它被 COM-Interop 编组为 IntPtr,到 .NET
How do I put a void* into a COM VARIANT so that it gets marshalled as IntPtr by COM-Interop to .NET?
如何放置一个空指针(又名。 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
(成员 intVal
)是一个 32 位整数,并强制指针为 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
,从而将mapps奖励到System.Int32
。 -
VT_I8
mappSystem.Int64
但不是System.IntPtr
。
那么VARENUM
标志会指定System.IntPtr
吗?
这是不可能的,VARIANT 是一种自动化类型。 自动化不喜欢处理指向未知类型的指针,没有安全的方法来取消引用它们。 唯一支持的指针类型是 IUnknown* 和 IDispatch*,即接口指针。
充其量你可以把它存储为一个VT_I8,编组到一个长。 然后,您可以将其转换为 IntPtr。
目前我找到了一个临时解决方案来解决整个问题: 为了在调用方法时显式定义参数类型,我将使用另一种调用机制。因此,我使用以下方法,它几乎破坏了类型invoke方法的参数,但另外检查类型并相应地强制转换它们,以便将System.IntPtr
识别为这样,而不是System.Int32
或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;
/已解决:-)
变体的PVOID byref;
成员看起来很有帮助。 但我不确定应该设置什么类型来伴随它。
你可以按照 Hans 的建议使用LONGLONG llVal
,因为即使是 32 位平台也有 IntPtr(Int64)
构造函数。 应该工作,直到有人发明 128 位指针。
我也有类似的问题。当将 64 位指针放入 PVOID 变体类型时,它被截断/编组为 32 位指针!因此,我随后使用了VT_I8变体类型并将指针放入其llVal成员中,一切正常。
我使用了VT_VOID和byref参数,几乎没有任何问题。几乎是因为在某些情况下,.NET 会引发有关从本机对象到托管对象的错误转换的 MDA 错误(InvalidVariant 错误)
我还无法检查问题是否出在 byref 为 0 时,因为它并不总是出现。 :)
- 将指向COM接口指针的指针从托管c++传递到.NET c#
- 合并 c 可执行文件、托管 COM dll 和 .Net GUI
- C# COM INTEROP in c++
- 在 .NET 中调用 COM 枚举器的正确方法是什么?
- 如何从com库中打印到主机,并从.NET代码召唤激活器
- 如何在Visual Studio 2012中创建Helloworld Com Interop
- 为使用C# /托管代码的无注册COM Interop设置DLL
- 如何从C++和通过COM互操作性访问.NET类的属性
- Com-interop:为什么tlibimp.exe生成只读属性
- 无法在.net中创建com对象实例
- C# COM-Interop dll for C++ COM dll 在 2 个解决方案之间不起作用
- 通过 .net 互操作类调试到 COM C++代码
- 如何将 void* 放入 COM 变体中,以便它被 COM-Interop 编组为 IntPtr,到 .NET
- 应用程序在 的协同创建实例期间挂起.基于 NET 的 COM 对象
- 一个C++客户端无法使用我们新的 COM 注册的 .NET .dll加载,另一个客户端可以正常工作
- CoCreateInstance:创建在 .NET 库中定义的 COM 实例
- 将本机dll或.NET程序集嵌入COM
- C++ VBA 浮点差异中的 .NET COM 组件
- 调试.NET应用程序创建的COM对象
- 用VB重写的c++ out-proc COM服务器.. NET和跨c++ EXE共享