Что нового

Как идентифицировать контрол среди одинаковых

beaver

Новичок
Сообщения
58
Репутация
2
Добрый день.
Пытаюсь автоматизировать GUI написанное на умирающем Delphi.
Все контроллы автоматизируемого GUI определяются через Window Info примерно как на скриншоте в аттаче к сообщению. Т.е. есть Class, Instance.
Элементы прекрасно автоматизируются, если использовать, например значение из поля Advanced Mode == [CLASS:ClassName; INSTANCE:1]
Однако от сборки к сборке ПО инстанс у элементов меняется, т.е. если у EditBox был в первой сборке INSTANCE = 1, то может стать = 2, у другого элемента наоборот поменяется с 2 на 1.

Соответственно у меня вопрос - как правильно идентифицировать контрол, если их на форме несколько с одинаковым названием, а инстанс меняется от сборки к сборке (т.е. на него нельзя ориентироваться).
 
Автор
B

beaver

Новичок
Сообщения
58
Репутация
2
Общался с разработчиками автоматизируемого ПО. Они посоветовали обратиться к public - свойству класса объекта, который мне известен. Вопрос для меня теперь как это сделать?

Помогите пожалуйста - вопрос крайне важный!!! :(
 

Yashied

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

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
beaver
Вот пример на основе калькулятора. Допустим, нам надо умножить 9 на 3 и получить результат, но мы не знаем ни одного идентификатора.
Код:
#include <WinAPIEx.au3>

$sFirst = '9'
$sAction = '*'
$sSecond = '3'
$sResult = '='
$sActionResult = ''

Run('calc.exe')
$hWin = WinWait('[Class:SciCalc]', '', 3)
If Not $hWin Then Exit
$aData = _WinAPI_EnumChildWindows($hWin)
If @error Then Exit

For $i = 1 To $aData[0][0]
	If $aData[$i][1] == 'Button' Then
		If ControlGetText($hWin, '', $aData[$i][0]) == $sFirst Then
			ControlClick($hWin, '', $aData[$i][0])
			ExitLoop
		EndIf
	EndIf
Next
Sleep(100)
For $i = 1 To $aData[0][0]
	If $aData[$i][1] == 'Button' Then
		If ControlGetText($hWin, '', $aData[$i][0]) == $sAction Then
			ControlClick($hWin, '', $aData[$i][0])
			ExitLoop
		EndIf
	EndIf
Next
Sleep(100)
For $i = 1 To $aData[0][0]
	If $aData[$i][1] == 'Button' Then
		If ControlGetText($hWin, '', $aData[$i][0]) == $sSecond Then
			ControlClick($hWin, '', $aData[$i][0])
			ExitLoop
		EndIf
	EndIf
Next
Sleep(100)
For $i = 1 To $aData[0][0]
	If $aData[$i][1] == 'Button' Then
		If ControlGetText($hWin, '', $aData[$i][0]) == $sResult Then
			ControlClick($hWin, '', $aData[$i][0])
			ExitLoop
		EndIf
	EndIf
Next
Sleep(100)
For $i = 1 To $aData[0][0]
	If $aData[$i][1] == 'Edit' Then
		$sActionResult = ControlGetText($hWin, '', $aData[$i][0])
		ExitLoop
	EndIf
Next
$sActionResult = StringFormat('%2d', $sActionResult)

MsgBox(64, 'Info', $sFirst & $sAction & $sSecond & $sResult & $sActionResult)
WinAPIEx.au3.
 
Автор
B

beaver

Новичок
Сообщения
58
Репутация
2
madmasles сказал(а):
beaver
Вот пример на основе калькулятора. Допустим, нам надо умножить 9 на 3 и получить результат, но мы не знаем ни одного идентификатора.

Я, наверное, не совсем ясно объяснил свою проблему. Дело в том, что идентифицировать контролы у меня прекрасно получается, например по следующим параметрам:
Код:
[CLASS:TAG2Edit; INSTANCE:1]
[CLASS:TAG2Edit; INSTANCE:2]
Проблема в том, что номера INSTANCE этих контролов меняются от версии к версии ПО, которое я тестирую. Специально для меня разработчики ПО добавили в класс TAG2Edit свойство, которое уникально для каждого элемента. Это public property называется unicpath и мне надо как-то узнавать его значение. Узнаю его значение - значит узнаю к какому из INSTANCE мне надо обращаться. У меня вопрос именно в том как получить значение свойства класса? В WinApi не могу найти функцию, которая это делает.
 

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
Вроде никак. Если я не ошибаюсь, то из другой программы нельзя обратиться к свойствам объектов.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
beaver [?]
Проблема в том, что номера INSTANCE этих контролов меняются

Специально для меня разработчики ПО добавили в класс TAG2Edit свойство, которое уникально для каждого элемента

Попробуй так:
Код:
ControlGetHandle($hWin, "", "[REGEXPCLASS:TAG2Edit;.*]")

Handle уникален, вот с ним и работайте.
 
Автор
B

beaver

Новичок
Сообщения
58
Репутация
2
Попробуй так:
Код:
ControlGetHandle($hWin, "", "[REGEXPCLASS:TAG2Edit;.*]")

Handle уникален, вот с ним и работайте.
[/quote]

То что handle уникален у меня сомнений нет, но ведь он будет различаться от версии к версии тестируемого мной ПО? Разве не так?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Вы же писали!
beaver [?]
добавили в класс TAG2Edit свойство, которое уникально для каждого элемента
Следовательно, можно за него зацепиться [REGEXPCLASS:TAG2Edit;.*]
 

r35p3ct

Продвинутый
Сообщения
228
Репутация
60
Если instance меняется, скорее всего TAG2Edit находятся на разных родительских контролах, тогда через _WinAPI_EnumChildWindows($hWin), в $hWin указывать родительский контрол и не должно быть проблем.
 
Автор
B

beaver

Новичок
Сообщения
58
Репутация
2
Garrett сказал(а):
Вы же писали!
beaver [?]
добавили в класс TAG2Edit свойство, которое уникально для каждого элемента
Следовательно, можно за него зацепиться [REGEXPCLASS:TAG2Edit;.*]

Видимо, я туплю по-страшному... Если не сложно, то можно примерчик как зацепиться, если я знаю только название свойства класса в котором содержится уникальное значение? Меня на форуме все уверяют, что доступ к свойствам объектов получить из AutoIt нельзя.
В вашем примере я не понимаю, что означает маска .* - для чего она нужна и как она может мне помочь.


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

r35p3ct сказал(а):
Если instance меняется, скорее всего TAG2Edit находятся на разных родительских контролах, тогда через _WinAPI_EnumChildWindows($hWin), в $hWin указывать родительский контрол и не должно быть проблем.

Родительский элемент у них один TFrameOneEditor. Дело в том, что контролы расставляются при компиляции по форме самописной а-ля студией разработчиков - именно она и расставляет номера. Так что это не вариант.
 

r35p3ct

Продвинутый
Сообщения
228
Репутация
60
ну тогда значит только по координатам...
 

EqKeeper

Новичок
Сообщения
29
Репутация
1
Garrett
Ты немного не в теме. Имеется ввиду некий контрол из разряда Windows Forms (кстати, на чем пишем-с то? C++, Delphi?), у которого есть это самое свойство. В имени класса ничего подобного нет. :smile: А вот внутри...

beaver
Было бы здорово, если бы из AI можно было обратиться к ним, но тут, имхо, единственный вариант - чтобы разработчики нарисовали Dll'ку, которая будет возвращать хендл контрола (или что там записано в этом TAG2Edit), и которую ты сможешь вызвать из AI функцией DllCall
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
beaver
Единственное, что приходит в голову. Эти [CLASS:TAG2Edit; INSTANCE:n], как я понимаю, представляют собой пустые поля для ввода. Они, предполагаю, расположены друг над другом. Переберите их в цикле и определите их порядок расположения.
Вот очередной пример на основе калькулятора:
Код:
#include <Array.au3>
#include <WinAPIEx.au3>

$sClass = 'Button'
;$sClass = 'Static'
$j = 0
Dim $aResult[$j + 1][5]

Run('calc.exe')
$hWin = WinWait('[Class:SciCalc]', '', 3)
If Not $hWin Then Exit

$aData = _WinAPI_EnumChildWindows($hWin)
If Not IsArray($aData) Then Exit

For $i = 1 To $aData[0][0]
	If $aData[$i][1] == $sClass Then
		$j += 1
		ReDim $aResult[$j + 1][5]
		$aResult[$j][0] = $aData[$i][1]
		$aResult[$j][1] = $aData[$i][0]
		$aResult[$j][2] = _WinAPI_GetDlgCtrlID($aData[$i][0])
		$aTemp = ControlGetPos($hWin, '', $aData[$i][0])
		If Not @error Then
			For $q = 0 To 1
				$aResult[$j][$q + 3] = $aTemp[$q]
			Next
		EndIf
	EndIf
Next
$aResult[0][0] = 'Class name'
$aResult[0][1] = 'Handle'
$aResult[0][2] = 'ID'
$aResult[0][3] = 'X'
$aResult[0][4] = 'Y'

_ArraySort($aResult, 0, 1, 0, 4) ; 3 - по X, 4 по Y
_ArrayDisplay($aResult)
 
Автор
B

beaver

Новичок
Сообщения
58
Репутация
2
EqKeeper сказал(а):
Garrett
Ты немного не в теме. Имеется ввиду некий контрол из разряда Windows Forms (кстати, на чем пишем-с то? C++, Delphi?), у которого есть это самое свойство. В имени класса ничего подобного нет. :smile: А вот внутри...

beaver
Было бы здорово, если бы из AI можно было обратиться к ним, но тут, имхо, единственный вариант - чтобы разработчики нарисовали Dll'ку, которая будет возвращать хендл контрола (или что там записано в этом TAG2Edit), и которую ты сможешь вызвать из AI функцией DllCall

Пишут товарисчи на великом и ужасном Delphi - я его терпеть как ненавижу автоматизировать.
За подсказку с dll большое спасибо - попробую завтра поговорить с разрабами. Останется почитать мануал как работать с dll. Если мне по определенному запросу, например по уникальному имени поля будут возвращать handle этого контрола, то дальше будет дело техники.


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

madmasles сказал(а):
beaver
Единственное, что приходит в голову. Эти [CLASS:TAG2Edit; INSTANCE:n], как я понимаю, представляют собой пустые поля для ввода. Они, предполагаю, расположены друг над другом. Переберите их в цикле и определите их порядок расположения.
Вот очередной пример на основе калькулятора:

Спасибо за совет. Кому-то он действительно может пригодиться, но в моем случае взаимное расположение элементов может также меняться как и номера INSTANCE. Если бы не этот факт, то вариант действительно был бы рабочим.
 
Верх