Working With Native Variant Pointers In C#

When interop-ing with C++ code that exposes changeable values as VARIANT pointers, it's much easier to work with objects on the managed side. Here's a helper class that wraps such a variant pointer into a managed class and exposes the variant value as object.

This class can be constructed with an IntPtr pointing to a VARIANT struct in memory. It then marshals the contained object to the _object member. If disposed, it writes the value of the _object member back to the wrapped VARIANT which can then be used in the unmanaged code again.

using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit, Size = 16)]
struct Variant {
    [FieldOffset(0)]
    public ushort vt;
    [FieldOffset(2)]
    public ushort wReserved1;
    [FieldOffset(4)]
    public ushort wReserved2;
    [FieldOffset(6)]
    public ushort wReserved3;
}
public class NativeVariantWrapper: IDisposable {
    Variant varStruct;
    object _object;
    IntPtr _variant;
    public NativeVariantWrapper(IntPtr variant) {
        _variant = variant;
        if (variant != IntPtr.Zero) {
            unsafe {
                void * variantPointer = variant.ToPointer();
                varStruct = * (Variant * ) variantPointer;
            }
            switch ((VarEnum) varStruct.vt) {
                case VarEnum.VT_EMPTY:
                    _object = String.Empty;
                    break;
                case VarEnum.VT_NULL:
                    _object = DBNull.Value;
                    break;
                default:
                    _object = Marshal.GetObjectForNativeVariant(variant);
                    break;
            }
        }
    }
    public object Object {
        get {
            return _object;
        }
        set {
            _object = value;
        }
    }
    public void SaveValue() {
        if (_variant != IntPtr.Zero) Marshal.GetNativeVariantForObject(_object, _variant);
    }
    public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        ~NativeVariantWrapper() {
            Dispose(false);
        }
    private bool disposed;
    protected virtual void Dispose(bool disposing) {
        if (!disposed) {
            if (disposing) {
                SaveValue();
            }
            disposed = true;
        }
    }
}
Next Recommended Reading Function Pointer in C#