Application.restart - VB.Net中的令人费解的行为

时间:2012-09-21 18:02:09

标签: vb.net

好的,伙计们,这里发生了什么? 在这个VB代码中:

Module Module1
Sub Main()


    If MsgBox("Restart?", MsgBoxStyle.OkCancel) = MsgBoxResult.Ok Then
        Application.Restart()

        MsgBox("restarting")

    Else
        MsgBox("Cancel")

    End If

End Sub
End Module

如果此代码包含在模块中,则Application.Restart不会结束正在运行的应用程序,直到命中End Sub。执行之前出现的任何代码 - 例如,出现“重新启动”消息框。 但是,如果在表单中运行等效代码,则Application.Restart会立即终止正在运行的应用程序。 (两种情况都正确地启动了一个新实例)。这种行为似乎没有记录在任何地方 - 文档中的含义是,就运行实例的终止而言,它与'End'是同义词。我错过了什么吗?

3 个答案:

答案 0 :(得分:3)

回答这些问题的最好方法是使用Reflector查看代码本身(或微软免费调试代码,当它可用时)。

使用Reflector,您可以看到(在.NET Framework 4.0中)System.Windows.Forms.Application.Restart查找四种不同类型的应用程序:

  • Assembly.GetEntryAssemblyNothing的初步检查,如果是NotSupportedException则会抛出; {/ li>
  • Process.GetCurrentProcess.MainModule.FileNameieexec.exe位于与当前.NET Framework相同的文件夹中(特别是定义Object的模块所在的文件夹);
  • ApplicationDeployment.IsNetworkDeployedTrue;和
  • 一般情况。

所有三个受支持的案例都会确定再次启动流程的方法,调用Application.ExitInternal并再次启动流程。

Application.ExitInternal关闭打开的表单,包括通过将FormClosingEventArgs.Cancel设置为True来检查试图中止结算的表单。如果没有表单尝试取消,表单将会关闭,并使用ThreadContext.ExitApplication清除所有ThreadConnextsDisposed或调用他们的ApplicationContext.ExitThread)。

NB没有调用Thread.Abort,因此线程 NOT 以任何方式显式结束。此外,Windows.Forms ModalApplicationContext甚至不会调用普通ThreadExit所做的ApplicationContext“事件”。

(请注意,Application.Restart 中的所有三个受支持的案例都忽略 Application.ExitInternal的结果,因此如果表单确实试图中止所有发生的事情,那么任何其他表单没有机会关闭,ThreadContexts没有清理!)

重要的是,对于您的问题,它 NOT 尝试实际退出当前线程或整个应用程序(除了关闭打开的表单和线程上下文)。

但是,当您的MsgBox("restarting")执行时,新应用程序已经启动。

您需要在致电Application.Restart后手动退出应用程序。在“在表单中运行”的情况下(您没有显示测试此处的代码)表单是否已关闭,这是您认为当前应用程序结束的内容,或{{1 (或VB)设置意味着应用程序 退出其中一个“事件”,当发生的清理运行时,它会抛出。

换句话说,在测试之前,我预计Windows.Forms会出现,即使此代码位于表单的MsgBox事件中,表单首先消失,应用程序重新启动同一时间。

测试完之后,Click试图出现,因为我听到与之对应的哔哔声,如果我发出评论,则不会发出哔哔声。所以有些东西会导致应用程序退出,即使它应该打开一个消息框,甚至在MsgBox之外的MsgBox中放置Finally也不会出现在Application.Run上}。 (注意,如果您在Restart之后致电MsgBox,则会看到类似的效果。)

因此Application.Exit(或VB)设置的内容实际上会调用类似Windows.Forms的内容,调用Win32Api Environment.Exit并且不会考虑ExitProcess或调用{{1 }或Finally

请注意,Dispose文档暗示它不适用于控制台应用程序,但它目前工作正常(除了不立即退出,Finalize不暗示)。

答案 1 :(得分:0)

根据我对Application.Restart()的一些相当高级的读数,这肯定会有点猜测,但我认为这是由于Restart在内部运行的方式而发生的。 / p>

我认为Restart()尝试对正在终止的进程进行尽可能多的“智能”清理,并且在可能被认为是相当简单的实现中,跟踪某些要清理的东西, “可能在它们上面调用Dispose()(如果适用),这通常是一个合理的步骤。在你的情况下,我将猜测后台线程或表单持有对某些内容的引用 - 不能说是什么 - 这会阻止代码关闭。它可能会意识到它正在一个方法中执行,并希望在杀死它之前给该方法一个完成的机会 - 等待该子/方法的完成。

我已经看到其他实例的重新启动实际上导致真的奇怪的“收集被修改”错误当没有涉及集合时。这对我来说可能是天真的,正在尝试实现的内部清理是在一个简单的列表中,但在某些情况下,清理以一种意想不到的方式修改元素,一种修改集合的方式,导致抛出异常,并中止退出/重新启动。

答案 2 :(得分:0)

我可以通过关闭并处理所有打开的窗体(正在调用的窗体除外)来重新启动应用程序。

    For j As Integer = Application.OpenForms.Count - 1 To 0 Step -1
        Dim frm = Application.OpenForms(j)
        If frm.Text <> callingForm.Text Then
            frm.Close()
            frm.Dispose()
        End If
    Next

    Application.Restart()