winforms DeactivateMdiChild中异常的不可捕获系统,NullReferenceException

kse8i1jr  于 2023-02-24  发布在  其他
关注(0)|答案(1)|浏览(118)

它是关于C#/.NET的Windows.Forms应用程序。
我遇到了一些奇怪的行为.NET -有一个奇怪的System.NullReferenceException异常在.NET代码内,它是不可能捕捉和处理这样的异常。
以下是例外详细信息:

System.NullReferenceException was unhandled
  Message=Object reference not set to an instance of an object.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.Form.DeactivateMdiChild()
       at System.Windows.Forms.Form.WmMdiActivate(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DefMDIChildProc(IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.Form.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
  InnerException:

我试着用.NET 2.0和.NET 4.0 CLR运行我的应用程序-它的工作方式是一样的,它会引发无法捕捉的未处理异常。
我尝试使用VS 2012和VS 2019进行调试-在同一位置报告异常,无法捕获或找出异常原因。
当运行我的应用的 * 发布版本 * 时,它在这里报告未处理的异常:

************** Exception Text **************
System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Windows.Forms.Form.DeactivateMdiChild()
   at System.Windows.Forms.Form.WmMdiActivate(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

下面是导致该异常的方法:

/// <returns>Returns true if we can close current workspace</returns>
private bool closeWorkspace()
{
    Trace.WriteLineIf(TrcLvl.TraceInfo, TrcLvl.TraceInfo ? string.Format("= FormMain.closeWorkspace( {0}: {1} queries )",  
        (this.document.DefaultWorkspace != null ? this.document.DefaultWorkspace.Name : "(null)"), this.MdiChildren.Length) : "");

    this.isClosingWorkspace = true;
    try
    {
        Trace.WriteLineIf(TrcLvl.TraceInfo, TrcLvl.TraceInfo ? string.Format(" - CloseWs: check if some of queries might be busy...") : "");
        foreach (Form mdi in this.MdiChildren)
        {
            if (!(mdi is FormQuery)) continue; // currently only FormQuery can be here, so this check is reserved for future version of app
            FormQuery frmQ = (FormQuery)mdi;
            if (frmQ.CheckIfBusy())
            {
                MessageBox.Show(Languages.TranslateFmt("Query[{0}] is busy!", frmQ.Query.Title),
                    Languages.Translate("Fail to Switch Workspace"), MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return false;
            }
        }
        Trace.WriteLineIf(TrcLvl.TraceInfo, TrcLvl.TraceInfo ? string.Format(" - CloseWs: detach queries...") : "");
        List<FormQuery> toClose = new List<FormQuery>();
        foreach (Form mdi in this.MdiChildren)
        {
            if (!(mdi is FormQuery)) continue; 
            FormQuery frmQ = (FormQuery)mdi;
            frmQ.DetachQuery();
            toClose.Add(frmQ);
        }
        Trace.WriteLineIf(TrcLvl.TraceInfo, TrcLvl.TraceInfo ? string.Format(" - CloseWs: closing queries ({0} items)...", toClose.Count) : "");
        for (int i = 0; i < toClose.Count; i++)
        {
            FormQuery frmQ = toClose[i];
            Trace.WriteLineIf(TrcLvl.TraceInfo, TrcLvl.TraceInfo ? string.Format("  - CloseWs#{0}: closing [{1}]...", i, frmQ.Text) : "");
            toClose[i] = null;
            try
            {
                frmQ.Hide();
                //frmQ.Close(); 

                Thread.Sleep(100);
                frmQ.Dispose();
                Thread.Sleep(100);
            }
            catch (Exception exc)
            {
                Trace.WriteLineIf(TrcLvl.TraceError, TrcLvl.TraceError ? string.Format("  !!! CloseWs[#{0}].ERR.{1}\n\t{2}",
                    i, ErrorUtils.FormatErrorMsg(exc), ErrorUtils.FormatStackTrace(exc)) : "");
            }
        }
    }
    finally { this.isClosingWorkspace = false; }
    return true;
}

在VS调试器中,此处弹出异常(在FormQuery.Designer.cs中):

protected override void Dispose(bool disposing)
{
    try
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing); // <-- unhandled exception pops up here!
    }
    catch (System.Exception exc) // <-- this DOES NOT WORK AT ALL!
    {
        System.Diagnostics.Trace.WriteLineIf(TrcLvl.TraceError, TrcLvl.TraceError ? string.Format("  !!! FormQuery.Designer.ERR.{0}\n\t{1}",
            XService.Utils.ErrorUtils.FormatErrorMsg(exc), XService.Utils.ErrorUtils.FormatStackTrace(exc)) : "");
    }
}

正如你所看到的-我试图把try-catch语句在那里,但.NET是无法赶上它!
以下是跟踪日志中的图片:

20200709,104115.32 T1  = FormMain.closeWorkspace( Test 1: 6 queries )
20200709,104115.32 T1   - CloseWs: check if some of queries might be busy...
20200709,104115.32 T1   - CloseWs: detach queries...
20200709,104115.32 T1  Query[#6/Query_2_Errors].ReleaseData()
20200709,104115.32 T1  Query[#7/Query_4_Ini_prm].ReleaseData()
20200709,104115.32 T1  Query[#8/Query_5_func].ReleaseData()
20200709,104115.32 T1  Query[#9/Query_6_app].ReleaseData()
20200709,104115.32 T1  Query[#10/Query_7_OrderInfo].ReleaseData()
20200709,104115.32 T1  Query[#11/Query_8_Bom].ReleaseData()
20200709,104115.32 T1   - CloseWs: closing queries (6 items)...
20200709,104115.32 T1    - CloseWs#0: closing [Query_2_Errors]... <-- here it pops up "unhandled exception" UI
20200709,104131.89 T1  --- FormQuery[Query_4_Ini_prm].Activated()
20200709,104131.89 T1  --- FormQuery[Query_4_Ini_prm].ReportActive()
20200709,104131.89 T1  = FormMain.ReportActive( Query_4_Ini_prm )
20200709,104131.90 T1  = FormMain_MdiChildActivate --- #18 ---
20200709,104132.00 T1    - CloseWs#1: closing [Query_4_Ini_prm]...
20200709,104132.01 T1  --- FormQuery[Query_8_Bom].Activated()
20200709,104132.01 T1  --- FormQuery[Query_8_Bom].ReportActive()
20200709,104132.01 T1  = FormMain.ReportActive( Query_8_Bom )
20200709,104132.02 T1  = FormMain_MdiChildActivate --- #19 ---
20200709,104132.22 T1    - CloseWs#2: closing [Query_5_func]...

下面是异常发生时VS中显示的堆栈跟踪:

System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.Dispose(bool disposing) + 0x19 bytes 
System.Windows.Forms.dll!System.Windows.Forms.Form.Dispose(bool disposing) + 0x247 bytes    
> Query.exe!ABC.App.QueryNet.FormQuery.Dispose(bool disposing) Line 22 + 0x13 bytes C#
System.dll!System.ComponentModel.Component.Dispose() + 0x19 bytes   
Query.exe!ABC.App.QueryNet.FormMain.closeWorkspace() Line 1230 + 0x15 bytes C#
Query.exe!ABC.App.QueryNet.FormMain.mmiOpenWs_Click(object sender, System.EventArgs e) Line 1141 + 0xd bytes    C#
System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.RaiseEvent(object key, System.EventArgs e) + 0x5e bytes 
System.Windows.Forms.dll!System.Windows.Forms.ToolStripMenuItem.OnClick(System.EventArgs e) + 0x53 bytes    
System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.HandleClick(System.EventArgs e) + 0xa2 bytes    
System.Windows.Forms.dll!System.Windows.Forms.ToolStripItem.ProcessMnemonic(char charCode) + 0xe bytes  
System.Windows.Forms.dll!System.Windows.Forms.ToolStripDropDown.ProcessDialogChar(char charCode) + 0x51 bytes   
System.Windows.Forms.dll!System.Windows.Forms.Control.PreProcessMessage(ref System.Windows.Forms.Message msg) + 0x1b1 bytes 
System.Windows.Forms.dll!System.Windows.Forms.Control.PreProcessControlMessageInternal(System.Windows.Forms.Control target, ref System.Windows.Forms.Message msg) + 0x14e bytes 
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.PreTranslateMessage(ref System.Windows.Forms.NativeMethods.MSG msg) + 0x1f9 bytes   
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason, int pvLoopData) + 0x599 bytes  
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) + 0x578 bytes  
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x65 bytes    
Query.exe!ABC.App.QueryNet.Program.Main(string[] args) Line 48 + 0x28 bytes C#
[Native to Managed Transition]  
[Managed to Native Transition]  
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x47 bytes  
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x9b bytes    
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x4d bytes

奇怪的是,工作区中有6个MDI子窗口,但它只为其中一个MDI查尔兹报告未处理的异常(总是在关闭第一个或第二个MDI子项时,从不关闭其他MDI子项)。所有其他MDI子项都已正常关闭。我尝试更改MDI子项的顺序(通过其内容)-不可能,它总是报告第一个或第二个MDI子关闭的未处理异常,而不管内容如何。
我在互联网上搜索了这个-什么都没有找到。我只看到了一个可能使用ActiveX的原因的参考,但在这里不是这样的。我的FormQuery非常简单,只有-面板,SplitContainer,TextBox,DataGridView,StatusStrip,一个ContextMenu -没有更多。所以,它没有使用任何ActiveX组件...
我试着用Reflector分析.NET的内部结构-我看不出任何可能的原因。
还尝试使用Hide()+Close(),Hide()+Dispose(),尝试添加线程。closeWorkspace()方法中的Sleep(100)-不可能,它无论如何都会报告异常,而且它是完全不可目录!:-(
我完全没有主意了-怎么弄清楚为什么会有异常?!你能给我建议吗-我还可以检查什么来找出异常的原因并修复它?
谢谢你。

fkaflof6

fkaflof61#

这是一个低级错误,MDI的致命组合,性能布局()和Layout事件处理程序,因为MDI必须先将子窗口从Maximized状态还原,然后才能将另一个子窗口置于最前面,这会触发窗体布局引擎重新布局运行Layout事件处理程序的窗体。这会在第二个窗体尝试与第一个窗体匹配时导致嵌套代码执行冲突。此错误的简单解决方法是确保活动MDI子窗口在关闭或显示新窗口之前未最大化。

//Set the active child in normal window state
if (this.ActiveMdiChild != null && this.ActiveMdiChild.WindowState == FormWindowState.Maximized)
{
    this.ActiveMdiChild.WindowState = FormWindowState.Normal;
}

foreach (Form mdi in this.MdiChildren)
{
    if (!(mdi is FormQuery)) continue; 
    FormQuery frmQ = (FormQuery)mdi;
    frmQ.DetachQuery();
    toClose.Add(frmQ);
}

相关问题