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.