【问题标题】:'System.ArithmeticException' while updating layout更新布局时出现“System.ArithmeticException”
【发布时间】:2014-08-14 14:56:35
【问题描述】:

这只发生在 x64 版本中

发生“System.ArithmeticException”类型的未处理异常 在 WindowsBase.dll 中 附加信息:溢出或下溢 算术运算。

在线崩溃

gridcontainer.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);

如果我删除该行,它会在没有可用源的情况下开始更新布局时立即崩溃

00000101  test        ecx,ecx 
00000103  je          0000000000000124 
00000105  lea         rdx,[rbp+18h] 
00000109  mov         rcx,qword ptr [rbp+70h] 
0000010d  call        0000000000216100 
00000112  cmp         byte ptr [rdi],0 

你知道如何预防吗?

例外:

    System.ArithmeticException: Overflow or underflow in the arithmetic operation.
   at System.Windows.UIElement.RoundLayoutSize(Size size, Double dpiScaleX, Double dpiScaleY)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.VirtualizingStackPanel.MeasureChild(IItemContainerGenerator& generator, IContainItemStorage& itemStorageProvider, IContainItemStorage& parentItemStorageProvider, Object& parentItem, Boolean& hasUniformOrAverageContainerSizeBeenSet, Double& computedUniformOrAverageContainerSize, Boolean& computedAreContainersUniformlySized, IList& items, Object& item, IList& children, Int32& childIndex, Boolean& visualOrderChanged, Boolean& isHorizontal, Size& childConstraint, Rect& viewport, VirtualizationCacheLength& cacheSize, VirtualizationCacheLengthUnit& cacheUnit, Boolean& foundFirstItemInViewport, Double& firstItemInViewportOffset, Size& stackPixelSize, Size& stackPixelSizeInViewport, Size& stackPixelSizeInCacheBeforeViewport, Size& stackPixelSizeInCacheAfterViewport, Size& stackLogicalSize, Size& stackLogicalSizeInViewport, Size& stackLogicalSizeInCacheBeforeViewport, Size& stackLogicalSizeInCacheAfterViewport, Boolean& mustDisableVirtualization, Boolean isBeforeFirstItem, Boolean isAfterFirstItem, Boolean isAfterLastItem, Boolean skipActualMeasure, Boolean skipGeneration, Boolean& hasBringIntoViewContainerBeenMeasured, Boolean& hasVirtualizingChildren)
   at System.Windows.Controls.VirtualizingStackPanel.MeasureOverrideImpl(Size constraint, Nullable`1& lastPageSafeOffset, List`1& previouslyMeasuredOffsets, Boolean remeasure)
   at System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
   at System.Windows.Controls.ItemsPresenter.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
   at System.Windows.Controls.ScrollContentPresenter.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
   at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
   at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
   at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.ScrollViewer.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Border.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Control.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.DockPanel.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
   at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
   at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
   at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.ContextLayoutManager.UpdateLayout()
   at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
   at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
   at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
   at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)

【问题讨论】:

  • 您的 UI 元素是超大还是超小?如果您启用 Break on Exceptions,您能否在 Locals 窗口中的堆栈跟踪的任何位置看到任何参数?
  • 在离崩溃最近的行设置断点。当它命中时,使用 Debug + Windows + Registers。右键单击并勾选“浮点”。 CTRL 寄存器应该是027F。右键单击并勾选“SSE”。 MXCSR 寄存器应为00001F80。如果他们没有这些值,那么您可以获得这些异常。您需要找到重新编程这些寄存器的外部代码,使用此调试窗口找到它。故意抛出异常并捕获它以恢复寄存器。
  • @HansPassant CTRL=1372MXCSR=000019A0。在此之前调用 _controlfp(_MCW_EM, _EM_INVALID); 可以为 x86 修复它,但不能为 x64 修复。它是一个改变 FPU 的 shell 上下文菜单扩展,但考虑到有多少,我需要修复它。
  • 卸载它,它可能会导致许多程序崩溃。
  • 那你当然需要推荐那些用户卸载它。或联系该外壳扩展的所有者以获得支持,这不是您的错误。在您的问题中没有提到您知道问题是由外壳扩展引起的,顺便说一句,这是非常糟糕的形式,真丢脸。

标签: c# wpf dispatcher


【解决方案1】:

我们偶尔会收到来自用户的此类报告。似乎问题与浮点单元损坏有关,如this question 中所述。不幸的是,尚不清楚如何在框架调用中处理此类错误。

UPD:我基于演示框架source code 创建了以下解决方法。使用单个调用初始化解决方法:UIHelper.InitWPFArithmeticExceptionWorkaround()

public static class UIHelper
{
    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int _fpreset();

    private static DispatcherOperationCallback _oldUpdateLayoutCallback;
    private static object UpdateLayoutCallback(object arg)
    {
        try
        {
            _oldUpdateLayoutCallback(arg);
            return null;
        }
        catch (System.Xaml.XamlParseException ex)
        {
            if (!(ex.InnerException is ArithmeticException))
            {
                throw;
            }
        }
        // Try to update layout second time after floating point unit reset
        _fpreset();
        _oldUpdateLayoutCallback(arg);
        return null;
    }

    public static bool InitWPFArithmeticExceptionWorkaround()
    {
        try
        {
            // Call fpreset early just to handle case with missed "msvcrt.dll" 
            // in future Windows versions
            _fpreset();
            Assembly assembly = typeof(System.Windows.UIElement).Assembly;
            Type managerType = assembly.GetType("System.Windows.ContextLayoutManager");
            if (managerType != null)
            {
                FieldInfo field = managerType.GetField("_updateCallback", BindingFlags.Static | BindingFlags.NonPublic);
                if (field != null)
                {
                    _oldUpdateLayoutCallback = field.GetValue(null) as DispatcherOperationCallback;
                    if (_oldUpdateLayoutCallback != null)
                    {
                        field.SetValue(null, new DispatcherOperationCallback(UpdateLayoutCallback));
                        return true;
                    }
                }
            }
        }
        catch
        {
        }
        return false;
    }
}

【讨论】:

    【解决方案2】:

    看起来您正在尝试绘制非常大或非常小的东西。 对于所有与绘图或用户控制值相关的计算值,请始终设置最小尺寸并在调用 draw/render/paint/invoke 之前检查它们。

    使用自定义绘图时,请确保在应用最大化和最小化时检查它

    另一个可能发生这种情况的地方是当您有一个包含太多列的数据网格时(如果总宽度超过 65k 像素)。我在数据网格上看到了这种情况,但我认为您应该确保所有控件都不会太大。

    【讨论】:

      猜你喜欢
      • 2015-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-29
      • 2011-08-09
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      相关资源
      最近更新 更多