【问题标题】:How to handle 'Not enough quota is available to process this command' exception while closing an App after an extended period of time长时间关闭应用程序时如何处理“没有足够的配额可用于处理此命令”异常
【发布时间】:2019-10-03 10:08:23
【问题描述】:

我有一个可以打开第 3 方应用程序的软件。为了让他们相互通信,我有一个桥接解决方案(只是一个从不显示的假 wpf 窗口),它在彼此之间发送消息并使用简单数据管理 XML 文件。 一切正常,直到应用程序打开超过 10-15 分钟(它甚至可以处于空闲状态)然后我尝试关闭它 - 然后我的软件因“配额不足异常”而崩溃。 当我的软件崩溃时,第 3 方应用程序有时会保持打开状态并仍在运行。

过去 3 天我一直在寻找解决方案。没有任何帮助。 'catch Win32Exception' 没有捕捉到它。 更改虚拟内存中的页面文件无济于事。 它可以在具有各种规格的多个站点上重现 - 每个站点都有足够的资源。 内存/磁盘使用率根本不高。 第 3 方应用程序不会用消息淹没我的软件,它会在关闭时发送 1-2 条消息。 通信是同步的。 我试过查看 BaseCompatibilityPreferences.HandleDispatcherRequestProcessingFailure ,它发布在这里:https://github.com/dotnet/wpf/issues/137 - 无济于事。 指向 wpf 窗口的指针不为空。 我还检查了线程。

异常详情:

System.ComponentModel.Win32Exception
  HResult=0x80004005
  Message=Not enough quota is available to process this command
  Source=WindowsBase
  StackTrace:
   at MS.Win32.UnsafeNativeMethods.PostMessage(HandleRef hwnd, WindowMessage msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable`1 channelSet)
   at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam)
   at System.Windows.Interop.HwndTarget.OnWindowPosChanged(IntPtr lParam)
   at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)

我的应用只有在第 3 方应用打开超过 10-15 分钟后才会崩溃,而且几乎总是可以重现。我可以在 10 分钟内完成大量操作,关闭应用程序,一切正常,但我可以打开应用程序,15 分钟内什么也不做,关闭应用程序时我的软件崩溃了。

知道我可以使用什么调试策略来诊断问题吗? 我可以提供任何其他数据吗?

编辑:

  private bool StartApplication()
  {

     SharedMemory sharedMemory = SharedMemory.GetInstance();
     if (sharedMemory == null)
     {
        Int32 memorySize = Convert.ToInt32(Properties.Resources.SharedMemoryInitialSize);
        SharedMemory.CreateSharedMemory(memorySize);
        sharedMemory = SharedMemory.GetInstance();
     }

     if (sharedMemory == null)
     {
        SeeLogWrapper.Log(Panel3DStarterCommonUtils.Properties.Messages.MemoryManagerNotFound);
        Debug.Assert(false, Panel3DStarterCommonUtils.Properties.Messages.MemoryManagerNotFound);
        return false;
     }

     string initData = CreateInitDataForProcess();

     if (string.IsNullOrEmpty(initData))
        return false;

     Process proc = new Process();
     proc.StartInfo.FileName = StarterExePath;
     proc.StartInfo.Arguments = initData;

     StarterProc = proc;

     try
     {
        proc.Start();
        proc.WaitForExit();

        if (MessageWindow != null)
        {
           MessageWindow.Dispatcher.Invoke(() =>
           {
              MessageWindow.Close(); //This is usually where I get the not enough quota exception
           });
        }

        MessageWindow = null;
        proc.Close();

     }
     //catch phrases + return
  }


  private void Initialize(string A_starterPath, Iproc A_starterInterface, string A_loggerId, IntPtr A_parentHandle)
  {
     LoggerID = "";
     if (string.IsNullOrEmpty(A_loggerId) == false)
     {
        LoggerID = A_loggerId;
        Logger.Initialize(A_loggerId);
     }

     StarterExePath = A_starterPath;
     Panel3DStarterInterface = A_starterInterface;

     MainInstance = this;

     MessageWindow = new Window()
     {
        Width = 0,
        Height = 0,
        WindowStyle = WindowStyle.None,
        ShowInTaskbar = false,
        ShowActivated = false,
        WindowStartupLocation = WindowStartupLocation.Manual,
        Left = -2000,
        Top = -2000
     };

     MessageWindow.Closing += MessageWindowClosing;

     WindowHelper = new WindowInteropHelper(MessageWindow);
     WindowHelper.Owner = A_parentHandle;

     MessageWindow.Show();

     HwndSource messageWindowSource = HwndSource.FromVisual(MessageWindow) as HwndSource;
     messageWindowSource.AddHook(WndProc);
  }

【问题讨论】:

  • 请编辑您的问题并包含您的代码。
  • 可能不相关:在最后几行中创建 MessageWindow,显示它,然后获得 HwndSource。错误的。请参阅:stackoverflow.com/questions/37974502/…。您应该在 SourceInitialized 事件上执行此操作。由于您没有向我们展示完整的代码,例如在你调用 Initialize 的地方,你可能会遇到更多类似的问题。
  • 我建议通过删除不相关的代码来简化您的代码。创建最小的可重现示例也将帮助您理解问题。您还可以考虑添加更多标签,例如与互操作相关。
  • 关于捕获异常:youtube.com/watch?v=U92Ts53win4

标签: c# wpf .net-4.7.2


【解决方案1】:

我们的一个应用程序也遇到了同样的问题。经过大量研究和反复试验,问题归结为使用 Process.WaitForExit() 阻塞主线程。我们做了一个简单的改变来打开一个新线程并让它 WaitForExit() 代替。然后主线程进入一个循环等待该线程关闭:

/* ----- In the Main Thread ----- */
Thread t = new Thread(() => waitForProcessClose(newProcess));
t.Start();
while (t.IsAlive)
{
    Thread.Sleep(500);                         
}
/* ----- In the Main Thread ----- */


public static bool waitForProcessClose(Process handleToProcess)
{
    handleToProcess.WaitForExit();

    return true;
}

这样做似乎让主线程有机会在每个间隔清除它的消息队列,所以它不会再堆积和崩溃。

也许您的问题不涉及主线程,但也许您的一个线程正在以类似的方式阻塞消息队列。

【讨论】:

    猜你喜欢
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 1970-01-01
    • 2021-04-20
    相关资源
    最近更新 更多