Что нового

_WinWaitOwner() - Ожидание окна дочернего к заданному

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Функция аналогична WinWait(), с той лишь разницей, что можно задать проверку для искомого окна $sTitle, является ли оно дочерним для родительского окна $sOwner. _WinWaitOwner() будет незаменима в случае, если присутствуют несколько окон с одинаковыми заголовками, например "Save As".


Код:
;Opt('WinWaitDelay', 0)

Run('Notepad.exe')
If Not WinWait('Untitled - Notepad', '', 3) Then
	Exit
EndIf
Send('^s')
If Not WinWait('Save As', '', 3) Then
	Exit
EndIf
$hWnd = _WinWaitOwner('Save As', '', 'Untitled - Notepad', 3)
If $hWnd Then
	WinMove($hWnd, '', 10, 10)
EndIf

Func _WinWaitOwner($sTitle, $sText = '', $sOwner = 0, $iTimeOut = 0)

	Local $hWnd, $List, $Ret, $Timer = TimerInit()

	$iTimeOut = Round($iTimeOut * 1000)

	While 1
		$List = WinList($sTitle, $sText)
		If $List[0][0] Then
			If Not $sOwner Then
				$hWnd = $List[1][1]
				ExitLoop
			Else
				$hWnd = WinGetHandle($sOwner)
				If IsHWnd($hWnd) Then
					For $i = 1 To $List[0][0]
						$Ret = DllCall('user32.dll', 'hwnd', 'GetWindow', 'hwnd', $List[$i][1], 'uint', 4)
						If (Not @error) And ($Ret[0] = $hWnd) Then
							$hWnd = $List[$i][1]
							ExitLoop 2
						EndIf
					Next
				EndIf
			EndIf
		EndIf
		If ($iTimeOut) And (TimerDiff($Timer) > $iTimeOut) Then
			Return 0
		EndIf
		Sleep(10)
	WEnd
	Sleep(Opt('WinWaitDelay'))
	Return $hWnd
EndFunc   ;==>_WinWaitOwner
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Хорошая идея, но есть пару заметок..

* Если я выставлю Opt('WinWaitDelay', 0) в своём скрипте, то функция нагружает процессор, т.к В Sleep будет 0. WinWaitDelay в данном случае не имеет связи с WinWait, оно влияет на паузу до начала ожидания окна.

* Я бы сделал эту функцию так (особо не тестировал, но вроде работает):

Код:
#include <WinAPI.au3>

Run('Notepad.exe')
If Not WinWait('[REGEXPCLASS:.*Notepad.*]', '', 3) Then Exit 1

Send('^s')
If Not WinWait('[REGEXPTITLE:^(?i)(Сохранить как|Save As)$]', '', 3) Then Exit

$hWnd = _WinWaitOwner('[REGEXPTITLE:^(?i)(Сохранить как|Save As)$]', '', '[REGEXPCLASS:.*Notepad.*]', 10)
If IsHWnd($hWnd) Then WinMove($hWnd, '', 10, 10)

Func _WinWaitOwner($sTitle, $sText = '', $sOwner = 0, $iTimeOut = 0)
    Local $hWnd, $hOwner, $WaitRet, $Parent, $Timer = TimerInit()
	
	$hOwner = WinGetHandle($sOwner)
    $iTimeOut = Round($iTimeOut * 1000)
	
	While 1
		$WaitRet = WinWait($sTitle, $sText, 1)
		$hWnd = WinGetHandle($sTitle, $sText)
		
		If $WaitRet And $sOwner <> '' Then
			$Parent = _WinAPI_GetParent($hWnd)
			If $Parent = $hOwner Then Return $hWnd
		ElseIf $WaitRet Then
			Return $hWnd
		EndIf
		
		If $iTimeOut And TimerDiff($Timer) > $iTimeOut Then Return 0
	WEnd
	
	Return 0
EndFunc
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
CreatoR,

Про WinWaitDelay согласен (позже разберусь), но с остальным...

Ты упустил основную идею этой функции.

Yashied сказал(а):
...будет незаменима в случае, если присутствуют несколько окон с одинаковыми заголовками, например "Save As".

Именно для этого я ее и написал, см. так же этот пост. Твой пример этого не учитывает.

:smile:
 

vcomp71

Осваивающий
Сообщения
431
Репутация
25
Что-то длинно слишком... А чем мой вариант не устроил? Конечно е=не все исключения отработаны, но зато работать должна быстро... Вообще из-за недостатка опыта судит сложно, мне вот одно странно, почему разработчики такой вариант не предусмотрели?

Кстати вопрос: где-то в недрах api функций, есть такая функция, которая проверяет, окно подчиненное или родительское... Да и вообще проверка по заголовку окна - чревата, тут только по pid проверять надо... Большая вероятность, что один из процессов создаст окно с одинаковым заголовками... Например - висят два блокнота одновременно открытых.. Заголовки у обоих - одинаковые...
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Yashied [?]
Ты упустил основную идею этой функции
Пример можно? Я если честно не пойму как функция их (окна) различает.


Добавлено:
Сообщение автоматически объединено:

