#1.0.25 #Safe call #UIDesktop (no Robot.py is needed) #Need test

dev-linux
Ivan Maslov 5 years ago
parent 3abf2b1761
commit e00eb589ac

8
.gitignore vendored

@ -3,11 +3,11 @@
#Игнорируем папки распакованного блокнота #Игнорируем папки распакованного блокнота
/**/Resources/Editor/Notepad++_7_7_x64/* /**/Resources/Editor/Notepad++_7_7_x64/*
/**/Resources/Editor/Notepad++_7_7_x32/* /**/Resources/Editor/Notepad++_7_7_x32/*
/**/Orchestrator/Reports /**/Orchestrator/**/Reports
/**/Sources/Reports /**/Robot/**/Reports
/**/Sources/build /**/Sources/build
/**/Sources/dist /**/Sources/dist
/**/Studio/Reports /**/Studio/**/Reports
/**/OpenRPA_Orchestrator.exe /**/OpenRPA_Orchestrator.exe
/**/OpenRPAOrchestrator.exe /**/OpenRPAOrchestrator.exe
/**/OpenRPARobotGUIx32.exe /**/OpenRPARobotGUIx32.exe
@ -16,5 +16,5 @@
/**/OpenRPARobot.exe /**/OpenRPARobot.exe
/**/breakpoints.lst /**/breakpoints.lst
/**/Orchestrator/screenshot.png /**/Orchestrator/screenshot.png
.idea/** **/.idea/**
/**/screenshot.png /**/screenshot.png

@ -0,0 +1,16 @@
import keyboard
import subprocess
import time
import Settings
import sys
sys.path.insert(0,"C:\\Abs\\Archive\\scopeSrcUL\\OpenRPA\\Sources")
from pyOpenRPA.Robot import UIDesktop #OpenRPA UIDesktop
global mSettingsDict
mSettingsDict = Settings.Settings()
#UIDesktop initialization
UIDesktop.Utils.ProcessBitness.SettingsInit(mSettingsDict.get("pyOpenRPA",{}).get("Robot",{}).get("UIDesktop",{}).get("Utils",{}).get("ProcessBitness",None))
#Robot script
#UIDesktop.UIOSelector_Get_UIO([{"title_re":".*Configu.*", "backend":"uia"}]).draw_outline()
UIDesktop.UIOSelectorUIOActivity_Run_Dict([{"title_re":".*Configu.*", "backend":"uia"}],"draw_outline")

@ -0,0 +1,3 @@
cd %~dp0
..\..\..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe "Script.py"
pause >nul

@ -0,0 +1,18 @@
def Settings():
lResult={
"pyOpenRPA":{
"Robot":{
"UIDesktop":{
"Utils":{
"ProcessBitness":{
"Python32FullPath": "..\\..\\..\\Resources\\WPy32-3720\\python-3.7.2\\python.exe", #Set from user: "..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe"
"Python64FullPath": None, #Set from user
"Python32ProcessName": "OpenRPA_UIDesktopX32.exe", #Config set once
"Python64ProcessName": "OpenRPA_UIDesktopX64.exe" #Config set once
}
}
}
}
}
}
return lResult

