Что нового

[Окна, Диалоги] Есть ли какая-нибудь возможность прочитать контекстное меню?

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Правым кликом мыши по иконке приложения в трее вызывается контекстное меню, которое представляет из себя окошко с некоторыми возможными действиями. Из всех свойств данного окошка Win Info видит только:
Class: #32768
Position: 1465, 743
Size: 118, 115
Style: 0x94800000
ExStyle: 0x00000189
Handle: 0x000B054A
По данному Handle или Class можно обращаться к окну, например, перемещать его по экрану. Но прочитать текст не получается. Есть ли какая-нибудь возможность справиться с данной задачей?
 

InnI

AutoIT Гуру
Сообщения
4 463
Репутация
1 209
Есть ли какая-нибудь возможность прочитать контекстное меню?

vitaliy4us [?]
возможность справиться с данной задачей
1. Отправить этому окну сообщение, получить идентификатор меню, использовать этот идентификатор в функциях GuiMenu.au3
Код:
#include <GuiMenu.au3>
#include <SendMessage.au3>

$hWnd = WinWait("[class:#32768]")
$hMenu = _SendMessage($hWnd, 0x01E1) ; MN_GETHMENU
For $i = 0 To _GUICtrlMenu_GetItemCount($hMenu) - 1
  ConsoleWrite(_GUICtrlMenu_GetItemText($hMenu, $i) & @CRLF)
Next


2. Использовать UIAutomate
Код:
#include "UIAutomate.au3"

$hWnd = WinWait("[class:#32768]")
$oParent = _UIA_GetElementFromHandle($hWnd)
$aElements = _UIA_FindAllElements($oParent, "ControlType", $UIA_MenuItemControlTypeId)
For $i = 1 To $aElements[0]
  ConsoleWrite(_UIA_ElementGetPropertyValue($aElements[$i], "Name") & @CRLF)
Next
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Первый вариант не прокатил. Выводит пустые строки, причем количество пустых строк на 3 больше, чем существует строк в меню. Со вторым вариантом надо разбираться с UIAutomate.au3.
 

InnI

AutoIT Гуру
Сообщения
4 463
Репутация
1 209
vitaliy4us [?]
Со вторым вариантом надо разбираться
Прежде, чем разбираться, запустите Inspect (там есть ссылка) и посмотрите видит ли эта утилита пункты. Если в Inspect свойство "Name" для пунктов меняться не будет, то, вероятно, вам уже ничего не поможет. Подобные "меню" я встречал.
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Спасибо, только не понял где взять утилиту Inspect.
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Нашел, спасибо, мощная вещь. Но только тоже текста не видит. Видит, что меню, видит 7 элементов меню (4 строки и 3 разделителя), а текста, увы, нет.
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
LegacyIAccessible.Name = ""
LegacyIAccessible.Value = ""
 

InnI

AutoIT Гуру
Сообщения
4 463
Репутация
1 209
Вероятно, хитрые разработчики рисуют текст поверх окна. Тут, видимо, только OCR поможет.
С другой стороны, пункты меню, как правило, местами не меняются. Поэтому таким меню можно управлять, посылая нужное количество раз down. Но для этого, конечно, нужно заранее знать, где находится пункт.
Код:
WinWait("[class:#32768]")
Send("{down 4}{enter}")
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Тут ситуация даже проще, меню срабатывает, если послать ему первую букву соответствующей строки. Просто, стоит вопрос автоматизации тест-кейса. Планировалось, сначала, протестировать открытие контекстного меню, которое может выглядеть по-разному (без подключения к серверу по TCP/IP оно состоит из одного набора строк, а при подключении появляются дополнительные строки). А уже в другом тест-кейсе планировалось тестировать непосредственно работу данного контекстного меню.
 

Naisho

