#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_x32/*
/**/Orchestrator/Reports
/**/Sources/Reports
/**/Orchestrator/**/Reports
/**/Robot/**/Reports
/**/Sources/build
/**/Sources/dist
/**/Studio/Reports
/**/Studio/**/Reports
/**/OpenRPA_Orchestrator.exe
/**/OpenRPAOrchestrator.exe
/**/OpenRPARobotGUIx32.exe
@ -16,5 +16,5 @@
/**/OpenRPARobot.exe
/**/breakpoints.lst
/**/Orchestrator/screenshot.png
.idea/**
**/.idea/**
/**/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
from . import ProcessCommunicator
from . import JSONNormalize
from . import Utils #For ProcessBitness
from threading import Timer
import datetime
import logging
@ -34,7 +35,16 @@ mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)
mRobotLoggerFH.setFormatter(mRobotLoggerFormatter)
# add handler to logger object
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")
@ -258,14 +268,32 @@ def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException
return lResult
#################################################################################################
#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 - -
def UIOSelector_Exist_Bool (inSpecificationList):
def UIOSelector_Exist_Bool (inUIOSelector):
lResult=False
#Получить родительский объект если на вход ничего не поступило
lResultList=UIOSelector_Get_UIOList(inSpecificationList,None,False)
if len(lResultList)>0:
lResult=True
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
#Получить родительский объект если на вход ничего не поступило
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
#################################################################################################
#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
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)
#old name - None
#return int 32, or int 64
@ -393,6 +436,18 @@ def Get_OSBitnessInt ():
if pywinauto.sysinfo.is_x64_OS():
lResult=64;
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
#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element
@ -523,48 +578,66 @@ def UIOSelector_SearchChildByMouse_UIO(inElementSpecification):
####################################################################################################
#inElementSpecification - UIOSelector
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - AutomationSearchMouseElementHierarchy
def UIOSelector_SearchChildByMouse_UIOTree(inElementSpecification):
def UIOSelector_SearchChildByMouse_UIOTree(inUIOSelector):
lItemInfo = []
#Запустить функцию поиска элемента по мыши
lElementList = UIOSelector_SearchChildByMouse_UIO(inElementSpecification)
lElement = lElementList[-1]['element']
#Detect backend of the elements
lFlagIsBackendWin32 = True
#Если объект имеется (не None), то выполнить построение иерархии
if lElement is not None:
if lElement.backend.name == 'uia':
lFlagIsBackendWin32 = False
#Циклическое создание дерева
#while lElement is not None:
lListIterator=0
lItemInfo2=lItemInfo
for lListItem in lElementList:
lElement = lListItem["element"]
#Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None
#if not lFlagIsBackendWin32 and lElement.parent() is None:
# lElement = None
#else:
#Получить информацию про объект
lItemInfo2.append(UIOEI_Convert_UIOInfo(lElement.element_info))
#Дообогатить информацией об индексе ребенка в родительском объекте
if "index" in lListItem:
if lListItem["index"] is not None:
lItemInfo2[-1]['ctrl_index']=lListItem["index"]
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
#Запустить функцию поиска элемента по мыши
lElementList = UIOSelector_SearchChildByMouse_UIO(inUIOSelector)
lElement = lElementList[-1]['element']
#Detect backend of the elements
lFlagIsBackendWin32 = True
#Если объект имеется (не None), то выполнить построение иерархии
if lElement is not None:
if lElement.backend.name == 'uia':
lFlagIsBackendWin32 = False
#Циклическое создание дерева
#while lElement is not None:
lListIterator=0
lItemInfo2=lItemInfo
for lListItem in lElementList:
lElement = lListItem["element"]
#Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None
#if not lFlagIsBackendWin32 and lElement.parent() is None:
# lElement = None
#else:
#Получить информацию про объект
lItemInfo2.append(UIOEI_Convert_UIOInfo(lElement.element_info))
#Дообогатить информацией об индексе ребенка в родительском объекте
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:
if "ctrl_index" in lListItem:
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"]
else:
if "ctrl_index" in lListItem:
lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"]
#Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников
lItemInfo2[-1]['SpecificationChild']=[]
lItemInfo2=lItemInfo2[-1]['SpecificationChild']
#Переход на родительский объект
#lElement = lElement.parent()
lListIterator=lListIterator+1
#Добавить информацию о Backend в первый объект
lItemInfo[0]["backend"]=lElement.backend.name
#Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников
lItemInfo2[-1]['SpecificationChild']=[]
lItemInfo2=lItemInfo2[-1]['SpecificationChild']
#Переход на родительский объект
#lElement = lElement.parent()
lListIterator=lListIterator+1
#Добавить информацию о Backend в первый объект
lItemInfo[0]["backend"]=lElement.backend.name
else:
# Run function from other process with help of PIPE
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
####################################################################################################
@ -600,41 +673,36 @@ def UIO_GetCtrlIndex_Int(inElement):
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
#old name - PywinautoExtElementsGetInfo
def UIOSelector_Get_UIOInfoList (inSpecificationList,inElement=None):
#Получить родительский объект если на вход ничего не поступило
lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement)
lIterator = 0
for lItem in lResultList:
lResultList[lIterator]=UIOEI_Convert_UIOInfo(lResultList[lIterator].element_info)
lIterator = lIterator + 1
def UIOSelector_Get_UIOInfoList (inUIOSelector, inElement=None):
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
#Получить родительский объект если на вход ничего не поступило
lResultList=UIOSelector_Get_UIOList(inUIOSelector, inElement)
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
####################################################################################################
#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
#(особенность uia backend - он не может прицепиться к окну, если оно свернуто)
@ -655,72 +723,124 @@ def UIOSelector_TryRestore_Dict(inSpecificationList):
return lResult
####################################################################################################
#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
#old name - ElementActionGetList
def UIOSelector_Get_UIOActivityList (inControlSpecificationArray):
#Получить объект
lObject=UIOSelector_Get_UIO(inControlSpecificationArray)
lActionList=dir(lObject)
lResult=dir(lObject)
#Выполнить чистку списка от неактуальных методов
for lActionItem in lActionList:
#Удалить те, которые начинаются на _
if lActionItem[0]=='_':
lResult.remove(lActionItem)
#Удалить те, которые начинаются с символа верхнего регистра
if lActionItem[0].isupper():
lResult.remove(lActionItem)
def UIOSelector_Get_UIOActivityList (inUIOSelector):
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
#Получить объект
lObject=UIOSelector_Get_UIO(inUIOSelector)
lActionList=dir(lObject)
lResult=dir(lObject)
#Выполнить чистку списка от неактуальных методов
for lActionItem in lActionList:
#Удалить те, которые начинаются на _
if lActionItem[0]=='_':
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
####################################################################################################
#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
#old name - ElementRunAction
def UIOSelectorUIOActivity_Run_Dict(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}):
def UIOSelectorUIOActivity_Run_Dict(inUIOSelector, inActionName, inArgumentList=[], inkwArgumentObject={}):
lResult={}
#Определить объект
lObject=UIOSelector_Get_UIO(inControlSpecificationArray)
#Получить метод для вызова
lFunction = getattr(lObject, inActionName)
#Выполнить действие
#Обернуто в безопасную обработку, тк для некоторых объектов метод не работает и может выдавать ошибку типа: NotImplementedError: This method not work properly for WinForms DataGrid, use cells()
try:
return lFunction(*inArgumentList,**inkwArgumentObject)
except Exception as e:
#Если ошибка возникла на action get_properties
if inActionName=="get_properties":
lResult={}
#Ручное формирование
lResult["class_name"]=lObject.class_name()
lResult["friendly_class_name"]=lObject.friendly_class_name()
lResult["texts"]=lObject.texts()
lResult["control_id"]=lObject.control_id()
lResult["control_count"]=lObject.control_count()
lResult["automation_id"]=lObject.automation_id()
return lResult
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
#Run activity if SafeOtherProcess is None
if lSafeOtherProcess is None:
#Определить объект
lObject=UIOSelector_Get_UIO(inUIOSelector)
#Получить метод для вызова
lFunction = getattr(lObject, inActionName)
#Выполнить действие
#Обернуто в безопасную обработку, тк для некоторых объектов метод не работает и может выдавать ошибку типа: NotImplementedError: This method not work properly for WinForms DataGrid, use cells()
try:
return lFunction(*inArgumentList,**inkwArgumentObject)
except Exception as e:
#Если ошибка возникла на action get_properties
if inActionName=="get_properties":
lResult={}
#Ручное формирование
lResult["class_name"]=lObject.class_name()
lResult["friendly_class_name"]=lObject.friendly_class_name()
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:
raise e
lResult = lPIPEResponseDict["Result"]
return lResult
####################################################################################################
#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
def UIOSelector_Get_UIOInfo(inControlSpecificationArray):
#Подготовка входного массива
inControlSpecificationArray=UIOSelector_SearchUIONormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
if len(inControlSpecificationArray) > 0:
#Получить объект
lTempObject=UIOSelector_Get_UIO(inControlSpecificationArray)
#Получить инфо объект
lTempObjectInfo = lTempObject.element_info
#Добавить информацию об обнаруженом объекте
lResultList.append(UIOEI_Convert_UIOInfo(lTempObjectInfo));
def UIOSelector_Get_UIOInfo(inUIOSelector):
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
#Подготовка входного массива
inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
if len(inUIOSelector) > 0:
#Получить объект
lTempObject=UIOSelector_Get_UIO(inUIOSelector)
#Получить инфо объект
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
####################################################################################################
#Search child UIO by the: Parent UIO, X, Y
#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
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#inControlSpecificationArray- UIOSelector
#old name - ElementGetChildElementList
def UIOSelector_GetChildList_UIOList(inControlSpecificationArray=[],inBackend=mDefaultPywinautoBackend):
#Подготовка входного массива
inControlSpecificationArray=UIOSelector_SearchUIONormalize_UIOSelector(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
#ctypes.windll.user32.MessageBoxW(0, str(inControlSpecificationArray), "Your title", 1)
if len(inControlSpecificationArray) > 0:
#Получить объект
lTempObject = UIOSelector_Get_UIO(inControlSpecificationArray)
#Получить список дочерних объектов
lTempChildList = lTempObject.children()
lIterator=0
#Подготовить результирующий объект
for lChild in lTempChildList:
lTempObjectInfo=lChild.element_info
#Добавить информацию об обнаруженом объекте
lObjectInfoItem=UIOEI_Convert_UIOInfo(lTempObjectInfo)
#Итератор внутри объекта (для точной идентификации)
lObjectInfoItem['ctrl_index']=lIterator;
lResultList.append(lObjectInfoItem);
#Инкремент счетчика
lIterator=lIterator+1
def UIOSelector_GetChildList_UIOList(inUIOSelector=[], inBackend=mDefaultPywinautoBackend):
#Check the bitness
lSafeOtherProcess = UIOSelector_SafeOtherGet_Process(inUIOSelector)
if lSafeOtherProcess is None:
#Подготовка входного массива
inUIOSelector=UIOSelector_SearchUIONormalize_UIOSelector(inUIOSelector)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
#ctypes.windll.user32.MessageBoxW(0, str(inControlSpecificationArray), "Your title", 1)
if len(inUIOSelector) > 0:
#Получить объект
lTempObject = UIOSelector_Get_UIO(inUIOSelector)
#Получить список дочерних объектов
lTempChildList = lTempObject.children()
lIterator=0
#Подготовить результирующий объект
for lChild in lTempChildList:
lTempObjectInfo=lChild.element_info
#Добавить информацию об обнаруженом объекте
lObjectInfoItem=UIOEI_Convert_UIOInfo(lTempObjectInfo)
#Итератор внутри объекта (для точной идентификации)
lObjectInfoItem['ctrl_index']=lIterator;
lResultList.append(lObjectInfoItem);
#Инкремент счетчика
lIterator=lIterator+1
else:
lResultList=BackendStr_GetTopLevelList_UIOInfo(inBackend)
#Установка бэк-енда на первый элемент
for lItem in lResultList:
lItem["backend"]=inBackend
else:
lResultList=BackendStr_GetTopLevelList_UIOInfo(inBackend)
#Установка бэк-енда на первый элемент
for lItem in lResultList:
lItem["backend"]=inBackend
# Run function from other process with help of PIPE
lPIPEResuestDict = {"ModuleName": "UIDesktop", "ActivityName": "UIOSelector_GetChildList_UIOList",
"ArgumentList": [inUIOSelector, 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
####################################################################################################
@ -1080,17 +1218,53 @@ def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend):
###################################################################################################
#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
def UIOSelector_Highlight(inSpecificationArray):
UIO_Highlight(UIOSelector_Get_UIO(inSpecificationArray))
return
def UIOSelector_Highlight(inUIOSelector):
#Check the bitness
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
#!!!!!Safe call is included (you can set activity and UIDesktop will choose the bitness and return the result)!!!!!
#old name - ElementDrawOutlineNewFocus
def UIOSelector_FocusHighlight(inSpecificationArray):
UIO_FocusHighlight(UIOSelector_Get_UIO(inSpecificationArray))
return
def UIOSelector_FocusHighlight(inUIOSelector):
#Check the bitness
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

@ -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'])
lProcessResponse["Result"]=JSONNormalize.JSONNormalizeDictListStrIntBool(lFunction(*lJSONInput['ArgumentList'],**lJSONInput['ArgumentDict']))
except Exception as e:
lProcessResponse["Result"] = None
#Установить флаг ошибки
lProcessResponse["ErrorFlag"]=True
#Зафиксировать 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
[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.1 Beta
Refactoring (Studio Orchestrator in pyOpenRPA package)

Loading…
Cancel
Save