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
- Convert the VARIANT to a type the helper supports, or perform the float/double conversion in your own code before/after marshaling
- Coerce the source data to an integer type (e.g. via VariantChangeType or explicit casting) before calling the converter
- Bypass this helper and read the VARIANT with Marshal/Convert.ChangeType directly for R4/R8 types
- 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
- Check the VARIANT's vt field before invoking the legacy converter
- Coerce floating-point VARIANTs to integral types via VariantChangeType first
- Prefer System.Convert/Marshal over this commented-out-message legacy path for R4/R8
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
- 0x80070057
- ArgumentNullException (buffer/sourceBuffer was IntPtr.Zero)
- Buffer address passed to GetText cannot be NULL.
- FILTER_E_UNKNOWNFORMAT
- InvalidOperationException
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)