Что нового

[Процессы] Слежение за процессом

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
два скрипта (читай программы). второй следит за процессом первого скрипта.
функция
Код:
ProcessExists

не подходит. так как второй скрипт выполняет свою работу и данная функция слишком тормозит.
есть ли какие-нибудь идеи как следить за процессом?
или . можно ли уведомить скрипт о критическом завершении его работы. к примеру, завершение работы через диспетчер задач
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
joiner
Много вариантов напрашивается в голову...

Первый скрипт запускает второй? Или они запускаются отдельно?
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
насчет много вариантов это понятно. я перебрал разные. но меня интересует тот, который занимает меньше всего времени на проверку.

firex [?]
Первый скрипт запускает второй? Или они запускаются отдельно?
тут возможны два варианта, но пусть будет первый
 

Z_Lenar

Продвинутый
Сообщения
209
Репутация
52
Код:
#include <WinAPI.au3>

; Сначала получаем PID процесса
; Можно через WinGetProcess или Run
Global $hProc = ProcessExists('totalcmd.exe')
Global $ret

If $hProc = 0 Then ; Если процесс не найден
	Exit
EndIf
$hProc = _WinAPI_OpenProcess(0x00100000, False, $hProc)

While 1
	; Второй параметр сколько "ждать" завершения
	;  целевого процесса (1000мс). Если -1 ждать бесконечно.
	$ret = _WinAPI_WaitForSingleObject($hProc, 1000)
	ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ret = ' & $ret & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
	If $ret = 258 Then  ; Если в течении 1000мс процесс не завершился
		; Выполняем свои действия
	Else
		; Процесс завершен
		_WinAPI_CloseHandle($hProc)
		ExitLoop
	EndIf
WEnd
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
согласно варианту Z_Lenar
Код:
#include <WinAPI.au3>
Global $hProc = ProcessExists('taskmgr.exe')
Global $ret

If $hProc = 0 Then 
	Exit
EndIf
$hProc = _WinAPI_OpenProcess(0x00100000, False, $hProc)

$file = @ScriptDir & '\1.mkv'
$file1 = @ScriptDir & '\2.mkv'
$part = 4096
$f_o = FileOpen($file)
$f_o1 = FileOpen($file1, 2)
$timer = TimerInit()
While 1
	$ret = _WinAPI_WaitForSingleObject($hProc, 1000)
	;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ret = ' & $ret & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
	If $ret = 258 Then
		$f_r = FileRead($file, $part)
		If @error = -1 Then ExitLoop
		FileWrite($file1, $f_r)
	Else
		_WinAPI_CloseHandle($hProc)
		ExitLoop
	EndIf
WEnd
ConsoleWrite(TimerDiff($timer) & @CRLF)
FileClose($file)
FileClose($file1)
я правильно понял принцип применения?
если да, то это в разы медленнее чем просто проверка существования процесса
 

Z_Lenar

Продвинутый
Сообщения
209
Репутация
52
joiner
Да. Но желательно не забывать уничтожить дескриптор процесса:
Код:
#include <WinAPI.au3>
Global $hProc = ProcessExists('taskmgr.exe')
Global $ret

If $hProc = 0 Then
    Exit
EndIf
$hProc = _WinAPI_OpenProcess(0x00100000, False, $hProc)

$file = @ScriptDir & '\1.mkv'
$file1 = @ScriptDir & '\2.mkv'
$part = 4096
$f_o = FileOpen($file)
$f_o1 = FileOpen($file1, 2)
$timer = TimerInit()
While 1
    $ret = _WinAPI_WaitForSingleObject($hProc, 0) ; не ждем
    If $ret = 258 Then
        $f_r = FileRead($file, $part)
        If @error = -1 Then ExitLoop
        FileWrite($file1, $f_r)
    EndIf
WEnd
_WinAPI_CloseHandle($hProc)
ConsoleWrite(TimerDiff($timer) & @CRLF)
FileClose($file)
FileClose($file1)
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
это понятно, но в данном случае вариант не тот
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Моё воспалённое воображение нарисовало вот такую картину.

