Что нового

Идентификация всплывающих окон

alexbs

Новичок
Сообщения
11
Репутация
0
Требуется реагировать на всплывающие окна (предупреждения о неисправностях) 1С. Хочу использовать WinWate. Но встал вопрос об идентификации окон (т.е. предупреждений). По "Title" и "Class" они не различаются. "Handle" тоже ничего в данном случае не даёт. А больше Autoit Window Info и не показывает. Можно ли средствами Autoit читать (распознавать) сообщения с полей окон (я так понимаю они нарисованы в графике), чтобы соответствующим образом реагировать.
Прошу не бросать в меня сапогами, я только начал копать в сторону Autoit, ранее пытался использовать для этой цели nncron, но там такая же проблема с распознаванием окон.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
alexbs
Приведите, если возможно, скриншот такого окна
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Пример окна
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
alexbs
Попробуйте просканировать такое окно Control Viewer
http://autoit-script.ru/index.php?topic=4579.0
или
InqSoft Window Scanner
http://kickme.to/inqsoft

Если эти программы прочитают текст надписи(надпись может быть прикрыта каким-то другим элементом окна, но обе прожки позволяют такой элемент скрыть\деактивировать), от этого можно будет отталкиваться.

Также конкретнее опишите, что требуется - нужно ждать любое такое окно, или только окно с определенной надписью, или еще как?
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Эти сообщения выдаются на удалённых серверах. В зависимости от вида ошибки нужно посылать (скажем по почте) соответствующее предупреждающее сообщение. А ошибочный процесс 1С снять (при принудительном закрытии окна, если я правильно понимаю, сбрасывается вызвавший его процесс). Сообщение, как я думаю, любой просмотрщик окон может идентифицировать по title окна, class окна, instance соответствующего поля и ID соответствующей надписи в этом поле. Но как всё это передать для реагирования в соответствующие функции...
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
alexbs
Скрипт раз в 3 сек проверяет наличие окон с заданным заголовком, если надпись в окне содержит ключевую фразу, то подается сообщение(или можно это окно закрыть)

Вместо простого If можно вставить сложный
Код:
Select...Case...EndSelect
для разных надписей

Про почту и т.д. посмотрите на форуме, примеры точно были

Код:
#Include <WinAPIEx.au3>
$okno="Заголовок" ;заголовок окон с сообщениями - 1С и т.д.
While 1
$var = WinList($okno) ; получаем список окон	
For $n = 1 to $var[0][0]	
$aData = _WinAPI_EnumChildWindows($var[$n][1])
For $i= 1 To $aData[0][0]
$text=ControlGetText ($var[$n][1], "", $aData[$i][0])
If StringInStr($text, "Надпись") Then ; ключевая фраза
MsgBox(0,"","Есть окно с надписью "& $text)

;список действий- закрытие окна, отправка почты и т.д.
;WinClose ($var[$n][1], "")
Endif

Next
Next
sleep (3000)
Wend


WinAPIEx.au3 брать здесь http://autoit-script.ru/index.php?topic=47.0
Cкопировать в папку Include в папке Autoit
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Спасибо, скрипт рабочий, но только не для окон 1С. В этих окнах, повторюсь, просмотрщики (а значит и функция) никакого текста не видят. Можно определить окно по заголовку, Instance поля и ID надписи в поле. Т.е. скрипт должен при появлении окна с нужным заголовком (классом) проверять все Instance и сравнивать ID с заданными. (Хотя соответствие ID нужной надписи ещё нужно проверить, просто сообщения с ошибками появляются не так часто).
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
alexbs
Скрипт и делает это - при наличии окна 1С он должен перебрать все элементы окна, пока не найдет нужную надпись. Окна такого рода должны, по идее, читаться.

Если же нет, то можно пойти обходными путями, например, делать скриншоты окон и сравнивать их хэши с заранее сделанными образцами. (Пример такого скрипта выложу в ближайшее время, пока времение нет :-X )
Еще можно попытаться распозновать текст в окне с помощью программ OCR.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 712
alexbs сказал(а):
Спасибо, скрипт рабочий, но только не для окон 1С. В этих окнах, повторюсь, просмотрщики (а значит и функция) никакого текста не видят. Можно определить окно по заголовку, Instance поля и ID надписи в поле. Т.е. скрипт должен при появлении окна с нужным заголовком (классом) проверять все Instance и сравнивать ID с заданными. (Хотя соответствие ID нужной надписи ещё нужно проверить, просто сообщения с ошибками появляются не так часто).
То окно, которое на скриншоте, есть стандартный диалог Windows со всеми вытекающими последствиями. Другими словами, все Control... функции для него должны работать.

Что значит "никакого текста не видят"? Какая-нибудь рамка появляется?

P.S