@ -1,81 +0,0 @@
import pywinauto #Is needed to detect OS bitness
import struct # Need to detect Current process bitness
import subprocess #Need to create subprocess
import os # Is needed to check file/folder path
############################################
####Module, which control the Bitness between 32 and 64 python (needed for pywinauto framework to work correctly)
############################################
global mSettingsDict
mSettingsDict = {
"BitnessProcessCurrent": "64", # "64" or "32"
"BitnessOS": "64", # "64" or "32"
"Python32FullPath": None, #Set from user: "..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe"
"Python64FullPath": None, #Set from user
"Python32ProcessName": "OpenRPAUIDesktopX32.exe", #Config set once
"Python64ProcessName": "OpenRPAUIDesktopX64.exe", #Config set once
"Python32Process":None,
"Python64Process":None,
"PythonArgs":["-m","pyOpenRPA"] #Start other bitness openRPA process with PIPE channel
}
#Init the global configuration
def SettingsInit(inSettingsDict):
global mSettingsDict
#Update values in settings from input
mSettingsDict.update(inSettingsDict)
#mSettingsDict = inSettingsDict
####################
#Detect OS bitness
####BitnessOS#######
lBitnessOS="32";
if pywinauto.sysinfo.is_x64_OS():
lBitnessOS="64";
inSettingsDict["BitnessOS"]=lBitnessOS
####################
#Detect current process bitness
####BitnessProcessCurrent#######
lBitnessProcessCurrent = str(struct.calcsize("P") * 8)
inSettingsDict["BitnessProcessCurrent"]=lBitnessProcessCurrent
#####################################
#Create the other bitness process if OS is 64 and we have another Python path
##########################################################################
#Check if OS is x64, else no 64 is applicable
if mSettingsDict["BitnessOS"]=="64":
#Check if current bitness is 64
if mSettingsDict["BitnessProcessCurrent"]=="64":
#create x32 if Python 32 path is exists
if mSettingsDict["Python32FullPath"] and mSettingsDict["Python32ProcessName"]:
#Calculate python.exe folder path
lPython32FolderPath= "\\".join(mSettingsDict["Python32FullPath"].split("\\")[:-1])
lPython32NewNamePath = f"{lPython32FolderPath}\\{mSettingsDict["Python32ProcessName"]}"
if not os.path.isfile(lPython32NewNamePath):
shutil.copyfile(mSettingsDict["Python32FullPath"],lPython32NewNamePath)
mSettingsDict["Python32Process"] = subprocess.Popen([lPython32NewNamePath] + mSettingsDict["Python32FullPath"],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
else:
#bitness current process is 32
#return x64 if it is exists
if mSettingsDict["Python64Process"]:
#Calculate python.exe folder path
lPython64FolderPath= "\\".join(mSettingsDict["Python64FullPath"].split("\\")[:-1])
lPython64NewNamePath = f"{lPython64FolderPath}\\{mSettingsDict["Python64ProcessName"]}"
if not os.path.isfile(lPython64NewNamePath):
shutil.copyfile(mSettingsDict["Python32FullPath"],lPython64NewNamePath)
mSettingsDict["Python64Process"] = subprocess.Popen([lPython64NewNamePath] + mSettingsDict["Python64FullPath"],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
#Return the other module bitnes
def OtherBitnessGet():
#Result template
lResult = None
global mSettingsDict
#Check if OS is x64, else no 64 is applicable
if mSettingsDict["BitnessOS"]=="64":
#Check if current bitness is 64
if mSettingsDict["BitnessProcessCurrent"]=="64":
#return x32 if it is exists
if mSettingsDict["Python32Process"]:
lResult = mSettingsDict["Python32Process"]
else:
#bitness current process is 32
#return x64 if it is exists
if mSettingsDict["Python64Process"]:
lResult = mSettingsDict["Python64Process"]
#Exit
return lResult

@ -14,6 +14,7 @@ import time
import traceback import traceback
from . import ProcessCommunicator from . import ProcessCommunicator
from . import JSONNormalize from . import JSONNormalize
from . import Utils #For ProcessBitness
from threading import Timer from threading import Timer
import datetime import datetime
import logging import logging
@ -34,7 +35,16 @@ mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)
mRobotLoggerFH.setFormatter(mRobotLoggerFormatter) mRobotLoggerFH.setFormatter(mRobotLoggerFormatter)
# add handler to logger object # add handler to logger object
mRobotLogger.addHandler(mRobotLoggerFH) mRobotLogger.addHandler(mRobotLoggerFH)
############################################
#When import UIDesktop init the other bitness python
#For this type UIDesktop.Utils.ProcessBitness.SettingsInit(inSettingsDict)
#inSettingsDict = {
# "Python32FullPath": None, #Set from user: "..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe"
# "Python64FullPath": None, #Set from user
# "Python32ProcessName": "OpenRPAUIDesktopX32.exe", #Config set once
# "Python64ProcessName": "OpenRPAUIDesktopX64.exe" #Config set once
#}
############################################
#logging.basicConfig(filename="Reports\ReportRobotGUIRun_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log", level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") #logging.basicConfig(filename="Reports\ReportRobotGUIRun_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log", level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
@ -258,14 +268,32 @@ def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException
return lResult return lResult
################################################################################################# #################################################################################################
#Check if UIO exist (Identified by the UIOSelector) #Check if UIO exist (Identified by the UIOSelector)
#inSpecificationList - UIOSelector #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#UIOSelector
#old name - - #old name - -
def UIOSelector_Exist_Bool (inSpecificationList): def UIOSelector_Exist_Bool (inUIOSelector):
lResult=False lResult=False
#Получить родительский объект если на вход ничего не поступило #Check the bitness
lResultList=UIOSelector_Get_UIOList(inSpecificationList,None,False) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if len(lResultList)>0: if lSafeOtherProcess is None:
lResult=True #Получить родительский объект если на вход ничего не поступило
lResultList=UIOSelector_Get_UIOList(inUIOSelector, None, False)
if len(lResultList)>0:
lResult=True
else:
# Run function from other process with help of PIPE
lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_Exist_Bool",
"ArgumentList": [inUIOSelector],
"ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(
f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else:
lResult = lPIPEResponseDict["Result"]
return lResult return lResult
################################################################################################# #################################################################################################
#Wait for UIO is appear (at least one of them or all at the same time) #Wait for UIO is appear (at least one of them or all at the same time)
@ -385,6 +413,21 @@ def UIOSelector_Get_BitnessInt (inSpecificationList):
lResult=32 lResult=32
return lResult return lResult
################################################################################################# #################################################################################################
#Get process bitness ("32" or "64")
#inSpecificationList - UIOSelector
#old name - None
#return None (if Process not found), int 32, or int 64
def UIOSelector_Get_BitnessStr (inSpecificationList):
lResult=None
#Получить объект Application (Для проверки разрядности)
lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList)
if lRootElement is not None:
if lRootElement.is64bit():
lResult="64"
else:
lResult="32"
return lResult
#################################################################################################
#Get OS bitness (32 or 64) #Get OS bitness (32 or 64)
#old name - None #old name - None
#return int 32, or int 64 #return int 32, or int 64
@ -393,6 +436,18 @@ def Get_OSBitnessInt ():
if pywinauto.sysinfo.is_x64_OS(): if pywinauto.sysinfo.is_x64_OS():
lResult=64; lResult=64;
return lResult; return lResult;
#################################################################################################
#Safe get other process or None if destination app is the other/same bitness
#inUIOSelector - selector of the destination
#return None or process (of the other bitness)
def UIOSelector_SafeOtherGet_Process(inUIOSelector):
#Default value
lResult = None
#Get selector bitness
lUIOSelectorAppBitness = UIOSelector_Get_BitnessStr(inUIOSelector)
if lUIOSelectorAppBitness and Utils.ProcessBitness.mSettingsDict["BitnessProcessCurrent"] != lUIOSelectorAppBitness:
lResult = Utils.ProcessBitness.OtherProcessGet()
return lResult
################################################################################################## ##################################################################################################
#inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation #inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation
#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element #Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
@ -523,48 +578,66 @@ def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
#################################################################################################### ####################################################################################################
#inElementSpecification - UIOSelector #inElementSpecification - UIOSelector
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - AutomationSearchMouseElementHierarchy #old name - AutomationSearchMouseElementHierarchy
def UIOSelector_SearchChildByMouse_UIOTree(inElementSpecification): def UIOSelector_SearchChildByMouse_UIOTree(inUIOSelector):
lItemInfo = [] lItemInfo = []
#Запустить функцию поиска элемента по мыши #Check the bitness
lElementList = UIOSelector_SearchChildByMouse_UIO(inElementSpecification) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
lElement = lElementList[-1]['element'] if lSafeOtherProcess is None:
#Detect backend of the elements #Запустить функцию поиска элемента по мыши
lFlagIsBackendWin32 = True lElementList = UIOSelector_SearchChildByMouse_UIO(inUIOSelector)
#Если объект имеется (не None), то выполнить построение иерархии lElement = lElementList[-1]['element']
if lElement is not None: #Detect backend of the elements
if lElement.backend.name == 'uia': lFlagIsBackendWin32 = True
lFlagIsBackendWin32 = False #Если объект имеется (не None), то выполнить построение иерархии
#Циклическое создание дерева if lElement is not None:
#while lElement is not None: if lElement.backend.name == 'uia':
lListIterator=0 lFlagIsBackendWin32 = False
lItemInfo2=lItemInfo #Циклическое создание дерева
for lListItem in lElementList: #while lElement is not None:
lElement = lListItem["element"] lListIterator=0
#Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None lItemInfo2=lItemInfo
#if not lFlagIsBackendWin32 and lElement.parent() is None: for lListItem in lElementList:
# lElement = None lElement = lListItem["element"]
#else: #Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None
#Получить информацию про объект #if not lFlagIsBackendWin32 and lElement.parent() is None:
lItemInfo2.append(UIOEI_Convert_UIOInfo(lElement.element_info)) # lElement = None
#Дообогатить информацией об индексе ребенка в родительском объекте #else:
if "index" in lListItem: #Получить информацию про объект
if lListItem["index"] is not None: lItemInfo2.append(UIOEI_Convert_UIOInfo(lElement.element_info))
lItemInfo2[-1]['ctrl_index']=lListItem["index"] #Дообогатить информацией об индексе ребенка в родительском объекте
if "index" in lListItem:
if lListItem["index"] is not None:
lItemInfo2[-1]['ctrl_index']=lListItem["index"]
else:
if "ctrl_index" in lListItem:
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"]
else: else:
if "ctrl_index" in lListItem: if "ctrl_index" in lListItem:
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"] lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"]
else: #Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников
if "ctrl_index" in lListItem: lItemInfo2[-1]['SpecificationChild']=[]
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"] lItemInfo2=lItemInfo2[-1]['SpecificationChild']
#Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников #Переход на родительский объект
lItemInfo2[-1]['SpecificationChild']=[] #lElement = lElement.parent()
lItemInfo2=lItemInfo2[-1]['SpecificationChild'] lListIterator=lListIterator+1
#Переход на родительский объект #Добавить информацию о Backend в первый объект
#lElement = lElement.parent() lItemInfo[0]["backend"]=lElement.backend.name
lListIterator=lListIterator+1 else:
#Добавить информацию о Backend в первый объект # Run function from other process with help of PIPE
lItemInfo[0]["backend"]=lElement.backend.name lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_SearchChildByMouse_UIOTree",
"ArgumentList": [inUIOSelector],
"ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(
f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else:
lItemInfo = lPIPEResponseDict["Result"]
#Вернуть результат #Вернуть результат
return lItemInfo return lItemInfo
#################################################################################################### ####################################################################################################
@ -600,41 +673,36 @@ def UIO_GetCtrlIndex_Int(inElement):
return lResult return lResult
#################################################################################################### ####################################################################################################
#Получить список информационных объектов, который удовлетворяет условиям # Get the UIO Info list for the selected criteria
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inSpecificationList - UIOSelector #inSpecificationList - UIOSelector
#old name - PywinautoExtElementsGetInfo #old name - PywinautoExtElementsGetInfo
def UIOSelector_Get_UIOInfoList (inSpecificationList,inElement=None): def UIOSelector_Get_UIOInfoList (inUIOSelector, inElement=None):
#Получить родительский объект если на вход ничего не поступило #Check the bitness
lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
lIterator = 0 if lSafeOtherProcess is None:
for lItem in lResultList: #Получить родительский объект если на вход ничего не поступило
lResultList[lIterator]=UIOEI_Convert_UIOInfo(lResultList[lIterator].element_info) lResultList=UIOSelector_Get_UIOList(inUIOSelector, inElement)
lIterator = lIterator + 1 lIterator = 0
for lItem in lResultList:
lResultList[lIterator]=UIOEI_Convert_UIOInfo(lResultList[lIterator].element_info)
lIterator = lIterator + 1
else:
# Run function from other process with help of PIPE
lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_Get_UIOInfoList",
"ArgumentList": [inUIOSelector, inElement],
"ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(
f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else:
lResultList = lPIPEResponseDict["Result"]
return lResultList return lResultList
####################################################################################################
#Check is the UIO/UIO's by the UIOSelector exist
#inSpecificationList - UIOSelector
#old name - PywinautoExtElementExist
def UIOSelector_IsExist_Bool (inSpecificationList):
return len(UIOSelector_Get_UIOList(inSpecificationList))>0
####################################################################################################
#Wait for the UIO by the UIOSelector appear
#inSpecificationList - UIOSelector
#result - { }
#old name - PywinautoExtElementWaitAppear
#############
#Внимание! Старая функция (на замену ей пришла UIOSelectorSecs_WaitAppear_Bool)
#############
def UIOSelector_WaitAppear_Dict(inSpecificationList,inTimeout=60):
lTimeoutSeconds = 0
while (not UIOSelector_IsExist_Bool(inSpecificationList) and inTimeout>lTimeoutSeconds):
lTimeoutSeconds = lTimeoutSeconds + 0.5
#Заснуть на полсекунды
time.sleep(0.5)
return UIOSelector_IsExist_Bool(inSpecificationList)
#################################################################################################### ####################################################################################################
#Try to restore (maximize) window, if it's was minimized #Try to restore (maximize) window, if it's was minimized
#(особенность uia backend - он не может прицепиться к окну, если оно свернуто) #(особенность uia backend - он не может прицепиться к окну, если оно свернуто)
@ -655,72 +723,124 @@ def UIOSelector_TryRestore_Dict(inSpecificationList):
return lResult return lResult
#################################################################################################### ####################################################################################################
#Get the list of the UI object activities #Get the list of the UI object activities
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inControlSpecificationArray - UIOSelector #inControlSpecificationArray - UIOSelector
#old name - ElementActionGetList #old name - ElementActionGetList
def UIOSelector_Get_UIOActivityList (inControlSpecificationArray): def UIOSelector_Get_UIOActivityList (inUIOSelector):
#Получить объект #Check the bitness
lObject=UIOSelector_Get_UIO(inControlSpecificationArray) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
lActionList=dir(lObject) if lSafeOtherProcess is None:
lResult=dir(lObject) #Получить объект
#Выполнить чистку списка от неактуальных методов lObject=UIOSelector_Get_UIO(inUIOSelector)
for lActionItem in lActionList: lActionList=dir(lObject)
#Удалить те, которые начинаются на _ lResult=dir(lObject)
if lActionItem[0]=='_': #Выполнить чистку списка от неактуальных методов
lResult.remove(lActionItem) for lActionItem in lActionList:
#Удалить те, которые начинаются с символа верхнего регистра #Удалить те, которые начинаются на _
if lActionItem[0].isupper(): if lActionItem[0]=='_':
lResult.remove(lActionItem) lResult.remove(lActionItem)
#Удалить те, которые начинаются с символа верхнего регистра
if lActionItem[0].isupper():
lResult.remove(lActionItem)
else:
# Run function from other process with help of PIPE
lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_Get_UIOActivityList",
"ArgumentList": [inUIOSelector],
"ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(
f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else:
lResult = lPIPEResponseDict["Result"]
return lResult return lResult
#################################################################################################### ####################################################################################################
#Run the activity in UIO (UI Object) #Run the activity in UIO (UI Object)
#inControlSpecificationArray - UIOSelector #!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inUIOSelector
#inActionName - UIOActivity (name) from Pywinauto #inActionName - UIOActivity (name) from Pywinauto
#old name - ElementRunAction #old name - ElementRunAction
def UIOSelectorUIOActivity_Run_Dict(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}): def UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=[], inkwArgumentObject={}):
lResult={} lResult={}
#Определить объект #Check the bitness
lObject=UIOSelector_Get_UIO(inControlSpecificationArray) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
#Получить метод для вызова #Run activity if SafeOtherProcess is None
lFunction = getattr(lObject, inActionName) if lSafeOtherProcess is None:
#Выполнить действие #Определить объект
#Обернуто в безопасную обработку, тк для некоторых объектов метод не работает и может выдавать ошибку типа: NotImplementedError: This method not work properly for WinForms DataGrid, use cells() lObject=UIOSelector_Get_UIO(inUIOSelector)
try: #Получить метод для вызова
return lFunction(*inArgumentList,**inkwArgumentObject) lFunction = getattr(lObject, inActionName)
except Exception as e: #Выполнить действие
#Если ошибка возникла на action get_properties #Обернуто в безопасную обработку, тк для некоторых объектов метод не работает и может выдавать ошибку типа: NotImplementedError: This method not work properly for WinForms DataGrid, use cells()
if inActionName=="get_properties": try:
lResult={} return lFunction(*inArgumentList,**inkwArgumentObject)
#Ручное формирование except Exception as e:
lResult["class_name"]=lObject.class_name() #Если ошибка возникла на action get_properties
lResult["friendly_class_name"]=lObject.friendly_class_name() if inActionName=="get_properties":
lResult["texts"]=lObject.texts() lResult={}
lResult["control_id"]=lObject.control_id() #Ручное формирование
lResult["control_count"]=lObject.control_count() lResult["class_name"]=lObject.class_name()
lResult["automation_id"]=lObject.automation_id() lResult["friendly_class_name"]=lObject.friendly_class_name()
return lResult lResult["texts"]=lObject.texts()
lResult["control_id"]=lObject.control_id()
lResult["control_count"]=lObject.control_count()
lResult["automation_id"]=lObject.automation_id()
return lResult
else:
raise e
else:
#Run function from other process with help of PIPE
lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelectorUIOActivity_Run_Dict",
"ArgumentList": [inUIOSelector, inActionName, inArgumentList, inkwArgumentObject],
"ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else: else:
raise e lResult = lPIPEResponseDict["Result"]
return lResult return lResult
#################################################################################################### ####################################################################################################
#Get the UIO dict of the attributes #Get the UIO dict of the attributes
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementGetInfo #old name - ElementGetInfo
def UIOSelector_Get_UIOInfo(inControlSpecificationArray): def UIOSelector_Get_UIOInfo(inUIOSelector):
#Подготовка входного массива #Check the bitness
inControlSpecificationArray=UIOSelector_SearchUIONormalize_UIOSelector(inControlSpecificationArray) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
#Выполнить идентификацию объектов, если передан массив if lSafeOtherProcess is None:
lResultList=[]; #Подготовка входного массива
if len(inControlSpecificationArray) > 0: inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector)
#Получить объект #Выполнить идентификацию объектов, если передан массив
lTempObject=UIOSelector_Get_UIO(inControlSpecificationArray) lResultList=[];
#Получить инфо объект if len(inUIOSelector) > 0:
lTempObjectInfo = lTempObject.element_info #Получить объект
#Добавить информацию об обнаруженом объекте lTempObject=UIOSelector_Get_UIO(inUIOSelector)
lResultList.append(UIOEI_Convert_UIOInfo(lTempObjectInfo)); #Получить инфо объект
lTempObjectInfo = lTempObject.element_info
#Добавить информацию об обнаруженом объекте
lResultList.append(UIOEI_Convert_UIOInfo(lTempObjectInfo))
else:
# Run function from other process with help of PIPE
lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_Get_UIOInfo",
"ArgumentList": [inUIOSelector],
"ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(
f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else:
lResultList = lPIPEResponseDict["Result"]
return lResultList return lResultList
#################################################################################################### ####################################################################################################
#Search child UIO by the: Parent UIO, X, Y #Search child UIO by the: Parent UIO, X, Y
#inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose #inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose
@ -812,35 +932,53 @@ def UIOXY_SearchChild_ListDict(inRootElement,inX,inY,inHierarchyList=[]):
################################################################################################### ###################################################################################################
#Get list of child UIO's by Parent UIOSelector #Get list of child UIO's by Parent UIOSelector
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inControlSpecificationArray- UIOSelector #inControlSpecificationArray- UIOSelector
#old name - ElementGetChildElementList #old name - ElementGetChildElementList
def UIOSelector_GetChildList_UIOList(inControlSpecificationArray=[],inBackend=mDefaultPywinautoBackend): def UIOSelector_GetChildList_UIOList(inUIOSelector=[], inBackend=mDefaultPywinautoBackend):
#Подготовка входного массива #Check the bitness
inControlSpecificationArray=UIOSelector_SearchUIONormalize_UIOSelector(inControlSpecificationArray) lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
#Выполнить идентификацию объектов, если передан массив if lSafeOtherProcess is None:
lResultList=[]; #Подготовка входного массива
#ctypes.windll.user32.MessageBoxW(0, str(inControlSpecificationArray), "Your title", 1) inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector)
if len(inControlSpecificationArray) > 0: #Выполнить идентификацию объектов, если передан массив
#Получить объект lResultList=[];
lTempObject = UIOSelector_Get_UIO(inControlSpecificationArray) #ctypes.windll.user32.MessageBoxW(0, str(inControlSpecificationArray), "Your title", 1)
#Получить список дочерних объектов if len(inUIOSelector) > 0:
lTempChildList = lTempObject.children() #Получить объект
lIterator=0 lTempObject = UIOSelector_Get_UIO(inUIOSelector)
#Подготовить результирующий объект #Получить список дочерних объектов
for lChild in lTempChildList: lTempChildList = lTempObject.children()
lTempObjectInfo=lChild.element_info lIterator=0
#Добавить информацию об обнаруженом объекте #Подготовить результирующий объект
lObjectInfoItem=UIOEI_Convert_UIOInfo(lTempObjectInfo) for lChild in lTempChildList:
#Итератор внутри объекта (для точной идентификации) lTempObjectInfo=lChild.element_info
lObjectInfoItem['ctrl_index']=lIterator; #Добавить информацию об обнаруженом объекте
lResultList.append(lObjectInfoItem); lObjectInfoItem=UIOEI_Convert_UIOInfo(lTempObjectInfo)
#Инкремент счетчика #Итератор внутри объекта (для точной идентификации)
lIterator=lIterator+1 lObjectInfoItem['ctrl_index']=lIterator;
lResultList.append(lObjectInfoItem);
#Инкремент счетчика
lIterator=lIterator+1
else:
lResultList=BackendStr_GetTopLevelList_UIOInfo(inBackend)
#Установка бэк-енда на первый элемент
for lItem in lResultList:
lItem["backend"]=inBackend
else: else:
lResultList=BackendStr_GetTopLevelList_UIOInfo(inBackend) # Run function from other process with help of PIPE
#Установка бэк-енда на первый элемент lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_GetChildList_UIOList",
for lItem in lResultList: "ArgumentList": [inUIOSelector, inBackend],
lItem["backend"]=inBackend "ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(
f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else:
lResultList = lPIPEResponseDict["Result"]
return lResultList return lResultList
#################################################################################################### ####################################################################################################
@ -1080,17 +1218,53 @@ def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend):
################################################################################################### ###################################################################################################
#Highlight the UI object #Highlight the UI object
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNew #old name - ElementDrawOutlineNew
def UIOSelector_Highlight(inSpecificationArray): def UIOSelector_Highlight(inUIOSelector):
UIO_Highlight(UIOSelector_Get_UIO(inSpecificationArray)) #Check the bitness
return lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
UIO_Highlight(UIOSelector_Get_UIO(inUIOSelector))
else:
# Run function from other process with help of PIPE
lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_Exist_Bool",
"ArgumentList": [inUIOSelector],
"ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(
f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else:
return lPIPEResponseDict["Result"]
return True
################################################################################################### ###################################################################################################
#inSpecificationArray - UIOSelector #inSpecificationArray - UIOSelector
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNewFocus #old name - ElementDrawOutlineNewFocus
def UIOSelector_FocusHighlight(inSpecificationArray): def UIOSelector_FocusHighlight(inUIOSelector):
UIO_FocusHighlight(UIOSelector_Get_UIO(inSpecificationArray)) #Check the bitness
return lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
UIO_FocusHighlight(UIOSelector_Get_UIO(inUIOSelector))
else:
# Run function from other process with help of PIPE
lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_Exist_Bool",
"ArgumentList": [inUIOSelector],
"ArgumentDict": {}}
# Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами
ProcessCommunicator.ProcessChildSendObject(lSafeOtherProcess, lPIPEResuestDict)
# Get answer from child process
lPIPEResponseDict = ProcessCommunicator.ProcessChildReadWaitObject(lSafeOtherProcess)
if lPIPEResponseDict["ErrorFlag"]:
raise Exception(
f"Exception was occured in child process (message): {lPIPEResponseDict['ErrorMessage']}, (traceback): {lPIPEResponseDict['ErrorTraceback']}")
else:
return lPIPEResponseDict["Result"]
return True
################################################################################################### ###################################################################################################
#old name - draw_outline_new #old name - draw_outline_new

