【问题标题】:Process WaitForSingleObject - responsive UI处理 WaitForSingleObject - 响应式 UI
【发布时间】:2021-07-18 06:50:29
【问题描述】:

我正在使用以下代码来了解如何在进程处于活动状态时等待它结束。
在我的代码中,就在记事本打开时,我看到了 MessageBox。

如何等到记事本关闭而不让我的表单无响应?

Public Class Form1
    Private Const WAIT_INFINITE = -1&
    Private Const SYNCHRONIZE = &H100000

    Private Declare Function OpenProcess Lib "kernel32" _
  (ByVal dwDesiredAccess As Long,
   ByVal bInheritHandle As Long,
   ByVal dwProcessId As Long) As Long

    Private Declare Function WaitForSingleObject Lib "kernel32" _
  (ByVal hHandle As Long,
   ByVal dwMilliseconds As Long) As Long

    Private Declare Function CloseHandle Lib "kernel32" _
  (ByVal hObject As Long) As Long

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim hProcess As Long
        Dim taskId As Long
        Dim cmdline As String

        cmdline = "notepad.exe"
        taskId = Shell(cmdline, vbNormalFocus)

        hProcess = OpenProcess(SYNCHRONIZE, True, taskId)
        Call WaitForSingleObject(hProcess, WAIT_INFINITE)
        CloseHandle(hProcess)

        MsgBox ("The shelled app has ended.")
    End Sub
End Class

【问题讨论】:

  • 您必须这样做还是更简单地使用System.Diagnostics.Process 的实例而不是Await proc.WaitForExitAsync()
  • 感谢您的评论!但这肯定没有按预期工作。请您发布一个演示 WaitForExitAsync 的示例代码吗?
  • 既然是“用代码理解等待过程”,能不能暂时把记事本执行代码注释掉?另外,您是否尝试过使用 Visual Studio 调试运行此 VB.NET 代码?

标签: vb.net winforms winapi process waitforsingleobject


【解决方案1】:

在最简单的情况下,WaitForExitAsync 如下所示:

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim p = Process.Start("notepad.exe")
    Await p.WaitForExitAsync()
    MsgBox ("The shelled app has ended.")
End Sub

【讨论】:

    【解决方案2】:

    在 .Net Framework / .Net Core 中,您可以使用异步、事件驱动的 WaitForExit 版本,订阅 Exited 事件,该事件在您启动的进程终止时引发。

    注意:该事件在 ThreadPool 线程中引发。您可以将 Process.SynchronizingObject 设置为当前的 Form 实例,以将事件编组到 UI 线程。

    在 .Net Framework 中,将 [Process].StartInfo.UseShellExecute 设置为 False,因为默认值为 True
    在 .Net Core 中,默认值已经是 False

    引发事件时,进程已经退出(HasExitedTrue),因此并非所有常用信息都可用。 Process.StartInfoProcessStartInfo 对象)是可访问的,当然还有 ExitTime 和其他值(在引发事件时检查 Process 对象)。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim p = New Process()
        p.StartInfo.FileName = "notepad.exe"
        p.StartInfo.UseShellExecute = False
        p.SynchronizingObject = Me
        p.EnableRaisingEvents = True
        AddHandler p.Exited,
            Sub()
                Dim processName = p.StartInfo.FileName
                Dim exitTime = p.ExitTime
                p?.Dispose()
                MessageBox.Show("Process exited")
                DoSomethingElseRelated(processName, exitTime)
            End Sub
        p.Start()
    End Sub
    

    【讨论】:

    • 我正在处理单击时禁用按钮并打开一个记事本实例。代码明智,它似乎工作,但我在调试模式'System.InvalidOperationException:'跨线程操作无效:控制'Button1'从创建它的线程以外的线程访问的异常。''我修改的代码你的答案: .... p?.Dispose() 'MessageBox.Show("Process exited") Button1.Enabled = True 'DoSomethingElseRelated(processName, exitTime) End Sub p.Start() Button1.Enabled = False
    • 当然。您可以添加[Process].SynchronizingObject = Me,否则在 ThreadPool 线程中引发事件。我已经编辑了帖子。 -- 你应该在开始进程之前禁用按钮。
    猜你喜欢
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-09
    • 2010-11-09
    • 2014-07-15
    • 2023-03-07
    相关资源
    最近更新 更多