Если ControlGetText() не возвращает текст, то возможно причина в кодировке (ANSI вместо Unicode). Попробуй изменить в Control Viewer кодировку (Options - Text Encoding - ...).
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Т.е. при наведении фокуса CV на надпись в окнах Color Picker и Capture изображение появляется, в Controls таблица Handle, Class, NN и ID для всех полей есть, а вот текста в Control - Text нет. Никакие кодировки не помогают. В окнах других программ - в этом поле замена кодировок действительно помогает получить текст вместо крякозябров, но здесь вообще ничего в этом поле нет.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 712
Значит 1С и здесь "постаралась".
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
При написании скрипта, работающего со скриншотами, столкнулся с проблемой -
функция
Код:
_ScreenCapture_CaptureWnd

каждый раз делает немного разные скрины окон, и хэши их не совпадают.
В то же время аналог - задача в программе xStarter вроде работает нормально :scratch: Могу ее выложить.

Также можно попробовать OCR. На этом компьютере нет случайно Офиса 2003?
Тогда можно неплохой пример написать, и нечитающиеся контролы без надобности :ok:
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
Пример с OCR средствами Офиса2003.
Самый качественный вариант для нечитаемых контролов.

Код:
#include <ScreenCapture.au3>
Dim $miDoc
Dim $oWord
Const $miLANG_ENGLISH = 9
Const $miLANG_RUSSIAN = 25

$temp="C:\Screen.bmp" ;файл скриншота
$okno="Заголовок" ;заголовок окон с сообщениями - 1С и т.д.
$text= ""

While 1
WinWait ($okno, "")
$var = WinList($okno) ; получаем список окон  
For $n = 1 to $var[0][0]    
WinActivate ($var[$n][1], "")
sleep (1000)
_ScreenCapture_CaptureWnd($temp,$var[$n][1],0,0,-1,-1, False)

;Распознаем текст сообщения:
Dim $test
    $miDoc = ObjCreate("MODI.Document")
    $miDoc.Create($temp)
    $miDoc.Ocr($miLANG_RUSSIAN, True, False)
For $oWord in $miDoc.Images(0).Layout.Words
$text= $text&" "&$oWord.text
Next
FileDelete($temp)
If StringInStr($text, "Ошибка") Then ; ключевая фраза
$text= ""
WinClose ($var[$n][1], "")
EndIf
Next
sleep (2000)
Wend


Варианты с хэшами скриншотов - на Win 7 из-за Аэро не работают точно, а на ХР тоже почему-то не идут. :scratch:
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Имеются ввиду сервера под Win2003, офисов на них нет ввиду ненадобности. По XStarter - я так понимаю это полный аналог nncron, который есть на серверах. Может быть nncron также позволяет снимать скриншот и сравнивать его по хэшу. Может быть кто-нибудь знает? Увы в языке Fort я также не силён, хотя можно попробовать задание XStartera переписать с Pascal на Fort.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
Кажется, примерный вариант со скриншотами добил :laugh:
(Предполагается, что текст сообщений стандартный и не меняется, т.е. число вариантов конечно и можно сделать скриншоты-эталоны). Предварительной работы, правда, много :smile:

Итак, два кода:

1) С помощью первого кода делаем скриншоты-эталоны.
При наличии окна сообщения запускаем данный код, он активизирует окно и делает скрин. Потом нужно сделать аналогичным способом скрин следующего сообщения и т.д.

Код:
#include <ScreenCapture.au3>
$File = "C:\1.bmp"
$okno="Заголовок";заголовок окон с сообщениями - 1С и т.д.
$pos=WinGetPos($okno,"")
$ClientSize=WinGetClientSize($okno,"")
WinWait ($okno, "")
WinActivate ($okno, "")
sleep(1000) 
_ScreenCapture_Capture($File, $pos[0]+7,$pos[1]+$pos[3]-$ClientSize[1], $pos[0]+$ClientSize[0]-7, $pos[1]+$pos[3]-7, False)


2) Основной код. Скрины-эталоны нужно переименовать последовательно -1.bmp, 2.bmp и т.д. При появлении окна(окон) с нужным заголовком скрипт активизирует это окно, делает скрин и сравнивает хэш с хэшами заранее сделанных эталонов. При равенстве хэшей окно закрывается и показывается соответствующее сообщение. Скрин делается не всего окна, а обрезанной клиентской части, тут можно еще поиграться с настройкой.

Код:
#include <ScreenCapture.au3>
HotKeySet("{ESC}", "_Exit"); выход по ESC

$okno="Заголовок" ;заголовок окон с сообщениями - 1С и т.д.
$File0 = "C:\Screen.bmp";файл временного скриншота, который сравнивается с эталонами
$File1 = "C:\1.bmp" ; файл первого скриншота-эталона
$File2 = "C:\2.bmp" ; файл второго скриншота-эталона
;$File3 = "C:\3.bmp" ; файл третьего скриншота-эталона и т.д.

