Reputation: 1622
How do I put a void pointer (aka. void*
or handle) into a COM VARIANT
-Type. The wrapper class _variant_t
converts it incorrectly to a boolean. But I need to put it in as pointer so that the COM-Marshaller for .NET recognizes it as IntPtr
.
One of the threads I've read, was this one at MSDN Social. They suggested a solution like this:
VARIANTARG Arg;
VariantInit(&Arg);
V_VT(&Arg) = VT_INT;
V_INT(&Arg) = (int)m_hWnd;
The problem with this solution is, that V_INT
(member intVal
) is a 32 bit integer and forces the pointers to be 32 bit pointers. In other words: I can't transfer 64 bit pointers. Is there any solution for that issue? Any other way to put it in an transfer it as 64 bit integer?
I've tested this by some code. Therefore I use a .NET method that receives any System.Object
and puts out its value and type.
public static void TakePtr(object ptr)
{
Console.WriteLine("Received a " + ptr.GetType() + " with value " + ptr);
}
My VARIANT
is filled for compatibility by v.llVal = 0; v.byref = myPointer;
so it should get compiled always correctly regarding 32/64 bit pointers.
Furthermore I need to set the variant type so that .NET mapps it to System.IntPtr
without casting. (Because for the real Assembly I can't change the code and don't want to wrapp it. That would add major complexity.).
System.IntPtr
backwards as VT_INT
, which forewards mapps to System.Int32
.VT_I8
mapps to System.Int64
but not System.IntPtr
.So what VARENUM
flag would specify a System.IntPtr
?
Upvotes: 4
Views: 2858
Reputation: 1104
I used VT_VOID and byref param without almost any problem. Almost because in some situations, .NET raises an MDA error about a bad conversion from native to a managed object (InvalidVariant error)
I couldn't check yet if the problem is when the byref is 0 because it doesn't appears always. :)
Upvotes: 0
Reputation: 11
I had a similar problem. When a 64 bit pointer is put into a PVOID variant type, it gets truncated/marshalled as a 32 bit pointer! So I then used the VT_I8 variant type and put the pointer into its llVal member and everything worked great.
Upvotes: 0
Reputation: 1622
At the moment I found a temporary solution to solve the full problem: To explicitly define the argument types when invoking a method, I will use an alternative invoke mechanism. Therefore I use the following method, which almost wrapps the arguments of the type invoke method, but additionally checks the types and casts them accordingly, so that a System.IntPtr
is recognized as such and not as System.Int32
or 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);
}
A call of this method could look like:
typeof(ExampleLib.HelloNET).InvokeMember(
null,
"TakePtr",
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod,
new Type[] { typeof(IntPtr) },
new object[] { 42 });
Finally this has to be used from COM to pass the pointer VARIANTs, which are filled as described: v.llVal = 0; v.byref = myPointer; v.vt = VT_INT;
/solved :-)
Upvotes: 2
Reputation: 283684
The PVOID byref;
member of variant looks helpful. But I'm not sure what type should be set to accompany it.
You could just use LONGLONG llVal
as Hans suggested, since even 32-bit platforms have the IntPtr(Int64)
constructor. Should work until someone invents 128-bit pointers.
Upvotes: 1
Reputation: 941545
That's not possible, VARIANT is an automation type. Automation does not like to deal with pointers to an unknown type, there's no safe way to dereference them. The only pointer types supported are IUnknown* and IDispatch*, interface pointers.
At best you could store it as a VT_I8 which marshals to a long. Which you can then cast to IntPtr.
Upvotes: 5