Код:
; отслеживаемый процесс

HotKeySet("+!e", "_Exit") ; Shift + Alt + e

While 1
	ToolTip("работает процесс 1"&@CR&@HOUR&":"&@MIN&":"&@SEC,0,0)
	Sleep(1000)
WEnd

Func _Exit()
	ControlClick("semafore","","[CLASS:Button; INSTANCE:1]")
	Exit
EndFunc


Код:
; следящий процесс

Opt("GUIOnEventMode", 1)

$hGUI = GUICreate("semafore")
$eButton = GUICtrlCreateButton("stop", 10, 10, 50, 20)
GUICtrlSetOnEvent(-1, "StopEvent")
GUISetState(@SW_SHOW)

While 1
	TrayTip("Работает процесс 2", @HOUR&":"&@MIN&":"&@SEC,10)
	Sleep(1000)
WEnd

Func StopEvent()
	GUIDelete($hGUI)
	MsgBox(0, "сообщение процесса 2", "Процесс 1 закрылся")
EndFunc
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
C2H5OH
:smile:
спасибо, но твой вариант не из моей оперы. никаких горячих клавиш . только - есть процесс, значит работаем, нет - выход. смотри пример выше
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
joiner, ты меня пугаешь!
HotKey используется исключительно для остановки процесса № 1.

Суть прикола в том, что Процесс № 1 при завершении вызывает событие в Процессе № 2,
которое Процесс № 2 отловит по GUIOnEventMode.
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
C2H5OH
прочитай еще раз первое сообщение темы.
и посмотри мой пример копирования файла. там нужно вставить проверку на наличие процесса
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Не вижу разногласий.
Тебе не доступен код первого процесса? Ты не можешь в него вносить изменения?
Код:
Opt("GUIOnEventMode", 1)
$hGUI = GUICreate("semafore")
$eButton = GUICtrlCreateButton("stop", 10, 10, 50, 20)
GUICtrlSetOnEvent(-1, "StopEvent")
GUISetState(@SW_SHOW)

Func StopEvent()
	GUIDelete($hGUI)
	FileClose($file)
	FileClose($file1)
EndFunc

$file = @ScriptDir & '\1.mkv'
$file1 = @ScriptDir & '\2.mkv'
$part = 4096
$f_o = FileOpen($file)
$f_o1 = FileOpen($file1, 2)
$timer = TimerInit()
While 1
    $f_r = FileRead($file, $part)
	If @error = -1 Then ExitLoop
	FileWrite($file1, $f_r)
WEnd
ConsoleWrite(TimerDiff($timer) & @CRLF)
FileClose($file)
FileClose($file1)
:smile:
 

Z_Lenar

Продвинутый
Сообщения
209
Репутация
52
joiner [?]
то это в разы медленнее чем просто проверка существования процесса
Что мешает вторым параметром функции WaitForSingleObject поставить 0?

Еще один вариант:
Код:
#include <WinAPIProc.au3>
#include <ProcessConstants.au3>
#include <WinAPISys.au3>

; Сначала получаем PID процесса
; Можно через WinGetProcess или Run
Global $hProc = ProcessExists('totalcmd.exe')
Global $ret

If $hProc = 0 Then ; Если процесс не найден
    Exit
EndIf

$hProc = _WinAPI_OpenProcess($PROCESS_QUERY_INFORMATION, False, $hProc)

While 1
	$ret = _WinAPI_GetExitCodeProcess($hProc)
    If $ret = 259 Then
        ; Выполняем свои действия
    Else
        ; Процесс завершен
        _WinAPI_CloseHandle($hProc)
        ExitLoop
    EndIf
WEnd
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Z_Lenar
протестил оба варианта
вот второй
Код:
#include <WinAPIProc.au3>
#include <ProcessConstants.au3>
#include <WinAPISys.au3>
Global $hProc = ProcessExists('taskmgr.exe')
Global $ret

$hProc = _WinAPI_OpenProcess($PROCESS_QUERY_INFORMATION, False, $hProc)

