vb.net 执行一个应用程序并等待它被加载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15906479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 13:12:04  来源:igfitidea点击:

Execute a application and wait for it to be loaded

vb.netvisual-studiohandlewindow-handles

提问by ElektroStudios

I'm searching for a way to execute Steam (Steam.exe) and wait for it to be loaded (Not to exited).

我正在寻找一种方法来执行 Steam (Steam.exe) 并等待它被加载(不要退出)。

I was think a good idea is to list all the child handles and search for a string in the title handles because when steam loads exist a window handle named "Friends", but this is hard to do it for me (APIs) so maybe exist a easy way to wait for a program to load...

我认为一个好主意是列出所有子句柄并在标题句柄中搜索一个字符串,因为当 Steam 加载时存在一个名为“Friends”的窗口句柄,但这对我来说很难(API),所以可能存在一种等待程序加载的简单方法...

Example of what I will do:

我将做的示例:

' First process
Process.start("Process 1.exe")

' Here will goes an efficient method to wait for application is loaded,
' not sleeping X seconds measuring the loading time or any of that.

' Second process
' Depends on first process fully loaded.
' If first process is not fully loaded (libraries and that) then this process can't run.
Process.start("Processs 2.exe")

UPDATE:

更新:

The Main question is how to wait for X process to be loaded, but about the Steam.exe I've noticed too when Steam is loaded tries to read/open some regkeys:

主要问题是如何等待 X 进程被加载,但关于 Steam.exe 我也注意到当 Steam 加载时尝试读取/打开一些注册码:

http://img267.imageshack.us/img267/6599/prtscrcapture4u.jpg

http://img267.imageshack.us/img267/6599/prtscrcapture4u.jpg

Maybe I can do something with code to monitor if one of that RegKeys is accesed?

也许我可以用代码做一些事情来监控是否访问了其中一个 RegKeys?

Something like this?:

像这样的东西?:

Dim RegKey = "HKLM\...blablabla"
Process.start("steam.exe")

While not Regkey.IsAccessed 
  ' Do nothing and wait
Loop

Process.start("Second process.exe")

UPDATE 2:

更新 2:

I'm trying to make a function taking by reference the solution of Amegon, I don't finished the code because I'm getting an error in the line:

我正在尝试通过引用 Amegon 的解决方案来创建一个函数,我没有完成代码,因为我在行中遇到错误:

Memory = hprocess.PrivateMemorySize64

enter image description here

在此处输入图片说明

But I only get the error when I try to launch a "big" application (application that needs much time to load like Photoshop), with "little" apps works good.

但是,当我尝试启动“大”应用程序(需要像 Photoshop 一样需要很长时间才能加载的应用程序)时,我只会收到错误消息,而“小”应用程序运行良好。

Please if someone can help me to simplify/improve the Amegon's solution to make a Generic function and to correct the memory overflow error... Thank you!

请如果有人可以帮助我简化/改进 Amegon 的解决方案以制作通用函数并纠正内存溢出错误......谢谢!

This is my code:

这是我的代码:

' This is the sub that launchs the unfinished function:
Private Sub Launch_Game()
    'Wait_For_Application_To_Load("C:\Games\Steam.exe", "-applaunch 0")
    Wait_For_Application_To_Load("C:\Program Files\Adobe Photoshop CS6 (64 Bit)\Photoshop.exe")
End Sub

Private Function Wait_For_Application_To_Load(ByVal APP_Path As String, Optional ByVal APP_Arguments As String = Nothing)
    Dim File = My.Computer.FileSystem.GetFileInfo(APP_Path)
    Process.Start(APP_Path, APP_Arguments)
    Timer_CheckCPU.Tag = File.Name.Substring(0, File.Name.Length - 4) ' Photoshop
    Timer_CheckCPU.Enabled = True
End Function

Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByVal lpBuffer As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
Private WithEvents Timer_CheckCPU As New Timer

Dim Memory_Value_Changed As Boolean
Dim CPU_Changed As Boolean
Dim CPU_Time As Boolean
Dim Running_Time As Boolean
Private _desiredTime_ms As Integer = 1500

Private Sub Timer_CheckCPU_Tick(sender As Object, ev As EventArgs) Handles Timer_CheckCPU.Tick
    Timer_CheckCPU.Enabled = False
    Dim pProcess() As Process = System.Diagnostics.Process.GetProcessesByName(Timer_CheckCPU.Tag)
    Dim hprocess As Process = pProcess(0)
    If hprocess Is Nothing Then
        Running = False
        Timer_CheckCPU.Enabled = True
        Return
    End If
    Running = True


    ' Here is the error:
    Memory = hprocess.PrivateMemorySize64
    ' MsgBox(hprocess.PrivateMemorySize64.ToString)


    CPUTotal = hprocess.TotalProcessorTime.TotalMilliseconds

    If AllConditionsGood() Then
        If Not (_countdown.IsRunning) Then
            _countdown.Reset()
            _countdown.Start()
        End If
        Dim _elapsed As Integer = _countdown.ElapsedMilliseconds
        If _elapsed >= _desiredTime_ms Then
            Me.TopMost = True
            MsgBox("process loaded")
            Return
        End If
    Else
        _countdown.Reset()
    End If
    Timer_CheckCPU.Enabled = True