Знающий
Сообщения
86
Репутация
12
Давненько пользуюсь - посмотрите может себе адаптируете
(идея - кликаете правой кнопкой где то, чтобы появилось контекстное меню, затем вызываете эту функцию с параметром - текстом пункта меню где надо кликнуть)
Код:
Func Click_RightClickMenu($sRequired_Text = "")
	Local $previousMousePos, $hWnd, $hMenu, $iCount, $iIndex, $sText, $aPos, $iOldOpt
	$previousMousePos = MouseGetPos()
	If $sRequired_Text = "" Then Return SetError(1)
	If WinExists("[CLASS:#32768]") Then
		$hWnd = WinGetHandle("[CLASS:#32768]")
		$hMenu = _SendMessage($hWnd, $MN_GETHMENU, 0, 0)
		If _GUICtrlMenu_IsMenu($hMenu) Then
			$iCount = _GUICtrlMenu_GetItemCount($hMenu)
			For $iIndex = 0 To $iCount - 1
				$sText = StringReplace(_GUICtrlMenu_GetItemText($hMenu, $iIndex),"&","")
				;ConsoleWrite($sText&@CRLF)
				If $sText == $sRequired_Text Then
					$aPos = _GUICtrlMenu_GetItemRect($hWnd, $hMenu, $iIndex)
					$iOldOpt = Opt("MouseCoordMode", 0)
					MouseClick("primary", $aPos[0] + ($aPos[2] - $aPos[0]) / 10, $aPos[1] + ($aPos[3] - $aPos[1]) / 2, 1, 1) ; Adjust the speed to suit
					Opt("MouseCoordMode", $iOldOpt)
				EndIf
			Next
		EndIf
	EndIf
	Sleep(10)
	MouseMove($previousMousePos[0], $previousMousePos[1], 0)
EndFunc   ;==>Click_RightClickMenu
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Naisho сказал(а):
Давненько пользуюсь - посмотрите может себе адаптируете
(идея - кликаете правой кнопкой где то, чтобы появилось контекстное меню, затем вызываете эту функцию с параметром - текстом пункта меню где надо кликнуть)
Как я понимаю, это то, что предлагалось InnI в первом варианте. И работает с тем же успехом (т.е. выдает семь пустых строк)


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

InnI сказал(а):
vitaliy4us [?]
протестировать открытие контекстного меню
Код:
PixelChecksum()
для всего меню или для каждого пункта.
Это вряд ли. Тем более, учитывая возможные изменения интерфейса.
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Меня терзают смутные сомненья: "Возможной причиной возврата пустой строки может являться то, что контекстное меню имеет две колонки, в первой из которых находится иконка, а во второй - непосредственно нужная строка. Похоже на то, что возвращаемая строка принадлежит первой колонке - т.е. иконке. В таком случае, как добраться до второй?"
 

InnI

AutoIT Гуру
Сообщения
4 463
Репутация
1 209
vitaliy4us [?]
Возможной причиной
Откуда у вас такая информация?

Что вообще у вас за программа? На каком языке она написана, знаете? Может это антивирус какой-нибудь?
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Программа написана на Delphi. Все контекстные меню, состоящие из одной колонки читаются без проблем с использованием Вашего совета (Вариант 1). И только это контекстное меню, в котором есть две колонки (в первой иконка опции, а во второй - сама опция). Кстати, ковыряя в данном направлении, пришел к неожиданному результату: в результате работы цикла присвоения текста строкам меню, с последующим отображением результата:
Код:
For $i = 0 to _GUICtrlMenu_GetItemCount($hMenu) - 1
	_GUICtrlMenu_SetItemText($hMenu, $i, "Item" & $i)
Next

For $i = 0 to _GUICtrlMenu_GetItemCount($hMenu) - 1
	$text = _GUICtrlMenu_GetItemText($hMenu, 0, $MF_BYPOSITION)
	ConsoleWrite("This is a text of the item " & $i & ": " & $text & @CRLF)
Next


получаем следующее:

This is a text of the item 0: Item0
This is a text of the item 1: Item1
This is a text of the item 2: Item2
This is a text of the item 3: Item3
This is a text of the item 4: Item4
This is a text of the item 5: Item5
This is a text of the item 6: Item6

А, сам текст нигде в контекстном меню не отображается. Изображение контекстного меню прилагаю.
 

Вложения

InnI

AutoIT Гуру
Сообщения
4 463
Репутация
1 209
vitaliy4us
Ваши изыскания косвенно подтверждают то, что текст пункта просто рисуется. Меню создаётся с пустыми пунктами, а потом в нужном месте рисуется текст. Для Delphi это нормальная практика. Так, например, у них Label сделан. Поэтому либо PixelChecksum(), либо OCR.
 
Автор
V

vitaliy4us

Новичок
Сообщения
158
Репутация
3
Приходится признать, что скорее всего, Вы правы.
 
Верх