2013-04-09 45 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

相關問題