@ -0,0 +1,85 @@
import pywinauto #Is needed to detect OS bitness
import struct # Need to detect Current process bitness
import subprocess #Need to create subprocess
import os # Is needed to check file/folder path
import shutil #os operations
import pdb
############################################
####Module, which control the Bitness between 32 and 64 python (needed for pywinauto framework to work correctly)
############################################
global mSettingsDict
mSettingsDict = {
"BitnessProcessCurrent": "64", # "64" or "32"
"BitnessOS": "64", # "64" or "32"
"Python32FullPath": None, #Set from user: "..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe"
"Python64FullPath": None, #Set from user
"Python32ProcessName": "OpenRPAUIDesktopX32.exe", #Config set once
"Python64ProcessName": "OpenRPAUIDesktopX64.exe", #Config set once
"Python32Process":None,
"Python64Process":None,
"PythonArgs":["-m","pyOpenRPA.Robot"] #Start other bitness openRPA process with PIPE channel
}
#Init the global configuration
def SettingsInit(inSettingsDict):
if inSettingsDict:
global mSettingsDict
#Update values in settings from input
mSettingsDict.update(inSettingsDict)
#mSettingsDict = inSettingsDict
####################
#Detect OS bitness
####BitnessOS#######
lBitnessOS="32";
if pywinauto.sysinfo.is_x64_OS():
lBitnessOS="64";
inSettingsDict["BitnessOS"]=lBitnessOS
####################
#Detect current process bitness
####BitnessProcessCurrent#######
lBitnessProcessCurrent = str(struct.calcsize("P") * 8)
inSettingsDict["BitnessProcessCurrent"]=lBitnessProcessCurrent
#####################################
#Create the other bitness process if OS is 64 and we have another Python path
##########################################################################
#Check if OS is x64, else no 64 is applicable
if mSettingsDict["BitnessOS"]=="64":
#Check if current bitness is 64
if mSettingsDict["BitnessProcessCurrent"]=="64":
#create x32 if Python 32 path is exists
if mSettingsDict["Python32FullPath"] and mSettingsDict["Python32ProcessName"]:
#Calculate python.exe folder path
lPython32FolderPath= "\\".join(mSettingsDict["Python32FullPath"].split("\\")[:-1])
lPython32NewNamePath = f"{lPython32FolderPath}\\{mSettingsDict['Python32ProcessName']}"
if not os.path.isfile(lPython32NewNamePath):
shutil.copyfile(mSettingsDict["Python32FullPath"],lPython32NewNamePath)
#pdb.set_trace()
mSettingsDict["Python32Process"] = subprocess.Popen([lPython32NewNamePath] + mSettingsDict["PythonArgs"],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
else:
#bitness current process is 32
#return x64 if it is exists
if mSettingsDict["Python64Process"]:
#Calculate python.exe folder path
lPython64FolderPath= "\\".join(mSettingsDict["Python64FullPath"].split("\\")[:-1])
lPython64NewNamePath = f"{lPython64FolderPath}\\{mSettingsDict['Python64ProcessName']}"
if not os.path.isfile(lPython64NewNamePath):
shutil.copyfile(mSettingsDict["Python64FullPath"],lPython64NewNamePath)
mSettingsDict["Python64Process"] = subprocess.Popen([lPython64NewNamePath] + mSettingsDict["PythonArgs"],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
#Return the other module bitnes
def OtherProcessGet():
#Result template
lResult = None
global mSettingsDict
#Check if OS is x64, else no 64 is applicable
if mSettingsDict["BitnessOS"]=="64":
#Check if current bitness is 64
if mSettingsDict["BitnessProcessCurrent"]=="64":
#return x32 if it is exists
if mSettingsDict["Python32Process"]:
lResult = mSettingsDict["Python32Process"]
else:
#bitness current process is 32
#return x64 if it is exists
if mSettingsDict["Python64Process"]:
lResult = mSettingsDict["Python64Process"]
#Exit
return lResult

@ -0,0 +1 @@
from . import ProcessBitness

@ -28,6 +28,7 @@ while True:
lFunction = getattr(UIDesktop,lJSONInput['ActivityName']) lFunction = getattr(UIDesktop,lJSONInput['ActivityName'])
lProcessResponse["Result"]=JSONNormalize.JSONNormalizeDictListStrIntBool(lFunction(*lJSONInput['ArgumentList'],**lJSONInput['ArgumentDict'])) lProcessResponse["Result"]=JSONNormalize.JSONNormalizeDictListStrIntBool(lFunction(*lJSONInput['ArgumentList'],**lJSONInput['ArgumentDict']))
except Exception as e: except Exception as e:
lProcessResponse["Result"] = None
#Установить флаг ошибки #Установить флаг ошибки
lProcessResponse["ErrorFlag"]=True lProcessResponse["ErrorFlag"]=True
#Зафиксировать traceback #Зафиксировать traceback

@ -1,4 +1,24 @@
Beta before 1.0.1 (new way of OpenRPA with improovments. Sorry, but no backward compatibility)/ Backward compatibility will start from 1.0.1 Beta before 1.0.1 (new way of OpenRPA with improovments. Sorry, but no backward compatibility)/ Backward compatibility will start from 1.0.1
[1.0.25]
*Dont upload to PyPi* - Not tested
Created safe call function in UIDesktop
UIOSelector_SafeOtherGet_Process
Safe call in UIDesktop for:
- UIOSelectorUIOActivity_Run_Dict
- UIOSelector_Exist_Bool
- UIOSelector_Highlight
- UIOSelector_FocusHighlight
- UIOSelector_SearchChildByMouse_UIOTree
- UIOSelector_GetChildList_UIOList
- UIOSelector_Get_UIOInfoList
- UIOSelector_Get_UIOInfo
- UIOSelector_Get_UIOActivityList
UIOSelectorSecs_WaitAppear_Bool
UIOSelectorSecs_WaitDisappear_Bool
UIOSelectorsSecs_WaitAppear_List
UIOSelectorsSecs_WaitDisappear_List
[1.0.24] [1.0.24]
1.0.1 Beta 1.0.1 Beta
Refactoring (Studio Orchestrator in pyOpenRPA package) Refactoring (Studio Orchestrator in pyOpenRPA package)

Loading…
Cancel
Save