dotnet/wpf · error · FormatException

FormatException

Error message

FormatException

What it means

This VARIANT-to-managed conversion helper in NativeMethodsCLR explicitly rejects floating-point VARIANT types (VT_R4/VT_R8) when converting to a numeric (integral) destination, throwing an uninformative FormatException (the SR message is commented out). The conversion from float/double to the requested type is simply not implemented.

Solutions

  1. Convert the VARIANT to a type the helper supports, or perform the float/double conversion in your own code before/after marshaling
  2. Coerce the source data to an integer type (e.g. via VariantChangeType or explicit casting) before calling the converter
  3. Bypass this helper and read the VARIANT with Marshal/Convert.ChangeType directly for R4/R8 types
  4. Check the source COM property's declared type and adjust the consuming code's expected type

Example fix

// before
object value = NativeMethods.ConvertVariantToManaged(variant); // throws for VT_R8
// after
object value = variant.vt == (short)tagVT.VT_R8
    ? Convert.ChangeType(variant.dblVal, typeof(decimal))
    : NativeMethods.ConvertVariantToManaged(variant);
Defensive patterns

Strategy: type-guard

Validate before calling

if (variant.vt == (short)tagVT.VT_R4 || variant.vt == (short)tagVT.VT_R8) { /* convert manually */ }

Type guard

bool IsFloatingVariant(VARIANT v) => v.vt == (short)tagVT.VT_R4 || v.vt == (short)tagVT.VT_R8;

Try / catch

try { result = NativeMethods.ConvertVariant(variant); } catch (FormatException) { result = Convert.ChangeType(variant.fltVal != 0 ? variant.dblVal : variant.fltVal, typeof(decimal)); }

Prevention

When it happens

Trigger: Calling the NativeMethods VARIANT conversion API on a VARIANT whose vt is VT_R4 or VT_R8 — e.g. marshaling COM/automation property data that holds a float or double into an integral/string expected type.

Common situations: Reading COM/ActiveX/automation properties that are floats or doubles through this legacy conversion path; interop code written for integer VARIANTs suddenly receiving floating-point data after a COM component or data source change.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/6dc8d05fb674aec3. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/NativeMethodsCLR.cs:2112

                    if (vt == (int)tagVT.VT_I8) {
                        return (long)longVal;
                    }
                    else {
                        return (UInt64)longVal;
                    }
                }

                if (Byref) {
                    val = GetRefInt(val);
                }

                switch (vtType) {
                case (int)tagVT.VT_R4:
                case (int)tagVT.VT_R8:

                    // can I use unsafe here?
                    throw new FormatException(/*SR.GetString(SR.CannotConvertIntToFloat)*/);

                case (int)tagVT.VT_CY:
                    // internally currency is 8-byte int scaled by 10,000
                    longVal = ((uint)data1 & 0xffffffff) | ((uint)data2 << 32);
                    return new Decimal(longVal);
                case (int)tagVT.VT_DATE:
                    throw new FormatException(/*SR.GetString(SR.CannotConvertDoubleToDate)*/);

                case (int)tagVT.VT_BSTR:
                case (int)tagVT.VT_LPWSTR:
                    return Marshal.PtrToStringUni(val);

                case (int)tagVT.VT_LPSTR:
                    return Marshal.PtrToStringAnsi(val);

                case (int)tagVT.VT_DISPATCH:
                case (int)tagVT.VT_UNKNOWN:
                    {

View on GitHub (pinned to 81131a70a4)