Поправил немного функцию, теперь проверяется если найденное окно имеет родителя $sOwner :smile:


Добавлено:
Сообщение автоматически объединено:

Vlasssov
Я как то давно писал библиотеку для работы с окнами, там конечно многое устарело, но всё же она может быть полезной: Библиотека для работы с заголовками окон и процессами

Скоро пересмотрю её и выложу тут на форуме.
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Функцию поправил, убрал WinWaitDelay.


CreatoR сказал(а):
Пример можно? Я если честно не пойму как функция их (окна) различает.

Код:
Run('notepad.exe')
Sleep(500)
Send('^s')
Sleep(500)
Run('mspaint.exe')
Sleep(500)
Send('^s')
Sleep(500)

$hWnd = _WinWaitOwner('Save As', '', 'Untitled - Notepad', 1)
If $hWnd Then 
	WinMove($hWnd, '', 10, 10)
EndIf


Твоя функция не сработает в этом случае, а моя - да. :smile:


Vlasssov сказал(а):
Кстати вопрос: где-то в недрах api функций, есть такая функция, которая проверяет, окно подчиненное или родительское...

Я ее здесь и использую.

Код:
DllCall('user32.dll', 'hwnd', 'GetWindow', 'hwnd', $hWnd, 'uint', $GW_OWNER)



Vlasssov сказал(а):
Да и вообще проверка по заголовку окна - чревата, тут только по pid проверять надо...

Лучше по хэндлу.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Yashied [?]
Твоя функция не сработает в этом случае, а моя - да
А что собственно должно сработать? у меня и с твоей ничего не произошло (паузу увеличил чтобы убедиться в появлений обеих окон).


Добавлено:
Сообщение автоматически объединено:

Yashied
Всё понял, я неверно оценил ситуацию, без WinList видимо не обойтись.


Добавлено:
Сообщение автоматически объединено:

Yashied [?]
Функцию поправил, убрал WinWaitDelay
Возможно стоит её добавить в качестве паузы в конец (на возврате) функций? Так будет ближе к оригиналу :smile:

Код:
Func _WinWaitOwner($sTitle, $sText = '', $sOwner = 0, $iTimeOut = 0)
	Local $hWnd, $List, $Ret, $WWDelay_Opt, $Timer
	
	$WWDelay_Opt = Opt("WinWaitDelay")
	$Timer = TimerInit()
	$iTimeOut = Round($iTimeOut * 1000)
	
	While 1
		If $iTimeOut And TimerDiff($Timer) > $iTimeOut Then Return 0
		
		$List = WinList($sTitle, $sText)
		If @error Then ContinueLoop
		
		If Not $sOwner Then Return SetExtended(Number(Sleep($WWDelay_Opt) = 0), $List[1][1])
		
		$hWnd = WinGetHandle($sOwner)
		If Not IsHWnd($hWnd) Then ContinueLoop
		
		For $i = 1 To $List[0][0]
			$Ret = DllCall('user32.dll', 'hwnd', 'GetWindow', 'hwnd', $List[$i][1], 'uint', 4)
			If Not @error And $Ret[0] = $hWnd Then Return SetExtended(Number(Sleep($WWDelay_Opt) = 0), $List[$i][1])
		Next
		
		Sleep(1)
	WEnd
EndFunc


P.S
И возможно лучше если пример будет более универсален (заголовки)?
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Вообщем у тебя получилась такая же функция, как у меня.

:smile:


Добавлено:
Сообщение автоматически объединено:

Просто добавить WinWaitDelay будет некорректно, нужно ее сопоставить с параметром $iTimeOut. В противнов случае функция будет еще более далека от WinWait().
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Yashied [?]
у тебя получилась такая же функция, как у меня.
Так это твоя, я просто её немного оптимизировал.

Просто добавить WinWaitDelay будет некорректно, нужно ее сопоставить с параметром $iTimeOut
Почему, в справке написано что на выходе ставится пауза, как на это влияет таймер?
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
А я по своему...
 

vcomp71

Осваивающий
Сообщения
431
Репутация
25
У меня вопрос по поводу использования sleep...
Дело в том, что разные машин обладают разной производительностью. На одной машине форма будут загружаться n миллисекунд, на другой n1 миллисекунд. Я вот начал юзать AutoiT потому что возникла задача ввести 6 тысяч наименований в программу, формат данный которой неизвестен, потому и пришлось, как написали на официальном сайте "рубить интерфейс программы" (huck application interface) . Ту каждая задержка на счету. Когда программа работает 4 часа, и мышкой не пошевелишь...

Да и вообще использование задержек не очень корректно с точки зрения алгоритма - а вдруг задержки не хватит?
Есть способ как-то их избежать? Перебирать окна в цикле - тоже не вариант, кто знает сколько их пользователь понаоткрывает...
 

vcomp71

Осваивающий
Сообщения
431
Репутация
25
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
О какой именно задержки идет речь?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Vlasssov [?]
Потому что у вас sleep в функции при переборе окон используется
Ну там ещё много чего используется, не задавать же вопросы про каждую функцию в этой теме?
 
Верх