You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/winGUI.py

343 lines
17 KiB

from http.server import BaseHTTPRequestHandler, HTTPServer
from pywinauto import win32defines, win32structures, win32functions
import pdb
import pywinauto
import json
import sys
import ctypes
import struct
import os
import select
import zlib
#Флаг отладки напрямую (не выполнять чтение буфера stdin)
mFlagIsDebug=False
#mPywinautoApplication=pywinauto.Application(backend="win32")
mPywinautoApplication=pywinauto.Application(backend="uia")
############################################
####Межпроцессное взаимодействие
############################################
#ProcessParentReadWaitString
def ProcessParentReadWaitString():
#Выполнить чтение строки
#ctypes.windll.user32.MessageBoxW(0, "Hello", "Your title", 1)
lResult = sys.stdin.buffer.readline()
#Вернуть потенциальные \n
lResult = lResult.replace(b'{{n}}',b'\n')
lResult = zlib.decompress(lResult[0:-1])
lResult = lResult.decode("utf-8")
#Вернуть результат
return lResult
#ParentProcessWriteString
def ProcessParentWriteString(lString):
lByteString = zlib.compress(lString.encode("utf-8"))
#Выполнить отправку строки в родительский процесс
#Вернуть потенциальные \n
lByteString = lByteString.replace(b'\n',b'{{n}}')
sys.stdout.buffer.write(lByteString+bytes("\n","utf-8"))
sys.stdout.flush();
return
#ProcessParentWriteObject
def ProcessParentWriteObject(inObject):
#Выполнить отправку сконвертированного объекта в JSON
ProcessParentWriteString(json.dumps(inObject))
return
#ProcessParentReadWaitObject
def ProcessParentReadWaitObject():
#Выполнить получение и разбор объекта
lResult=json.loads(ProcessParentReadWaitString());
return lResult;
##################################
###Методы взаимодействия с GUI интерфейсом
##################################
#pywinauto
def GetControl(inControlSpecificationArray):
#Подготовка взодного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту
lRPAApplication = mPywinautoApplication
#Проверка разрядности
lRPAApplication.connect(**inControlSpecificationArray[0])
lTempObject=lRPAApplication.window(**inControlSpecificationArray[0])
#Циклическое прохождение к недрам объекта
for lWindowSpecification in inControlSpecificationArray[1:]:
lTempObject=lTempObject.window(**lWindowSpecification)
return lTempObject
#Выполнить действие над элементом
def ElementRunAction(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}):
#Определить объект
lObject=GetControl(inControlSpecificationArray)
#Получить метод для вызова
lFunction = getattr(lObject.wrapper_object(), inActionName)
#Выполнить действие
lFunction(*inArgumentList,**inkwArgumentObject)
return
def ElementGetInfo(inControlSpecificationArray):
#Подготовка входного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту
lRPAApplication = mPywinautoApplication
#Проверка разрядности
lRPAApplication.connect(**inControlSpecificationArray[0])
lTempObject=lRPAApplication.window(**inControlSpecificationArray[0])
#Циклическое прохождение к недрам объекта
for lWindowSpecification in inControlSpecificationArray[1:]:
lTempObject=lTempObject.window(**lWindowSpecification)
#Получить инфо объект
lTempObjectInfo = lTempObject.wrapper_object().element_info
#Добавить информацию об обнаруженом объекте
lResultList.append(ElementInfoExportObject(lTempObjectInfo));
return lResultList
#debug
def ElementGetChildElementList(inControlSpecificationArray=[]):
#Подготовка входного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
#ctypes.windll.user32.MessageBoxW(0, str(inControlSpecificationArray), "Your title", 1)
if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту
lRPAApplication = mPywinautoApplication
lRPAApplication.connect(**inControlSpecificationArray[0])
lTempObject=lRPAApplication.window(**inControlSpecificationArray[0])
#Циклическое прохождение к недрам объекта
for lWindowSpecification in inControlSpecificationArray[1:]:
lTempObject=lTempObject.window(**lWindowSpecification)
#Получить список дочерних объектов
lTempChildList = lTempObject.wrapper_object().children()
#Подготовить результирующий объект
for lChild in lTempChildList:
lTempObjectInfo=lChild.element_info
#Добавить информацию об обнаруженом объекте
lResultList.append(ElementInfoExportObject(lTempObjectInfo));
else:
lResultList=GetRootElementList()
return lResultList
#Подготовить массив для обращшения к поиску элемементов
def ElementSpecificationArraySearchPrepare(inControlSpecificationArray):
lResult=[]
#Циклический обход
for lSpecificationItem in inControlSpecificationArray:
lSpecificationItemNew=lSpecificationItem.copy()
#Перебор всех элементов
for lItemKey,lItemValue in lSpecificationItem.items():
#Флаг удаления атрибута
lFlagRemoveAttribute=False
#############################
#Если является вложенным словарем - удалить
if type(lItemValue) is dict:
lFlagRemoveAttribute=True
#Является типом None
if lItemValue is None:
lFlagRemoveAttribute=True
#Проверка допустимого ключевого слова
if (
lItemKey == "class_name" or
lItemKey == "class_name_re" or
lItemKey == "parent" or
lItemKey == "process" or
lItemKey == "title" or
lItemKey == "title_re" or
lItemKey == "top_level_only" or
lItemKey == "visible_only" or
lItemKey == "enabled_only" or
lItemKey == "best_match" or
lItemKey == "handle" or
lItemKey == "ctrl_index" or
lItemKey == "found_index" or
lItemKey == "predicate_func" or
lItemKey == "active_only" or
lItemKey == "control_id" or
lItemKey == "control_type" or
lItemKey == "auto_id" or
lItemKey == "framework_id" or
lItemKey == "backend"):
True == True
else:
lFlagRemoveAttribute=True
#############################
#Конструкция по удалению ключа из словаря
if lFlagRemoveAttribute:
lSpecificationItemNew.pop(lItemKey)
#Добавить строку в результирующий массив
lResult.append(lSpecificationItemNew)
#Вернуть результат
return lResult
#Получить объект из атрибутов, которые удалось прочитать
def ElementInfoExportObject(inElementInfo):
#Подготовить выходную структуру данных
lResult = {"name":None,"rich_text":None,"process_id":None,"handle":None,"class_name":None,"control_type":None,"control_id":None,"rectangle":{"left":None,"top":None,"right":None,"bottom":None}, 'runtime_id':None}
#Проверка name
try:
lResult['name']=inElementInfo.name
except Exception as e:
True == False
#Проверка rich_text
try:
lResult['rich_text']=inElementInfo.rich_text
except Exception as e:
True == False
#Проверка process_id
try:
lResult['process_id']=inElementInfo.process_id
except Exception as e:
True == False
#Проверка handle
try:
lResult['handle']=inElementInfo.handle
except Exception as e:
True == False
#Проверка class_name
try:
lResult['class_name']=inElementInfo.class_name
except Exception as e:
True == False
#Проверка control_type
try:
lResult['control_type']=inElementInfo.control_type
except Exception as e:
True == False
#Проверка control_id
try:
lResult['control_id']=inElementInfo.control_id
except Exception as e:
True == False
#Проверка rectangle left
try:
lResult['rectangle']['left']=inElementInfo.rectangle.left
except Exception as e:
True == False
#Проверка rectangle right
try:
lResult['rectangle']['right']=inElementInfo.rectangle.right
except Exception as e:
True == False
#Проверка rectangle top
try:
lResult['rectangle']['top']=inElementInfo.rectangle.top
except Exception as e:
True == False
#Проверка rectangle bottom
try:
lResult['rectangle']['bottom']=inElementInfo.rectangle.bottom
except Exception as e:
True == False
#Проверка runtime_id
try:
lResult['runtime_id']=inElementInfo.runtime_id
except Exception as e:
True == False
#Вернуть результат
return lResult
def GetRootElementList():
#Получить список объектов
lResultList=pywinauto.findwindows.find_elements()
lResultList2=[]
for lI in lResultList:
lTempObjectInfo=lI
lResultList2.append(ElementInfoExportObject(lI));
return lResultList2
def ElementDrawOutlineNew(inSpecificationArray):
draw_outline_new(GetControl(inSpecificationArray))
return
def draw_outline_new(lWrapperObject,colour='green',thickness=2,fill=win32defines.BS_NULL,rect=None):
"""
Draw an outline around the window.
* **colour** can be either an integer or one of 'red', 'green', 'blue'
(default 'green')
* **thickness** thickness of rectangle (default 2)
* **fill** how to fill in the rectangle (default BS_NULL)
* **rect** the coordinates of the rectangle to draw (defaults to
the rectangle of the control)
"""
#pdb.set_trace()
# don't draw if dialog is not visible
#if not lWrapperObject.is_visible():
# return
colours = {
"green": 0x00ff00,
"blue": 0xff0000,
"red": 0x0000ff,
}
# if it's a known colour
if colour in colours:
colour = colours[colour]
if rect is None:
rect = lWrapperObject.rectangle()
# create the pen(outline)
pen_handle = win32functions.CreatePen(
win32defines.PS_SOLID, thickness, colour)
# create the brush (inside)
brush = win32structures.LOGBRUSH()
brush.lbStyle = fill
brush.lbHatch = win32defines.HS_DIAGCROSS
brush_handle = win32functions.CreateBrushIndirect(ctypes.byref(brush))
# get the Device Context
dc = win32functions.CreateDC("DISPLAY", None, None, None )
# push our objects into it
win32functions.SelectObject(dc, brush_handle)
win32functions.SelectObject(dc, pen_handle)
# draw the rectangle to the DC
win32functions.Rectangle(
dc, rect.left, rect.top, rect.right, rect.bottom)
# Delete the brush and pen we created
win32functions.DeleteObject(brush_handle)
win32functions.DeleteObject(pen_handle)
# delete the Display context that we created
win32functions.DeleteDC(dc)
#run()
lText = "Bitness:" + str(struct.calcsize("P") * 8)
#for line in sys.stdin:
# lText=lText+line;
#ctypes.windll.user32.MessageBoxW(0, lText, "Your title", 1)
buffer = ""
lJSONInputString=""
#Выполнить чтение буфера, если не отладка библиотеки
if not mFlagIsDebug:
#{'functionName':'', 'argsArray':[]}
while True:
try:
lJSONInput = ProcessParentReadWaitObject()
lJSONInputString=str(lJSONInput)
#{'outputObject':''}
#Выполнить вызов функции
lResult=locals()[lJSONInput['functionName']](*lJSONInput['argsArray'])
lJSONInput['outputObject']=lResult
ProcessParentWriteObject(lJSONInput)
except Exception as e:
#Вывод ошибки в родительский поток
ProcessParentWriteObject({'Error':str(e), 'ArgObject':str(lJSONInputString)})
else:
print('Debug mode is turned on!')
#if __name__ == '__main__':
# if len(sys.argv) > 1:
# lFunctionArgs = sys.argv[2:]
# print(locals()[sys.argv[1]](*lFunctionArgs))