$file = @ScriptDir & '\1.mkv'
$file1 = @ScriptDir & '\2.mkv'
$part = 1048576
$f_o = FileOpen($file, 16)
$f_o1 = FileOpen($file1, 26)
$timer = TimerInit()
While 1
	$ret = _WinAPI_GetExitCodeProcess($hProc)
	If $ret = 259 Then
		$f_r = FileRead($f_o, $part)
		If @error = -1 Then ExitLoop
		FileWrite($f_o1, $f_r)
	Else
		ExitLoop
	EndIf
WEnd
_WinAPI_CloseHandle($hProc)
ConsoleWrite(TimerDiff($timer) & @CRLF)
FileClose($file)
FileClose($file1)
показывают одно время (плюс - минус) с обычным копированием..
протестирую в своей программе, тогда отпишусь о результате
во всяком случае спасибо за наводку
 

Houshi

Новичок
Сообщения
10
Репутация
0
Можно проверять не наличие, а отсутствие процесса if not ProcessExists и в проверке установить sleep (1000) , тогда, при наличии процесса, скрипт будет просто проскакивать и не тормозить.
 

Z_Lenar

Продвинутый
Сообщения
209
Репутация
52
Houshi
Можно копирующий цикл и так написать:
Код:
$f_r = FileRead($f_o, $part)
While @error <> -1 And _WinAPI_GetExitCodeProcess($hProc) = 259
	FileWrite($f_o1, $f_r)
	$f_r = FileRead($f_o, $part)
WEnd
Или вообще загрузить в память исполняемый шелл код. Но из-за обращения к диску сомнительно что это сильно увеличит скорость.
 

_dron_

Знающий
Сообщения
84
Репутация
8
или создать два сокета :smile: в процессе который следит изредка отправлять по одному байту и ловить ошибку! Если ведомый процесс закрылся то по идее в сокете будет ошибка. пример не дам так как спать ложусь :blink:
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
_dron_, а что, хорошая идея...
Я вот заметил что похоже Firefox использует такой же метод (т.е. на 127.0.0.1 localhost отправляет самому себе какие-то пакеты)...
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
ребята, спасибо за обсуждение темы.
приоритет - скорость выполнения своей задачи скриптом, который следит за процессом.
в примере я показал код второго скрипта, он копирует файл. в цикле "чтение-запись" должно происходить слежение за первым процессом. в цикле нельзя ставить Sleep.
цель - найти метод проверки существования (слежение) первого процесса, чтобы при этом не увеличилось время копирования файла
пока вижу выход в использовании _WinAPI_GetExitCodeProcess
буду благодарен за альтернативные варианты с примерами
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
joiner,
Решил проверить на скорость 7 вариантов (какие пока смог придумать) слежения за наличием процесса. У меня стабильно на первом месте IsHWnd. Тестировал на Win7x32 и WinXPx32.
Скрипт проверки.
Код:
#include <Array.au3>

Opt('MustDeclareVars', 1)

Global $sFile = 'Test_Script.exe', $sTitle = StringLeft($sFile, StringInStr($sFile, '.', 0, -1) - 1), $hWnd, $iPid, $hProc, $aRes, $iTimer, $iRes, $hWin, _
		$iCount = 10, $aResult[7][$iCount + 2] = [['ProcessExists'],['WinGetHandle'],['FindWindowW'],['WinExists'],['IsWindow'],['IsHWnd'],['GetExitCodeProcess']], _
		$aMin[2] = [100], $aMax[2]

