Речь идет о приложении 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 - работает точно так же, выдает необработанное исключение, которое невозможно перехватить.
Я пытался отладить его с помощью VS2012 и VS2019 - исключение сообщается в том же месте, и его невозможно поймать или выяснить причина исключения.
При запуске сборки выпуска моего приложения здесь отображается необработанное исключение:
************** 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-потомков windows в рабочей области, но он сообщает о необработанном исключении только для одного из дочерних элементов MDI (всегда при закрытии 1-го или 2-го дочернего элемента MDI, никогда при закрытии других дочерних элементов MDI). Все остальные дочерние элементы MDI закрываются нормально. Я попытался изменить последовательность дочерних элементов MDI (по его содержимому) - ни в коем случае, он всегда сообщает о необработанном исключении для закрытия 1-го или 2-го дочернего элемента MDI, несмотря на содержимое.
Я искал inte rnet для этого - ничего не нашел. Я видел только ссылку на возможную причину использования ActiveX, но здесь это не так. Мой FormQuery очень простой, есть только - Panel, SplitContainer, TextBox, DataGridView, StatusStrip, одно ContextMenu - ничего больше. Итак, он не использует никаких компонентов ActiveX ...
Я пытался проанализировать. NET внутренности с помощью Reflector - я не вижу никаких возможных причин такого исключения.
Также пытался использовать Hide () + Close (), Hide () + Dispose (), попытался добавить Thread.Sleep (100) в метод closeWorkspace () - нет, он все равно сообщает об исключении, и это полностью неуловимо ! : - (
Я совершенно не понимаю - как понять, почему существует это исключение?! Не могли бы вы посоветовать - что еще я могу проверить, чтобы выяснить причину исключения и исправить это?
Спасибо.