Marshalling variant properties in C#
This post is a continuation of the one covering WPD property retrieval in C#. That post explained how to marshal strings and the basic int properties. Handling other types such as VT_DATE and VT_BOOL is trickier so I'll try to cover them here.
VT_DATE
VT_DATE variants hold the date time value in a field of type double. So we'll need to update our C# PropVariant definition to include a double field.
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct PropVariant
{
[FieldOffset(0)]
public short variantType;
[FieldOffset(8)]
public IntPtr pointerValue;
[FieldOffset(8)]
public byte byteValue;
[FieldOffset(8)]
public long longValue;
[FieldOffset(8)]<br> public double dateValue;
}
Once we have a field that can hold the value, we need to convert it to something C# can understand. PROPVARIANTs are really OLE automation structures, so we can use the DateTime.FromOADate method to coerce our double into a DateTime object.
DateTime date = DateTime.FromOADate(pvValue.dateValue);
To convert from DateTime to the double value in the PropVariant, use DateTime.ToOADate.
VT_BOOL
VT_BOOL variants hold the bool value in a field of type short. So we'll need to update the C# PropVariant definition to include the short field.
[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct PropVariant
{
[FieldOffset(0)]
public short variantType;
[FieldOffset(8)]
public IntPtr pointerValue;
[FieldOffset(8)]
public byte byteValue;
[FieldOffset(8)]
public long longValue;
[FieldOffset(8)]
public double dateValue;
[FieldOffset(8)]<br> public short boolValue;
}
Once we have the short field, we can convert it to a bool using Convert.ToBoolean.
bool b = Convert.ToBoolean(pvValue.boolValue);
VT_CLSID
VT_CLSID variants hold the GUID value in a field of type CLSID* . The value itself is a pointer to a blob of memory allocated using CoTaskMemAlloc. Since we are dealing with a pointer, we can use the pointerValue field to access this.
We then use PtrToStructure (similar to how we handled LPWSTR) to marshal this pointer into a Guid we can use ourselves.
Guid guid = (Guid)Marshal.PtrToStructure(pvValue.pointerValue, typeof(Guid));
StructureToPtr can be used to marshal a Guid back into the PropVariant.
I'll update this post if I encounter other types that require special handling. Feel free to leave a comment on any that you come across as well.