End Sub

Private Function AllConditionsGood() As Boolean
    If CPU_Time Then Return False
    If Memory_Value_Changed Then Return False
    If Running_Time Then Return False
    Return True
End Function

Private _countdown As New Stopwatch

Private _Running As Boolean = False
Public WriteOnly Property Running() As Boolean
    Set(ByVal value As Boolean)
        _Running = value
        If value Then
            Running_Time = False
        Else
            Running_Time = True
        End If
    End Set
End Property

Private _CPUTotal As Integer
Public WriteOnly Property CPUTotal() As Integer
    Set(ByVal value As Integer)
        CPU = value - _CPUTotal 'used cputime since last check
        _CPUTotal = value
    End Set
End Property


Private _CPU As Integer
Public WriteOnly Property CPU() As Integer
    Set(ByVal value As Integer)
        If value = 0 Then
            CPU_Time = False
        Else
            CPU_Time = True
        End If
        _CPU = value
    End Set
End Property

Private _Memory As Integer
Public WriteOnly Property Memory() As Integer
    Set(ByVal value As Integer)
        MemoryDiff = Math.Abs(value - _Memory)
        _Memory = value
    End Set
End Property

Private _MemoryDiff As Integer
Public WriteOnly Property MemoryDiff() As Integer
    Set(ByVal value As Integer)
        If value = _MemoryDiff Then
            Memory_Value_Changed = False
        Else
            Memory_Value_Changed = True
        End If
        _MemoryDiff = value
    End Set
End Property

回答by Olivier Jacot-Descombes

The WaitForInputIdlemethod waits until the application has started and is waiting for input

WaitForInputIdle方法等待直到应用程序启动并等待输入

Dim psi As New ProcessStartInfo("fileName", "arguments")
Dim p As New Process
p.StartInfo = psi
p.Start()
p.WaitForInputIdle()


Note: This will not work for service applications.

注意:这不适用于服务应用程序。

回答by Amegon

UpdateI have build an example program to show this memory and cpu observing

更新我已经构建了一个示例程序来显示这个内存和 CPU 观察

To run it create a new project, windows form application, then open the code part and insert the following code. -no need to add any controls, I added them in code manually. I as able to successfully run the code with VS 2012 ultimate on win8 prof x64- :

要运行它,请创建一个新项目,windows 窗体应用程序,然后打开代码部分并插入以下代码。- 不需要添加任何控件,我手动在代码中添加了它们。我能够在 win8 prof x64- 上使用 VS 2012 Ultimate 成功运行代码:

Option Strict On
Imports System.Runtime.InteropServices

