2013-04-09 50 views
0

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

我认为一个好主意是列出所有子句柄并在标题句柄中搜索一个字符串,因为当蒸汽加载存在名为“朋友”的窗口句柄时,但这很难做到这一点(API ),所以也许存在一个简单的方法来等待程序加载......什么,我会做

例子:

' 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:

主要的问题是如何等待X程序被加载,但对Steam.exe当蒸汽加载尝试读取/打开一些REGKEYS我注意到太:

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

也许我可以做用代码来监视某个RegKeys是否被认可?

像这样的事情?:

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

While not Regkey.IsAccessed 
    ' Do nothing and wait 
Loop 

Process.start("Second process.exe") 

更新2:

我试图做一个函数以供参考Amegon的解决方案,我没有完成的代码因为我得到一行错误:

Memory = hprocess.PrivateMemorySize64 

enter image description here

但是,当我尝试推出一个“大”的应用程序(应用程序需要大量的时间来加载,如Photoshop),与“小”的应用程序工作好,我只能得到错误。

如果有人可以帮助我简化/改进Amegon的解决方案,使通用功能和纠正内存溢出错误...谢谢!

这是我的代码:

' 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 
+0

你检查了Process类的[GetProcessesByName](http://msdn.microsoft.com/en-us/library/z3w4xdc9.aspx)方法吗?只需尝试使用像ProcessExplorer这样的工具来识别进程名称..... – Steve 2013-04-09 16:15:29

+0

如果点击进程按钮,您会看到什么?你正在搜索的过程不是窗口 – Steve 2013-04-09 16:26:08

+0

对不起,这是我第一次使用spy ++,我编辑了我的问题! – ElektroStudios 2013-04-09 16:30:33

回答

1

更新我必须建立一个例子程序,以显示该内存和cpu观察

要运行它创建一个新的项目,Windows窗体应用程序,然后打开代码部分并插入以下代码。无需添加任何控件,我手动将它们添加到代码中。我为能与2012 VS上的win8教授x64-最终成功运行的代码:

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 

如果您按一下按钮,它会开始输入dxdiag并显示内存的变化,总的CPU时间差(与上次相比)在文本框中。如果所有条件都满足(运行,没有cpu总时间变化,没有内存变化),那么秒表将计数到1500,然后消息框会说'已完成'

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

等待时间是为了确保第二个纯粹的硬盘加载时间不会造成加载完成的错误印象(可能无内存或cpu更改)。

风险是..如果一个页面会自动出现并显示内容/广告,那么也许该CPU是不断使用。所以您只能检查内存变化或任何其他值,您可以从Process中访问。

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

+0

谢谢,但内存消耗可以在第一个进程(steam.exe)的加载时间变化很多,我认为这是一个风险,就像时间一样。真的,我不明白你对“子进程”(steam.exe的子线程,或独立的可执行文件)的意思,但我用“sysinternals”的“进程监视器”来监视可执行文件,而我现在我第一次使用“Spy ++”,我没有注意到任何“子进程”,但也许我错了,因为我不是专家。我会在几秒钟内更新我的问题上传一个截图。 – ElektroStudios 2013-04-09 16:11:37

+0

关于消失,我发动了一个争论来禁用更新,这个问题就解决了。 – ElektroStudios 2013-04-09 16:26:35

+0

我也是Spy ++的初学者,但在使用sendkeys(尝试构建一个简单的bot)时,我了解到有时必须访问特定目标才能发送命令。因此,用spy ++检查一个正在运行的程序是否存在是很有用的。我不确定它是否被定义为子进程或子线程。由于蒸汽可能不会发送“我完成加载”的消息,所以也许你可以尝试找到另一个只在加载时存在的蒸汽下的子对象,例如,展示朋友。在这种情况下,您可以不断扫描该对象,并知道发现蒸汽时加载 – Amegon 2013-04-09 16:27:30

2

WaitForInputIdle方法等待,直到应用程序已启动,正在等待输入

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

注:这不会对服务应用程序。

+0

等待输入意味着等待用户输入?是仅适用于CLI应用程序的解决方案? – ElektroStudios 2013-04-09 16:58:02

+0

+1为启动过程的方式(并立即有一个句柄,不知道这种方式)。另外,如果你保留进程句柄p并且WaitForInputIdle不成功(例如,蒸汽允许用户在输入某些组件时登录到朋友网络),那么你可以使用.Refresh来读取最新的值进程句柄p。 – Amegon 2013-04-09 17:48:12

+0

@Amegon:是的,您只能调用一次'WaitForInputIdle'!之后它不再有任何效果。我不知道这个方法是如何工作的,但我认为这是开始消息循环的开始,例如,即使它仍然在工作,你可以用SendKeys来发送它。 – 2013-04-09 18:10:26

相关问题