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 import win32api import time from threading import Timer mFlagIsDebug=False mPywinautoApplication=pywinauto.Application(backend="win32") #mPywinautoApplication=pywinauto.Application(backend="uia") ##### ##Внимание! Нельзя делать print так как он уходит в родительский поток и ломает механизм взаимодействия ##Чтобы его использовать надо писать функцию обертку ##### ########################### ####Модуль Automation ########################### #inElementSpecificationList = [ [{lvl_0},{lvl_1},{lvl_2}],... ] #result = pywinauto element wrapper instance or None def AutomationSearchMouseElement(inElementSpecification): lBitmap={} lGUISearchElementSelected=None #Создать карту пикселей и элементов lBitmap=GUISearchBitmapCreate(GetControl(inElementSpecification),lBitmap) #Выдать сообщение, что поиск готов к использованию #print("GUISearch: Ready for search!") ########### #Версия с задержкой (без таймеров, событий в отдельных потоках) ########### #Сбросить нажатие Ctrl, если оно было bool(win32api.GetAsyncKeyState(17)) #Настройка - частота обновления подсвечивания lTimeSleepSeconds=0.7 lFlagLoop = True while lFlagLoop: #Проверить, нажата ли клавиша Ctrl (код 17) lFlagKeyPressedCtrl=bool(win32api.GetAsyncKeyState(17)) #Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз if not lFlagKeyPressedCtrl: #Получить координаты мыши (lX,lY) = win32api.GetCursorPos() #Подсветить объект, если мышь над ним if (lX,lY) in lBitmap: if lGUISearchElementSelected != lBitmap[lX,lY]: lGUISearchElementSelected = lBitmap[lX,lY] #Классическая функция отрисовки (из pywinauto) #lBitmap[lX,lY].draw_outline() #Доработанная функция отрисовки draw_outline_new(lBitmap[lX,lY]) else: lGUISearchElementSelected = None else: #Была нажата клавиша Ctrl - выйти из цикла lFlagLoop=False; #Заснуть до следующего цикла time.sleep(lTimeSleepSeconds) #Вернуть результат поиска return lGUISearchElementSelected def AutomationSearchMouseElementHierarchy(inElementSpecification): lItemInfo = None #Запустить функцию поиска элемента по мыши lElement = AutomationSearchMouseElement(inElementSpecification) #Detect backend of the elements lFlagIsBackendWin32 = True if lElement.backend.name == 'uia': lFlagIsBackendWin32 = False #Если объект имеется (не None), то выполнить построение иерархии if lElement is not None: #Циклическое создание дерева while lElement is not None: #Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None if not lFlagIsBackendWin32 and lElement.parent() is None: lElement = None else: #Получить информацию про объект lItemInfo2 = ElementInfoExportObject(lElement.element_info) #Дообогатить информацией об индексе ребенка в родительском объекте lItemInfo2['ctrl_index']=PywinautoExtElementCtrlIndexGet(lElement) #Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников lItemInfo2['SpecificationChild']=[lItemInfo] lItemInfo=lItemInfo2 #Переход на родительский объект lElement = lElement.parent() #Вернуть результат return [lItemInfo] #return [1,2,3,4,5,3] ########################### ####Модуль PywinautoExt ########################### def PywinautoExtElementCtrlIndexGet(inElement): lResult = None #Выполнить алгоритм, если есть Element if inElement is not None: lElementParent = inElement.parent() if lElementParent is not None: lResult = 0 lFlagFind = True #Получить список потомков lElementParentChildrenList = lElementParent.children() #Циклический поиск до того момента, пока не упремся в текущий элемент while lFlagFind: #Прекратить поиск, если элемент был обнаружен if inElement == lElementParentChildrenList[lResult]: lFlagFind = False else: #Прекратить поиски, если итератор вышел за пределы списка if lResult>=len(lElementParentChildrenList): lResult = None lFlagFind = False else: lResult = lResult + 1 #Вернуть результат return lResult ################################ #Функция повторяющегося таймера ############################# class RepeatedTimer(object): def __init__(self, interval, function, *args, **kwargs): self._timer = None self.interval = interval self.function = function self.args = args self.kwargs = kwargs self.is_running = False self.start() def _run(self): self.is_running = False self.start() self.function(*self.args, **self.kwargs) def start(self): if not self.is_running: self._timer = Timer(self.interval, self._run) self._timer.start() self.is_running = True def stop(self): self._timer.cancel() self.is_running = False #mTimer.start() # after 30 seconds, "hello, world" will be printed #Флаг отладки напрямую (не выполнять чтение буфера stdin) ############################################ ####Межпроцессное взаимодействие ############################################ #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}}}') #Вернуть \r lByteString = lByteString.replace(b'\r',b'{{{r}}}') #Вернуть \0 lByteString = lByteString.replace(b'\0',b'{{{0}}}') #Вернуть \a lByteString = lByteString.replace(b'\a',b'{{{a}}}') #Вернуть \b lByteString = lByteString.replace(b'\b',b'{{{b}}}') #Вернуть \t lByteString = lByteString.replace(b'\t',b'{{{t}}}') #Вернуть \v lByteString = lByteString.replace(b'\v',b'{{{v}}}') #Вернуть \f lByteString = lByteString.replace(b'\f',b'{{{f}}}') ############################ #print(b"Result: "+lByteString) #lByteString= b'x\x9c\xdd\x95]O\xc20\x14\x86\xffJ\xb3[5\xa1Cqz\x07\xc4\xe8\x8d\x1fQ\x13.\x0cYJw\xb6U\xbav\xe9\xce"\x84\xf0\xdfm\'"\xb8\xa0L%Q\xb3\x9b\xf6=\xdfO\x9a\xb3\x99\x17\x97\x8a\xa3\xd0\xea\x8ae\xe0\x9d\x12\xaf[\xa2\xce\x98S\xee\x80\x19\x9e^\xea\xb2\x803\t\x19(\xbc\x10`\x9c6\xf5\xf6\x89\xc7LRt\x8daS\x1b\xf5\xf00\xf3\xd4"\xc1u\x0e\xea\xf6\xa6K\x0e\xc8\xb9\xd6\x89\x04\xd2O\x8d\xb6&\x1bb\x04OC\x84\t~\xe2\x97\x1b\xcd\xa1(B\x11YG\xdaj\xfb\xc1\x9b\xb8\xa2\xa4LE\xd2\xd5\xa4\xf6\xdenY\x85Kf\xc3^;yI\x18\x0eD\x94\x00\x0e\x84{{n}}\xa9K\xce\xb5B\xa3e\x88\xd3\xbc\xf2Z\xd5\xaa\x82\xaa\x94\xd25\x0b\x1c\x99J\xaa\x023OB\xec\xbavEP\xe7\x8b\x93\x11I\xeaTz\xe2\xbb\xebH\xa3eW5\xe8\xb7\xe6\xce^*\x14\xb6\x83e\xda\xf9phe]b^\xe2\xf5\xe8\xd1Vp\xf0\xfe.\xbb\x1b\xa6`\x87\xfc8\x1a\x9bSE0q\xa2\x15\xeer\xe0"\x16\xbcz\x9f\xfdT\xc8h\x9d\xdf\xc7\xd4\xbe\xcdj1\xd9:\xa9\x1f\xe1B7\x81\xa1\xef\xc0\xd0:\x98\xc3-\xc0\xd4X\xfc\xda\xf1i\xbb\xe9\xfc\xdb<\x8c\xff2\x7f\'\xa8\x8d\xdf\xdab\xfc\x9e\xd6\xe3\x8c\x99qQ\xe3\xb0f\xd9\x19\x90{\xade\x8f\x99/3\xa1AC(\xfe\x16P\x06F \x90\xb3\t\x07Iba\x17\x83P\xa4\xbf\xb7G\x9e\x04\xa6vE\x13\xb6\xfc\x13\xd6\xa85\x0b\xdd\x19\xd6^i\x11\xa8FT;G\xfe\x06\xac\xc1q\xb0N\x956\xd84\xae\xe4p\xbe\xfa=\x03\x01\xce\x95\x9a' #lByteString = b"x\x9c\xb5\x91\xcfO\xc3 \x14\xc7\xff\x95\xa6\xd7uI\xf9Q\x8a\xde\xd4\x93\x07\xbdx\xf00\x97\x05)[I(\x90\x8ef3\xcb\xfew\x81M\xbb\xd9M]\x8c!y\xd0\xf7}\xbc\xef\xe3\xd3\xc9&\xd5\xac\x11\xe9u\x92j\xb1J@2N\x1e\x8d\x13\x96U\xa3Q\x9a%i+y=sb\xed\xceV\xd8\xd6p\xb1\\\xced\xe5K{{n}}\x80`\x9f\xeb\x135\xd3\x95{{n}}.\x08RR\xe4>\xc3\x15\xf3\x97>\xbc\x8f:r\xa3]k\xd4\xcc\xbd\xd9(>K]\x99\xd5\xa1\x12\xbd\x00\xc6\xb0\xcc\xcb0\xa4\xe0\x8e\xe9E4\xd8\xa4J\xcc\xc3\xb44\x07^r\xc6\xfa3\x04(\xbeeQ\x07\x05P\x1a\xa4W\xe3\x9ci\xfc\xf7\x15(\xb6A\xee\xb4\x93\x8d\xd85\x9f`?\xf6n\xd8i0v\xadw\xd5\x95X\x87n>\xf1d\x05\x97s\xc9\x99\x93F\xdf\xd5R\xc5K=\xcc\x1bk\xd5^\x1d`\xfc\xa2]\x06PwJ\r\xf0\x9d\xa2\xf6 tw\xcb\xda\x01\xb6}\x83\xd3\xcc\x00\xec\x99\x15\xf4\x88Y\x99\x1f2\x83\xb4\xfc\x8e\x99\xdf\xb3d\x0c\x01.1E\x04\x93l\xff\x8e\xcf\x7f6\xa4Z\xfc\x82\xeaK\x97c BD\xf3\x101\x89g\xba\x8b\x03\xd0?\x97\xff#\xfb{'\x9a\x8b\xe0\x03H\xc89\xfa\x08\x15\x7f\xa2\x0f >\x80_\x0e\xe0\x93\xb3\xf0\xc3\xc4\xd3m\\\xef\xf8\x958\xa0" lt=open("logSendByteStringWithoutN.log","wb") lt.write(lByteString) lt.close() ############################ 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 = pywinauto.Application() #Проверка разрядности lRPAApplication.connect(**inControlSpecificationArray[0]) #lTempObject=lRPAApplication.window(**inControlSpecificationArray[0]) #Скорректировано из-за недопонимания структуры lTempObject=lRPAApplication #Нормализация массива для целей выборки объекта (удаление конфликтующих ключей) inControlSpecificationArray=ElementSpecificationListNormalize(inControlSpecificationArray) #Циклическое прохождение к недрам объекта for lWindowSpecification in inControlSpecificationArray[0:]: lTempObject=lTempObject.window(**lWindowSpecification) return lTempObject #Получить массив свойств и методов у элемента def ElementActionGetList (inControlSpecificationArray): #Получить объект lObject=GetControl(inControlSpecificationArray) return dir(lObject.wrapper_object()) #Выполнить действие над элементом def ElementRunAction(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}): #Определить объект lObject=GetControl(inControlSpecificationArray) #Получить метод для вызова lFunction = getattr(lObject.wrapper_object(), inActionName) #Выполнить действие return lFunction(*inArgumentList,**inkwArgumentObject) def ElementGetInfo(inControlSpecificationArray): #Подготовка входного массива inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray) #Выполнить идентификацию объектов, если передан массив lResultList=[]; if len(inControlSpecificationArray) > 0: #Получить объект lTempObject=GetControl(inControlSpecificationArray) #Получить инфо объект lTempObjectInfo = lTempObject.wrapper_object().element_info #Добавить информацию об обнаруженом объекте lResultList.append(ElementInfoExportObject(lTempObjectInfo)); return lResultList ############################################ ###Модуль поиска объекта на экране ############################################ #Инициализация глобальных переменных mBitmap={} mGUISearchElementSelected={} def GUISearchEvent_on_move(lX, lY): global mBitmap global mGUISearchElementSelected if (lX,lY) in mBitmap: if mGUISearchElementSelected != mBitmap[lX,lY]: mGUISearchElementSelected = mBitmap[lX,lY] mBitmap[lX,lY].draw_outline() def GUISearchEvent_on_click(x, y, button, pressed): global mBitmap global mGUISearchElementSelected print('{0} at {1}'.format( 'Pressed' if pressed else 'Released', (x, y))) print(str(len(mBitmap))) if not pressed: # Stop listener del mBitmap mBitmap={} del mGUISearchElementSelected mGUISearchElementSelected={} return False def GUISearchEvent_on_scroll(x, y, dx, dy): print('Scrolled {0} at {1}'.format( 'down' if dy < 0 else 'up', (x, y))) #Создать bitmap карту объектов #GUISearchBitmapCreate #inElement - wrapper_object() # dict: x_y_ : elementObject def GUISearchRun(inSpecificationArray): lBitmap={} lGUISearchElementSelected=None #Создать карту пикселей и элементов lBitmap=GUISearchBitmapCreate(GetControl(inSpecificationArray),lBitmap) #Выдать сообщение, что поиск готов к использованию print("GUISearch: Ready for search!") #mBitmap=lBitmap # Collect events until released #Версия с Events (занимает поток, чтобы использовать общие переменные) #with mouse.Listener( # on_move=GUISearchEvent_on_move, # on_click=GUISearchEvent_on_click, # on_scroll=GUISearchEvent_on_scroll) as listener: #listener.join() # True == False ##################### ###Версия с таймером ##################### #mTimer = RepeatedTimer(0.5, GUISearchDraw, lBitmap) # it auto-starts, no need of rt.start() #mTimer.start() ########### #Версия с задержкой ########### #Сбросить нажатие Ctrl, если оно было bool(win32api.GetAsyncKeyState(17)) lTimeSleepSeconds=0.7 lFlagLoop = True while lFlagLoop: #Проверить, нажата ли клавиша Ctrl (код 17) lFlagKeyPressedCtrl=bool(win32api.GetAsyncKeyState(17)) #Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз if not lFlagKeyPressedCtrl: #Получить координаты мыши (lX,lY) = win32api.GetCursorPos() #Подсветить объект, если мышь над ним if (lX,lY) in lBitmap: if lGUISearchElementSelected != lBitmap[lX,lY]: lGUISearchElementSelected = lBitmap[lX,lY] lBitmap[lX,lY].draw_outline() else: lGUISearchElementSelected = None else: #Была нажата клавиша Ctrl - выйти из цикла lFlagLoop=False; #Заснуть до следующего цикла time.sleep(lTimeSleepSeconds) #Вернуть результат поиска return lGUISearchElementSelected def GUISearchBitmapCreate (inElement,inBitmapDict={}): #Добавить в карту информацию о текущем объекте inBitmapDict=GUISearchBitmapElementFill(inElement,inBitmapDict) #Получить список детей и добавить в карту for lItem in inElement.children(): inBitmapDict=GUISearchBitmapCreate(lItem,inBitmapDict) return inBitmapDict #GUISearchBitmapElementFill def GUISearchBitmapElementFill (inElement,inBitmapDict): lElementInfo=inElement.element_info #Получить параметры прямоугольника lElementRectX1 = 0 lElementRectX2 = 0 lElementRectY1 = 0 lElementRectY2 = 0 lFlagHasRect = True try: lElementRectX1=lElementInfo.rectangle.left lElementRectX2=lElementInfo.rectangle.right lElementRectY1=lElementInfo.rectangle.top lElementRectY2=lElementInfo.rectangle.bottom except Exception as e: lFlagHasRect = False #Выполнить установку элемента, если прямоугольник получить удалось if lFlagHasRect: lX=lElementRectX1 #Циклический обход по оси X while lX<=lElementRectX2: lY=lElementRectY1 #Циклический обход по Оси Y while lY<=lElementRectY2: #Установка элемента по адресу [,] inBitmapDict[lX,lY]=inElement #Инкремент y lY=lY+1 #Инкремент X lX=lX+1 return inBitmapDict #debug def ElementGetChildElementList(inControlSpecificationArray=[]): #Подготовка входного массива inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray) #Выполнить идентификацию объектов, если передан массив lResultList=[]; #ctypes.windll.user32.MessageBoxW(0, str(inControlSpecificationArray), "Your title", 1) if len(inControlSpecificationArray) > 0: #Получить объект lTempObject = GetControl(inControlSpecificationArray) #Получить список дочерних объектов lTempChildList = lTempObject.wrapper_object().children() lIterator=0 #Подготовить результирующий объект for lChild in lTempChildList: lTempObjectInfo=lChild.element_info #Добавить информацию об обнаруженом объекте lObjectInfoItem=ElementInfoExportObject(lTempObjectInfo) #Итератор внутри объекта (для точной идентификации) lObjectInfoItem['ctrl_index']=lIterator; lResultList.append(lObjectInfoItem); #Инкремент счетчика lIterator=lIterator+1 else: lResultList=GetRootElementList() return lResultList #Подготовить спецификацию для поиска элемента def ElementSpecificationListNormalize(inElementSpecification): lResult=[] #Циклический обход for lSpecificationItem in inElementSpecification: 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 == "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) #Проверит наличие ctrl_index - если он есть, то удалить control_id и control_type из-за того, что они мешают друг другу if 'ctrl_index' in lSpecificationItemNew: if "control_id" in lSpecificationItemNew: lSpecificationItemNew.pop("control_id") if "control_type" in lSpecificationItemNew: lSpecificationItemNew.pop("control_type") #Добавить строку в результирующий массив lResult.append(lSpecificationItemNew) #Вернуть результат return lResult #Подготовить массив для обращшения к поиску элемементов 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) #Проверит наличие ctrl_index - если он есть, то удалить control_id и control_type из-за того, что они мешают друг другу if 'ctrl_index' in lSpecificationItemNew: if "control_id" in lSpecificationItemNew: lSpecificationItemNew.pop("control_id") if "control_type" in lSpecificationItemNew: lSpecificationItemNew.pop("control_type") #Добавить строку в результирующий массив lResult.append(lSpecificationItemNew) #Вернуть результат return lResult ############################### ####Нормализация под JSON (в JSON нельзя передавать классы - только null, числа, строки, словари и массивы) ############################### #Нормализация словаря под JSON def JSONNormalizeDictionary(inDictionary): #Сделать копию объекта lResult=inDictionary.copy() #Перебор всех элементов for lItemKey,lItemValue in inDictionary.items(): #Флаг удаления атрибута lFlagRemoveAttribute=False #Если строка или число или массив или объект или None - оставить if ( type(lItemValue) is dict or type(lItemValue) is int or type(lItemValue) is str or type(lItemValue) is list or lItemValue is None): True==True else: lFlagRemoveAttribute=True #Рекурсивный вызов, если объект является словарем if type(lItemValue) is dict: lResult[lItemKey]=JSONNormalizeDictionary(lItemValue) #Рекурсивный вызов, если объект является списком if type(lItemValue) is list: lResult[lItemKey]=JSONNormalizeList(lItemValue) ############################# #Конструкция по удалению ключа из словаря if lFlagRemoveAttribute: lResult.pop(lItemKey) #Вернуть результат return lResult #Нормализация массива под JSON def JSONNormalizeList(inList): lResult=[] #Циклический обход for lItemValue in inList: #Если строка или число или массив или объект или None - оставить if ( type(lItemValue) is int or type(lItemValue) is str or lItemValue is None): lResult.append(lItemValue) #Если является словарем - вызвать функцию нормализации словаря if type(lItemValue) is dict: lResult.append(JSONNormalizeDictionary(lItemValue)) #Если является массиваом - вызвать функцию нормализации массива if type(lItemValue) is list: lResult.append(JSONNormalizeList(lItemValue)) #Вернуть результат return lResult #Определить объект - dict or list - и нормализовать его для JSON def JSONNormalizeDictList(inDictList): lResult={} if type(inDictList) is dict: lResult=JSONNormalizeDictionary(inDictList) if type(inDictList) is list: lResult=JSONNormalizeList(inDictList) return lResult; #Получить объект из атрибутов, которые удалось прочитать def ElementInfoExportObject(inElementInfo): #Подготовить выходную структуру данных lResult = {"name":None,"rich_text":None,"process_id":None,"process":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 lResult['process']=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: if inElementInfo.control_id!=0: 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(top_level_only=True) 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']=JSONNormalizeDictList(lResult) ProcessParentWriteObject(lJSONInput) except Exception as e: #Вывод ошибки в родительский поток ProcessParentWriteObject({'Error':str(e), 'ArgObject':str(lJSONInputString)}) #ctypes.windll.user32.MessageBoxW(0, str(e), "Your title", 1) 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))