def DetectZoomMeeting(): global zoomToolbarOpen global zoomMeetingOpen if debug == True: global start start = time.time() zoomMeetingInProgress = False def GetFirstChild(control): return control.GetFirstChildControl() def GetNextSibling(control): return control.GetNextSiblingControl() desktop = automation.GetRootControl() zoomMeetingOpen = False zoomToolbarOpen = False for control, depth in automation.WalkTree(desktop, getFirstChild=GetFirstChild, getNextSibling=GetNextSibling, includeTop=False, maxDepth=2): if debug == True: print(str(depth) + ' ' * depth * 4 + str(control)) if str(control).find("ZPContentViewWndClass") > 0: zoomMeetingInProgress = True zoomMeetingOpen = True if str(control).find("ZPFloatToolbarClass") > 0: zoomMeetingInProgress = True zoomToolbarOpen = True return zoomMeetingInProgress
def _get_element_by_locator_string( self, locator: str, search_depth: int, root_element: Optional[WindowsElement] ) -> WindowsElement: root = root_element.item if self._window_or_none(root_element) else None anchor = self.anchor.item if self.anchor else None window = self.window.item if self.window else None self.logger.debug("argument root = %s", root) self.logger.debug("active anchor = %s", anchor) self.logger.debug("active window = %s", window) root_result = root or anchor or window or auto.GetRootControl() self.logger.debug("resulting root = %s", root_result) locators = locator.split(MatchObject.TREE_SEP) try: for loc in locators: self.logger.info("Root element: %r", root_result) control = self._get_control_with_locator_part( loc, search_depth, root_result ) root_result = control except LookupError as err: raise ElementNotFound( f"Element not found with locator {locator!r}" ) from err # If we get here, then we have a `control` no matter what. return WindowsElement(control, locator)
def get_element( self, locator: Optional[Locator] = None, search_depth: int = 8, root_element: Optional[WindowsElement] = None, timeout: Optional[float] = None, # pylint: disable=unused-argument ) -> WindowsElement: if isinstance(locator, str): locator = self._load_by_alias(locator) self.logger.info("Getting element with locator: %s", locator) if not locator: element = ( self.ctx.anchor_element or self.ctx.window_element or WindowsElement(auto.GetRootControl(), None) ) elif isinstance(locator, str): element = self._get_element_by_locator_string( locator, search_depth, root_element ) else: element = locator if self._window_or_none(element) is None: raise ElementNotFound(f"Unable to get element with {locator!r}") self.logger.info("Returning element: %s", element) return element
def screen_capture(self): time.sleep(2) c = automation.GetRootControl() if c.CaptureToImage(path): automation.Logger.WriteLine('capture image: ' + path) else: automation.Logger.WriteLine('capture failed', automation.ConsoleColor.Yellow)
def _get_control_with_locator_part( self, locator: str, search_depth: int, root_control: "Control" ) -> "Control": # Prepare control search parameters. match_object = MatchObject.parse_locator(locator) self.logger.info("Locator %r produced matcher: %s", locator, match_object) search_params = {} for loc in match_object.locators: # pylint: disable=not-an-iterable search_params[loc[0]] = loc[1] if "searchDepth" not in search_params: search_params["searchDepth"] = search_depth # Obtain an element with the search parameters. if "desktop" in search_params: root_control = auto.GetRootControl() return Control.CreateControlFromControl(root_control) if "executable" in search_params: return self._get_control_from_listed_windows( search_params, param_type="executable", win_type="name" ) if "handle" in search_params: return self._get_control_from_listed_windows( search_params, param_type="handle", win_type="handle" ) return self._get_control_from_params(search_params, root_control=root_control)
def DetectZoomMeeting(): if debug: global start start = time.time() zoomMeetingInProgress = False def GetFirstChild(control): return control.GetFirstChildControl() def GetNextSibling(control): return control.GetNextSiblingControl() desktop = automation.GetRootControl() #window = automation.WindowControl(searchDepth=1, ClassName='ZPContentViewWndClass') #toolsMenu = window.WindowControl(searchDepth=3, ClassName='ZPControlPanelClass') #start = time.time() for control, depth in automation.WalkTree(desktop, getFirstChild=GetFirstChild, getNextSibling=GetNextSibling, includeTop=False, maxDepth=2): if debugWalkTree: print('DEBUG:' + str(depth) + ' ' * depth * 4 + str(control)) if str(control).find("ZPContentViewWndClass") > 0: zoomMeetingInProgress = True return zoomMeetingInProgress
def __new__(cls, *args, **kwargs): if not cls.__instance: cls.__instance = super().__new__(cls, *args, **kwargs) print(auto.GetRootControl()) subprocess.Popen( "C:\\Program Files (x86)\\HexMeetHJT\\HexMeetHJT.exe") return cls.__instance
def vars(self): self.color = True self.inMeeting = False self.muted = False self.desktop = automation.GetRootControl() self.window = automation.WindowControl( searchDepth=1, ClassName='ZPContentViewWndClass') self.toolsMenu = self.window.WindowControl( searchDepth=3, ClassName='ZPControlPanelClass')
def test1(stopEvent): c = automation.GetRootControl() n = 0 while True: if stopEvent.is_set(): break print(n) n += 1 stopEvent.wait(1) print('test1 exits')
def _find_window(self, locator, main) -> Optional[WindowsElement]: try: # `root_element = None` means using the `anchor` or `window` as root later # on. (fallbacks to Desktop) root_element = (WindowsElement(auto.GetRootControl(), locator) if main else None) window = self.ctx.get_element(locator, root_element=root_element) return window except (ElementNotFound, LookupError): return None
def WalkDesktop(): def GetFirstChild(control): return control.GetFirstChildControl() def GetNextSibling(control): return control.GetNextSiblingControl() desktop = automation.GetRootControl() for control, depth in automation.WalkTree(desktop, getFirstChild=GetFirstChild, getNextSibling=GetNextSibling, includeTop=True, maxDepth=2): print(' ' * depth * 4 + str(control))
def hide(): root = automation.GetRootControl() for window in root.GetChildren(): if window.ClassName in WindowsWantToHide: automation.Logger.WriteLine('hide window, handle {}'.format( window.Handle)) window.Hide() fin = open('hide_windows.txt', 'wt') fin.write(str(window.Handle) + '\n') fin.close()
def main(): main = threading.currentThread() auto.Logger.WriteLine('This is running in main thread. {} {}'.format(main.ident, main.name), auto.ConsoleColor.Cyan) time.sleep(2) auto.GetConsoleWindow().CaptureToImage('console_mainthread.png') root = auto.GetRootControl() auto.EnumAndLogControl(root, 1) th = threading.Thread(target=threadFunc, args=(root, )) th.start() th.join() auto.Logger.WriteLine('\nMain thread exits. {} {}'.format(main.ident, main.name), auto.ConsoleColor.Cyan)
def win32_automation(): print(automation.GetRootControl()) subprocess.Popen('notepad.exe') notepadWindow = automation.WindowControl(searchDepth=1, ClassName='Notepad') print(notepadWindow.Name) notepadWindow.SetTopmost(True) edit = notepadWindow.EditControl() #edit.SetValue('Hello') edit.SendKeys('{Ctrl}{End}{Enter}World')
def main(args): if args.time > 0: time.sleep(args.time) start = time.clock() if args.active: c = automation.GetForegroundControl() elif args.cursor or args.up: c = automation.ControlFromCursor() elif args.fullscreen: c = automation.GetRootControl() CaptureControl(c, args.path, args.up) automation.Logger.WriteLine('cost time: {:.3f} s'.format(time.clock() - start))
def main(): if auto.IsNT6orHigher: oriTitle = auto.GetConsoleOriginalTitle() else: oriTitle = auto.GetConsoleTitle() auto.SetConsoleTitle(auto.GetConsoleTitle() + ' | Ctrl+1,Ctrl+2, stop Ctrl+4') auto.Logger.ColorfullyWriteLine('Press <Color=Cyan>Ctrl+1 or Ctrl+2</Color> to start, press <Color=Cyan>ctrl+4</Color> to stop') auto.Logger.Write('\nUse UIAutomation in main thread:\n', auto.ConsoleColor.Yellow) auto.LogControl(auto.GetRootControl()) auto.Logger.Write('\n') auto.RunByHotKey({(auto.ModifierKey.Control, auto.Keys.VK_1): test1, (auto.ModifierKey.Control, auto.Keys.VK_2): test2}, (auto.ModifierKey.Control, auto.Keys.VK_4)) auto.SetConsoleTitle(oriTitle)
def walk(): wiresharkWindow = None for win in auto.GetRootControl().GetChildren(): if win.ClassName == 'MainWindow' and win.AutomationId == 'MainWindow': if win.ToolBarControl( AutomationId='MainWindow.displayFilterToolBar').Exists( 0, 0): wiresharkWindow = win break if not wiresharkWindow: auto.Logger.WriteLine('Can not find Wireshark', auto.ConsoleColor.Yellow) return console = auto.GetConsoleWindow() if console: sx, sy = auto.GetScreenSize() tp = console.GetTransformPattern() tp.Resize(sx, sy // 4) tp.Move(0, sy - sy // 4 - 50) console.SetTopmost() wiresharkWindow.SetActive(waitTime=0.1) wiresharkWindow.Maximize() auto.Logger.ColorfullyWriteLine('Press <Color=Cyan>F1</Color> to stop', auto.ConsoleColor.Yellow) tree = wiresharkWindow.TreeControl(searchDepth=4, ClassName='PacketList', Name='Packet list') rect = tree.BoundingRectangle tree.Click(y=50, waitTime=0.1) auto.SendKeys('{Home}', waitTime=0.1) columnCount = 0 treeItemCount = 0 for item, depth in auto.WalkControl(tree): if isinstance(item, auto.HeaderControl): columnCount += 1 auto.Logger.Write(item.Name + ' ') elif isinstance(item, auto.TreeItemControl): if treeItemCount % columnCount == 0: auto.Logger.Write('\n') time.sleep(0.1) treeItemCount += 1 auto.Logger.Write(item.Name + ' ') if item.BoundingRectangle.bottom >= rect.bottom: auto.SendKeys('{PageDown}', waitTime=0.1) if auto.IsKeyPressed(auto.Keys.VK_F1): auto.Logger.WriteLine('\nF1 pressed', auto.ConsoleColor.Yellow) break
def threadFunc(root): """ If you want to use functionalities related to Controls and Patterns in a new thread. You must call InitializeUIAutomationInCurrentThread first in the thread and call UninitializeUIAutomationInCurrentThread when the thread exits. But you can't use use a Control or a Pattern created in a different thread. So you can't create a Control or a Pattern in main thread and then pass it to a new thread and use it. """ #print(root)# you cannot use root because it is root control created in main thread th = threading.currentThread() auto.Logger.WriteLine('\nThis is running in a new thread. {} {}'.format(th.ident, th.name), auto.ConsoleColor.Cyan) time.sleep(2) auto.InitializeUIAutomationInCurrentThread() auto.GetConsoleWindow().CaptureToImage('console_newthread.png') newRoot = auto.GetRootControl() #ok, root control created in new thread auto.EnumAndLogControl(newRoot, 1) auto.UninitializeUIAutomationInCurrentThread() auto.Logger.WriteLine('\nThread exits. {} {}'.format(th.ident, th.name), auto.ConsoleColor.Cyan)
def CaptureControl(c, path, up = False): if c.CaptureToImage(path): auto.Logger.WriteLine('capture image: ' + path) else: auto.Logger.WriteLine('capture failed', auto.ConsoleColor.Yellow) if up: r = auto.GetRootControl() depth = 0 name, ext = os.path.splitext(path) while True: c = c.GetParentControl() if not c or auto.ControlsAreSame(c, r): break depth += 1 savePath = name + '_p' * depth + ext if c.CaptureToImage(savePath): auto.Logger.WriteLine('capture image: ' + savePath) subprocess.Popen(path, shell = True)
def threadFunc(uselessRoot): """ If you want to use UI Controls in a new thread, create an UIAutomationInitializerInThread object first. But you can't use use a Control or a Pattern created in a different thread. So you can't create a Control or a Pattern in main thread and then pass it to a new thread and use it. """ # print(uselessRoot)# you cannot use uselessRoot because it is a control created in a different thread th = threading.currentThread() auto.Logger.WriteLine( '\nThis is running in a new thread. {} {}'.format(th.ident, th.name), auto.ConsoleColor.Cyan) time.sleep(2) with auto.UIAutomationInitializerInThread(debug=True): auto.GetConsoleWindow().CaptureToImage('console_newthread.png') newRoot = auto.GetRootControl( ) # ok, root control created in current thread auto.EnumAndLogControl(newRoot, 1) auto.Logger.WriteLine('\nThread exits. {} {}'.format(th.ident, th.name), auto.ConsoleColor.Cyan)
def main(args): if args.time > 0: time.sleep(args.time) start = time.time() if args.active: c = auto.GetForegroundControl() CaptureControl(c, args.path, args.up) elif args.cursor or args.up: c = auto.ControlFromCursor() CaptureControl(c, args.path, args.up) elif args.fullscreen: c = auto.GetRootControl() rects = auto.GetMonitorsRect() dot = args.path.rfind('.') for i, rect in enumerate(rects): path = args.path[:dot] + '_' * i + args.path[dot:] c.CaptureToImage(path, rect.left, rect.top, rect.width(), rect.height()) auto.Logger.WriteLine('capture image: ' + path) auto.Logger.WriteLine('cost time: {:.3f} s'.format(time.time() - start))
def close_window( self, locator: Optional[Locator] = None, timeout: Optional[float] = None, # pylint: disable=unused-argument ) -> int: """Closes identified windows or logs the problems. :param locator: String locator or `Control` element. :param timeout: float value in seconds, see keyword ``Set Global Timeout`` :return: How many windows were found and closed. Example: .. code-block:: robotframework ${closed_count} = Close Window Calculator """ # Starts the search from Desktop level. root_element = WindowsElement(auto.GetRootControl(), locator) # With all flavors of locators. (if flexible) for loc in self._iter_locator(locator): try: elements: List[WindowsElement] = self.ctx.get_elements( loc, root_element=root_element) except (ElementNotFound, LookupError): continue break else: raise WindowControlError( f"Couldn't find any window with {locator!r}") closed = 0 for element in elements: self.logger.debug("Controlling and closing window: %s", element) try: self.control_window(element) closed += int(self.close_current_window()) except Exception as exc: # pylint: disable=broad-except self.logger.warning("Couldn't close window %r due to: %s", element, exc) return closed
def list_windows(self, icons: bool = False, icon_save_directory: Optional[str] = None) -> List[Dict]: windows = auto.GetRootControl().GetChildren() process_list = get_process_list() win_list = [] for win in windows: pid = win.ProcessId fullpath = None try: handle = win32api.OpenProcess( win32con.PROCESS_QUERY_LIMITED_INFORMATION, False, pid) fullpath = win32process.GetModuleFileNameEx(handle, 0) except Exception as err: # pylint: disable=broad-except self.logger.info("Open process error in `List Windows`: %s", err) handle = win.NativeWindowHandle icon_string = (self.get_icon(fullpath, icon_save_directory) if icons else None) rect = win.BoundingRectangle rectangle = ([rect.left, rect.top, rect.right, rect.bottom] if rect else [None] * 4) info = { "title": win.Name, "pid": pid, "name": process_list[pid] if pid in process_list else None, "path": fullpath, "handle": handle, "icon": icon_string, "automation_id": win.AutomationId, "control_type": win.ControlTypeName, "class_name": win.ClassName, "rectangle": rectangle, "keyboard_focus": win.HasKeyboardFocus, "is_active": handle == auto.GetForegroundWindow(), "object": win, } if icons and not icon_string: self.logger.info("Icon for %s returned empty", win.Name) win_list.append(info) return win_list
def test1(stopEvent): """ This function runs in a new thread triggered by hotkey. """ auto.InitializeUIAutomationInCurrentThread() n = 0 child = None auto.Logger.WriteLine('Use UIAutomation in another thread:', auto.ConsoleColor.Yellow) while True: if stopEvent.is_set(): break if not child: n = 1 child = auto.GetRootControl().GetFirstChildControl() auto.Logger.WriteLine(n, auto.ConsoleColor.Cyan) auto.LogControl(child) child = child.GetNextSiblingControl() n += 1 stopEvent.wait(1) auto.UninitializeUIAutomationInCurrentThread() print('test1 exits')
def get_chrome_url(focused=False): try: if not focused: control = automation.FindControl( automation.GetRootControl(), lambda c, d: c.ClassName.startswith('Chrome')) else: control = automation.GetFocusedControl() control_list = [] while control: control_list.insert(0, control) control = control.GetParentControl() if len(control_list) == 1: control = control_list[0] else: control = control_list[1] address_control = automation.FindControl( control, lambda c, d: isinstance(c, automation.EditControl) and "Address and search bar" in c.Name) return address_control.CurrentValue() except AttributeError: return None
def Screenshot(self=uiautomation.GetRootControl(), filename=f"{time.strftime(r'%Y%m%d-%H%M%S')}.jpg", log=True): if not ENABLE_SCREENSHOT: return "Screenshot disabled" file_path = LOG_DIR / filename stem = file_path.stem suffix = file_path.suffix num = 1 while file_path.is_file(): file_path = LOG_DIR / f"{stem}-{num}{suffix}" num += 1 rect = self.Element.CurrentBoundingRectangle x = rect.left y = rect.top w = rect.right - rect.left h = rect.bottom - rect.top self.CaptureToImage(str(file_path), x, y, w, h) logging.debug(f"Screenshot to file: {file_path}") try: relative_path = file_path.relative_to(os.getcwd()) except ValueError: relative_path = file_path if log: if "robot" in sys.modules: from robot.api import logger logger.info( f"Screenshot to file {file_path}\n" f"{embedded_image(relative_path)}", html=True) else: logging.info(f"Screenshot to file {file_path}") return relative_path
def main(): import getopt auto.Logger.Write('UIAutomation {} (Python {}.{}.{}, {} bit)\n'.format( auto.VERSION, sys.version_info.major, sys.version_info.minor, sys.version_info.micro, 64 if sys.maxsize > 0xFFFFFFFF else 32)) options, args = getopt.getopt(sys.argv[1:], 'hrfcand:t:', [ 'help', 'root', 'focus', 'cursor', 'ancestor', 'showAllName', 'depth=', 'time=' ]) root = False focus = False cursor = False ancestor = False foreground = True showAllName = False depth = 0xFFFFFFFF seconds = 3 for (o, v) in options: if o in ('-h', '-help'): usage() exit(0) elif o in ('-r', '-root'): root = True foreground = False elif o in ('-f', '-focus'): focus = True foreground = False elif o in ('-c', '-cursor'): cursor = True foreground = False elif o in ('-a', '-ancestor'): ancestor = True foreground = False elif o in ('-n', '-showAllName'): showAllName = True elif o in ('-d', '-depth'): depth = int(v) elif o in ('-t', '-time'): seconds = int(v) if seconds > 0: auto.Logger.Write('please wait for {0} seconds\n\n'.format(seconds), writeToFile=False) time.sleep(seconds) auto.Logger.Log('Starts, Current Cursor Position: {}'.format( auto.GetCursorPos())) control = None if root: control = auto.GetRootControl() if focus: control = auto.GetFocusedControl() if cursor: control = auto.ControlFromCursor() if depth < 0: while depth < 0 and control: control = control.GetParentControl() depth += 1 depth = 0xFFFFFFFF if ancestor: control = auto.ControlFromCursor() if control: auto.EnumAndLogControlAncestors(control, showAllName) else: auto.Logger.Write( 'IUIAutomation returns null element under cursor\n', auto.ConsoleColor.Yellow) else: indent = 0 if not control: control = auto.GetFocusedControl() controlList = [] while control: controlList.insert(0, control) control = control.GetParentControl() if len(controlList) == 1: control = controlList[0] else: control = controlList[1] if foreground: indent = 1 auto.LogControl(controlList[0], 0, showAllName) auto.EnumAndLogControl(control, depth, showAllName, startDepth=indent) auto.Logger.Log('Ends\n')
import os import subprocess from time import sleep import uiautomation as auto print(auto.GetRootControl()) # subprocess.Popen('notepad.exe') # notepadWindow = automation.WindowControl(searchDepth=1, ClassNam='Notepad') # print(notepadWindow.Name) # notepadWindow.SetTopmost(True) # edit = notepadWindow.EditControl() # edit.SetValue('Hello') # edit.SendKeys('{Ctrl}{End}{Enter}World') subprocess.Popen('C:\Program Files (x86)\PesticideModels\TOPRice\TOPrice.exe') window = auto.WindowControl(searchDepth=1, title_re='TOPrice*') if auto.WaitForExist(window, 3): auto.Logger.WriteLine("Notepad exists now") else: auto.Logger.WriteLine("Notepad does not exist after 3 seconds", auto.ConsoleColor.Yellow) window.SetActive() # windowFont = window.WindowControl(Name='File') # print(window.Name) # window.window_(title_re = u'File').Click() # # # window.SetTopmost(True) # window.ButtonControl(name="Projects").Click() # button = auto.ButtonControl(Name='Projects')
def main(): width = 500 height = 500 cmdWindow = auto.GetConsoleWindow() print('create a transparent image') bitmap = auto.Bitmap(width, height) bitmap.ToFile('image_transparent.png') cmdWindow.SetActive() print('create a blue image') start = auto.ProcessTime() for x in range(width): for y in range(height): argb = 0x0000FF | ((255 * x // 500) << 24) bitmap.SetPixelColor(x, y, argb) cost = auto.ProcessTime() - start print('write {}x{} image by SetPixelColor cost {:.3f}s'.format( width, height, cost)) bitmap.ToFile('image_blue.png') start = auto.ProcessTime() for x in range(width): for y in range(height): bitmap.GetPixelColor(x, y) cost = auto.ProcessTime() - start print('read {}x{} image by GetPixelColor cost {:.3f}s'.format( width, height, cost)) argb = [(0xFF0000 | (0x0000FF * y // height) | ((255 * x // width) << 24)) for x in range(width) for y in range(height)] start = auto.ProcessTime() bitmap.SetPixelColorsOfRect(0, 0, width, height, argb) cost = auto.ProcessTime() - start print( 'write {}x{} image by SetPixelColorsOfRect with List[int] cost {:.3f}s' .format(width, height, cost)) bitmap.ToFile('image_red.png') arrayType = auto.ctypes.c_uint32 * (width * height) nativeArray = arrayType(*argb) start = auto.ProcessTime() bitmap.SetPixelColorsOfRect(0, 0, width, height, nativeArray) cost = auto.ProcessTime() - start print( 'write {}x{} image by SetPixelColorsOfRect with native array cost {:.3f}s' .format(width, height, cost)) bitmap.ToFile('image_red2.png') start = auto.ProcessTime() colors = bitmap.GetAllPixelColors() cost = auto.ProcessTime() - start print('read {}x{} image by GetAllPixelColors cost {:.3f}s'.format( width, height, cost)) bitmap.ToFile('image_red.png') bitmap.ToFile('image_red.jpg') subprocess.Popen('image_red.png', shell=True) root = auto.GetRootControl() bitmap = root.ToBitmap(0, 0, 400, 400) print('save (0,0,400,400) of desktop to desk_part.png') bitmap.ToFile('desk_part.png') width, height = 100, 100 colors = bitmap.GetPixelColorsOfRects([(0, 0, width, height), (100, 100, width, height), (200, 200, width, height)]) for i, nativeArray in enumerate(colors): print('save part of desk_part.png to desk_part{}.png'.format(i)) with auto.Bitmap(width, height) as subBitmap: subBitmap.SetPixelColorsOfRect(0, 0, width, height, nativeArray) subBitmap.ToFile('desk_part{}.png'.format(i)) print('save part of desk_part.png to desk_part3.png') with bitmap.Copy(300, 300, 100, 100) as subBitmap: subBitmap.ToFile('desk_part3.png') print('flip X of desk_part.png') with bitmap.RotateFlip(auto.RotateFlipType.RotateNoneFlipX) as bmpFlipX: bmpFlipX.ToFile('desk_flipX.png') print('flip Y of desk_part.png') with bitmap.RotateFlip(auto.RotateFlipType.RotateNoneFlipY) as bmpFlipY: bmpFlipY.ToFile('desk_flipY.png') print('rotate 90 of desk_part.png') with bitmap.Rotate(90) as bmpRotate90: bmpRotate90.ToFile('desk_rotate90.png') print('rotate 270 of desk_part.png') with bitmap.Rotate(270) as bmpRotate270: bmpRotate270.ToFile('desk_rotate270.png') print('rotate 45 of desk_part.png') with bitmap.Rotate(45) as bmpRotate45: bmpRotate45.ToFile('desk_rotate45.png')
def SwitchToRootControl(cls): ''' switch to root control and init handles ''' __root = uiautomation.GetRootControl() cls.__handles = [(__root.Handle, __root), {"Handle":__root.Handle, "Name":__root.Name}]