While 1
WinWait ($okno, "")
$var = WinList($okno) ; получаем список окон  
For $n = 1 to $var[0][0]    
$pos=WinGetPos($var[$n][1],"")
$ClientSize=WinGetClientSize($var[$n][1],"")
WinActivate ($var[$n][1], "")
Sleep(1000)
;Получение временного скриншота
_ScreenCapture_Capture($File0, $pos[0]+7,$pos[1]+$pos[3]-$ClientSize[1], $pos[0]+$ClientSize[0]-7, $pos[1]+$pos[3]-7, False)

Select
Case _Hash($File1,$File0)= 1	
WinClose ($var[$n][1], "");действие 1 - закрытие n-го окна по хэндлу из массива
MsgBox(0, '', "Появилось окно №1"&@LF&"Окно было закрыто",3)
Case _Hash($File2,$File0)= 1
WinClose ($var[$n][1], "");действие 2 и т.д.
MsgBox(0, '', "Появилось окно №2"&@LF&"Окно было закрыто",3)
;Case _Hash($File3,$File0)= 1 ; и т.д.
EndSelect
Next
Sleep(5000)
WEnd

Func _Hash($str,$str2)
$hFile1 = FileOpen($str, 16)
$hFile2 = FileOpen($str2, 16)
$sTest1 = FileRead($hFile1)
$sTest2 = FileRead($hFile2)
if $sTest1 = $sTest2 then
Return 1
else
Return 0
endif
FileClose($hFile1)
FileClose($hFile2)
EndFunc
Func _Exit()
    Exit 0
EndFunc


Минусы этого варианта - если в сообщении появится хотя бы один новый символ, то определение не сработает. Плюс мелькание окошек - но так будет при любом способе.
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Большое спасибо, будем пробовать. А всё-таки скрипт из XStarter если нетрудно. :thumbs_up:

Опробовал на паре окон, вроде бы работает. Большое спасибо. Далее сам подшлифую.
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Увы, скрипт от WSWR работает только со свежими окнами, т.е. выскочившими одновременно и каптуренными. Более старые скриншоты скрипт в упор не видит. При сравнении скриншотов comp'ом показывает разницу в 10 байт, причём одних и тех же на скриншотах по порядковому номеру на разных серверах. То ли _ScreenCapture_Capture нумерует скриншоты, толи время и дату указывает. Посему прошу поделиться вариантом с XStarter.
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Время от времени новые окна совпадают со старыми и скрипт их закрывает. Только запускать его нужно через стандартный шедулер, т.к. постоянно слетает.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
361
Давно не заходил сюда

В приложенном файле пример для xStarter
(файл-загрузить задачу)

Еще может быть вариант с программой Kleptomania. Она позволяет копировать с экрана нечитаемые тексты
Правда, бесплатная версия Kleptomania 2.5, а последняя Kleptomania 2.6 - уже триал.

Или демо-версия ABBYY Screenshot Reader, триал 120 дней. http://www.abbyy.ru/download/screenshot_reader/ Сделать пример не трудно.
 
Автор
A

alexbs

Новичок
Сообщения
11
Репутация
0
Думал проблема решена, скрипты от WSWR (после оответствующей доработки ) поставлены на всех серверах, но выявилось следующее. Файл $File0, созданный функцией ScreenCapture_Capture($File0, $pos[0]+7,$pos[1]+$pos[3]-$ClientSize[1],
$pos[0]+$ClientSize[0]-7, $pos[1]+$pos[3]-7, False) не высвобождается до завершения работы скрипта. Т.е. при переборе окон в него пишется хэш только одного окна. Если активно окно 1С, которое не нужно, то скрипт ничего не делает, а только активирует окно-сообщение об ошибке, которое может быть убрано при следующем запуске скрипта. Но предыдущее окно тоже может быть до этого открыто шедулером, т.е. сообщение об ошибке будет долго висеть в скрытом виде и требовать действий. Кроме того, иногда 1С умудряется выдать под 30 одинаковых ошибочных сообщений одновременно. Попытки очищать в процессе работы скрипта файл хэша с помощью FileDelete, в комбинации с FileOpen, FileClose, FileFlush, FileSetAttrib (+"O") ничего не дали, файл блокирован до завершения скрипта. Попытки выделить функцию ScreenCapture_Capture($File0, $pos[0]+7,$pos[1]+$pos[3]-$ClientSize[1], $pos[0]+$ClientSize[0]-7, $pos[1]+$pos[3]-7, False) в отдельный внешний скрипт упираются в способ передачи ему параметров, т.е. окна, хэш которого нужно сохранить. Что тут можно сделать?
 
Верх