$iPid = Run(@ScriptDir & '\' & $sFile)
If Not $iPid Then Exit 1
$hWnd = WinWait('[Title:' & $sTitle & ';Class:AutoIt v3]', '', 3)
If Not $hWnd Then Exit 2
$aRes = DllCall('kernel32.dll', 'handle', 'OpenProcess', 'dword', 0x1000, 'bool', 0, 'dword', $iPid)
;~ $PROCESS_QUERY_LIMITED_INFORMATION =  = 0x1000 ;Win Vista +
;~ $PROCESS_QUERY_INFORMATION = 0x0400 ;WinXP
If (@error) Or (Not $aRes[0]) Then Exit 3
$hProc = $aRes[0]

For $i = 1 To $iCount
	Sleep(1000)
	$iTimer = TimerInit()
	$iRes = ProcessExists($iPid)
	$aResult[0][$i] = Round(TimerDiff($iTimer), 3)
	ConsoleWrite('ProcessExists: ' & $aResult[0][$i] & @TAB & $iRes & @LF)

	Sleep(1000)
	$iTimer = TimerInit()
	$hWin = WinGetHandle('[Title:' & $sTitle & ';Class:AutoIt v3]')
	$aResult[1][$i] = Round(TimerDiff($iTimer), 3)
	ConsoleWrite('WinGetHandle: ' & $aResult[1][$i] & @TAB & $hWin & @LF)

	Sleep(1000)
	$iTimer = TimerInit()
	$aRes = DllCall('user32.dll', 'hwnd', 'FindWindowW', 'wstr', 'AutoIt v3', 'wstr', $sTitle)
	$aResult[2][$i] = Round(TimerDiff($iTimer), 3)
	ConsoleWrite('FindWindowW: ' & $aResult[2][$i] & @TAB & $aRes[0] & @LF)

	Sleep(1000)
	$iTimer = TimerInit()
	$iRes = WinExists($hWnd)
	$aResult[3][$i] = Round(TimerDiff($iTimer), 3)
	ConsoleWrite('WinExists: ' & $aResult[3][$i] & @TAB & $iRes & @LF)

	Sleep(1000)
	$iTimer = TimerInit()
	$aRes = DllCall('user32.dll', 'int', 'IsWindow', 'hwnd', $hWnd)
	$aResult[4][$i] = Round(TimerDiff($iTimer), 3)
	ConsoleWrite('IsWindow: ' & $aResult[4][$i] & @TAB & $aRes[0] & @LF)

	Sleep(1000)
	$iTimer = TimerInit()
	$iRes = IsHWnd($hWnd)
	$aResult[5][$i] = Round(TimerDiff($iTimer), 3)
	ConsoleWrite('IsHWnd: ' & $aResult[5][$i] & @TAB & $iRes & @LF)

	Sleep(1000)
	$iTimer = TimerInit()
	$aRes = DllCall('kernel32.dll', 'int', 'GetExitCodeProcess', 'ptr', $hProc, 'dword*', 0)
	$aResult[6][$i] = Round(TimerDiff($iTimer), 3)
	ConsoleWrite('GetExitCodeProcess: ' & $aResult[6][$i] & @TAB & $aRes[2] & @LF)
	ConsoleWrite('---' & @LF)
Next
DllCall('kernel32.dll', 'bool', 'CloseHandle', 'handle', $hProc)
If ProcessExists($iPid) Then ProcessClose($iPid)
For $i = 0 To 6
	For $j = 1 To $iCount
		$aResult[$i][$iCount + 1] += $aResult[$i][$j]
	Next
	$aResult[$i][$iCount + 1] = Round($aResult[$i][$iCount + 1] / $iCount, 3)
	If $aResult[$i][$iCount + 1] < $aMin[0] Then
		$aMin[0] = $aResult[$i][$iCount + 1]
		$aMin[1] = $i
	EndIf
	If $aResult[$i][$iCount + 1] > $aMax[0] Then
		$aMax[0] = $aResult[$i][$iCount + 1]
		$aMax[1] = $i
	EndIf
Next
ConsoleWrite('Min time func: ' & $aResult[$aMin[1]][0] & @LF)
ConsoleWrite('Max time func: ' & $aResult[$aMax[1]][0] & @LF)
;~ последняя колонка - среднее значение
_ArraySort($aResult, 0, 0, 0, $iCount + 1)
_ArrayDisplay($aResult, 'number of cycles: ' & $iCount)
Скрипт Test_Script (его надо скомпилировать).
Код:
#NoTrayIcon
AutoItWinSetTitle(StringLeft(@ScriptName, StringInStr(@ScriptName, '.', 0, -1) - 1))
MsgBox(64, 'Info', 'Test_Script')
Exit 66
 
Верх