Public Class Form1
    Private WithEvents btnStart As New Button
    Private WithEvents tmrCheckCPU As New Timer

    Private tbRunning As New TextBox
    Private tbCPU As New TextBox
    Private tbMemory As New TextBox
    Private tbTime As New TextBox

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Size = New Size(400, 400)
        With btnStart
            '.Text = "Start DxDiag"
            .Text = "Start Photoshop"
            Me.Controls.Add(btnStart)
            .Location = New Point(50, 50)
            .Size = New Size(200, 50)
        End With
        With tmrCheckCPU
            .Interval = 100
            .Enabled = False
        End With
        With tbRunning
            Me.Controls.Add(tbRunning)
            .Location = New Point(50, 110)
            .Size = New Size(100, 40)
        End With
        With tbCPU
            Me.Controls.Add(tbCPU)
            .Location = New Point(50, 150)
            .Size = New Size(100, 40)
        End With
        With tbMemory
            Me.Controls.Add(tbMemory)
            .Location = New Point(50, 200)
            .Size = New Size(100, 40)
        End With
        With tbTime
            Me.Controls.Add(tbTime)
            .Location = New Point(50, 250)
            .Size = New Size(100, 40)
        End With
    End Sub

    Private Sub btnStart_Clicked(sender As Object, ev As EventArgs) Handles btnStart.Click
        'start Process
        'Process.Start("dxdiag.exe", "/whql:on")
        Process.Start("C:\Program Files\Adobe\Adobe Photoshop CS6 (64 Bit)\Photoshop.exe")
        'start watching Timer
        tmrCheckCPU.Enabled = True
    End Sub

    Private Function FindProcess(MainWindowTitle As String) As System.Diagnostics.Process
        For Each ele As System.Diagnostics.Process In Process.GetProcesses
            If ele.MainWindowTitle = MainWindowTitle Then Return ele
        Next
        Return Nothing
    End Function

    Private Sub tmrCheckCPU_Tick(sender As Object, ev As EventArgs) Handles tmrCheckCPU.Tick
        tmrCheckCPU.Enabled = False
        'Dim name As String = "DirectX Diagnostic Tool"
        Dim name As String = "Adobe Photoshop CS6 Extended"
        Dim hprocess As Process = FindProcess(name)
        If hprocess Is Nothing Then
            Running = False
            tmrCheckCPU.Enabled = True
            Return
        End If
        Running = True
        Memory = hprocess.PrivateMemorySize64
        CPUTotal = hprocess.TotalProcessorTime.TotalMilliseconds

        If AllConditionsGood() Then
            If Not (_countdown.IsRunning) Then
                _countdown.Reset()
                _countdown.Start()
            End If
            Dim _elapsed As Long = _countdown.ElapsedMilliseconds
            If _elapsed >= _desiredTime_ms Then
                tbTime.Text = _desiredTime_ms.ToString
                tbTime.BackColor = Color.LightGreen
                Me.TopMost = True
                Me.Focus()
                MsgBox("process loaded")
                Return
            Else
                tbTime.Text = _elapsed.ToString
                tbTime.BackColor = Color.LightGreen
            End If
        Else
            _countdown.Reset()
        End If
        tmrCheckCPU.Enabled = True
    End Sub

    Private _desiredTime_ms As Integer = 1500

    Private Function AllConditionsGood() As Boolean
        If tbCPU.BackColor <> Color.LightGreen Then Return False
        If tbMemory.BackColor <> Color.LightGreen Then Return False
        If tbRunning.BackColor <> Color.LightGreen Then Return False
        Return True
    End Function

    Private _countdown As New Stopwatch

    Private _Running As Boolean = False
    Public WriteOnly Property Running() As Boolean
        Set(ByVal value As Boolean)
            _Running = value
            If value Then
                tbRunning.Text = "Running"
                tbRunning.BackColor = Color.LightGreen
            Else
                tbRunning.Text = "Not Running"
                tbRunning.BackColor = Color.LightPink
            End If
        End Set
    End Property

    Private _CPUTotal As Double
    Public WriteOnly Property CPUTotal() As Double
        Set(ByVal value As Double)
            CPU = value - _CPUTotal 'used cputime since last check
            _CPUTotal = value
        End Set
    End Property


    Private _CPU As Double
    Public WriteOnly Property CPU() As Double
        Set(ByVal value As Double)
            If value = 0 Then
                tbCPU.BackColor = Color.LightGreen
            Else
                tbCPU.BackColor = Color.LightPink
            End If
            _CPU = value
            tbCPU.Text = value.ToString
        End Set
    End Property

    Private _Memory As Long
    Public WriteOnly Property Memory() As Long
        Set(ByVal value As Long)
            MemoryDiff = Math.Abs(value - _Memory)
            _Memory = value
        End Set
    End Property

    Private _MemoryDiff As Long
    Public WriteOnly Property MemoryDiff() As Long
        Set(ByVal value As Long)
            If value = _MemoryDiff Then
                tbMemory.BackColor = Color.LightGreen
            Else
                tbMemory.BackColor = Color.LightPink
            End If
            _MemoryDiff = value
            tbMemory.Text = value.ToString
        End Set
    End Property

End Class

If you click on the button, it will start dxdiag and shows the change of memory and the difference of total cpu time (compared with last time) in textboxes. If all conditions are met (running, no cpu total time change, no memory change) then a stopwatch will count to 1500 and then a messagebox will say 'finished'

如果你点击按钮,它会启动 dxdiag 并在文本框中显示内存的变化和总 CPU 时间的差异(与上次相比)。如果满足所有条件(正在运行、CPU 总时间没有变化、内存没有变化),那么秒表将计数到 1500,然后消息框将显示“已完成”

It is dirty written, but I guess you understand the main core (how to find the correct process without any dll declare method), how to read some information of that process after finding it, and in what way to apply the conditions.

写得很脏,但我猜你明白主要核心(如何在没有任何dll声明方法的情况下找到正确的进程),找到后如何读取该进程的一些信息,以及如何应用条件。

The waiting time is meant to assure that a second of pure hard drive loading time will not create the wrong impression that loading is done (no memory or cpu change maybe).

等待时间是为了确保一秒钟的纯硬盘加载时间不会造成加载已完成的错误印象(可能没有内存或 CPU 变化)。

The risk is that.. if a page will automatically appear and show content/advertisement, then maybe the cpu is constantly used. so you may only check for memory change or any other value tht you can access from the Process.

风险在于……如果页面会自动出现并显示内容/广告,那么可能会不断使用 CPU。因此您只能检查内存更改或您可以从进程访问的任何其他值。

Updatecorrected code (fixed the wrong data types). Now Option strict is not complaining about my code :)

更新更正的代码(修复了错误的数据类型)。现在 Option strict 不会抱怨我的代码 :)