text: # GUI Application automation and testing library
  # Copyright (C) 2006-2018 Mark Mc Mahon and Contributors
  # https://github.com/pywinauto/pywinauto/graphs/contributors
  # http://pywinauto.readthedocs.io/en/latest/credits.html
  # All rights reserved.
  #
  # Redistribution and use in source and binary forms, with or without
  # modification, are permitted provided that the following conditions are met:
  #
  # * Redistributions of source code must retain the above copyright notice, this
  #   list of conditions and the following disclaimer.
  #
  # * Redistributions in binary form must reproduce the above copyright notice,
  #   this list of conditions and the following disclaimer in the documentation
  #   and/or other materials provided with the distribution.
  #
  # * Neither the name of pywinauto nor the names of its
  #   contributors may be used to endorse or promote products derived from
  #   this software without specific prior written permission.
  #
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
  """Basic wrapping of Windows controls"""
  from __future__ import unicode_literals
  from __future__ import print_function
  
  # pylint:  disable-msg=W0611
  
  # import sys
  import copy
  import time
  import re
  import ctypes
  import win32api
  import win32gui
  import win32con
  import win32process
  import win32event
  import six
  import pywintypes
  import warnings
  
  # the wrappers may be used in an environment that does not need
  # the actions - as such I don't want to require sendkeys - so
  # the following makes the import optional.
  
  from .. import win32functions
  from .. import win32defines
  from .. import win32structures
  from .. import controlproperties
  from ..actionlogger import ActionLogger
  from .. import keyboard
  from .. import mouse
  from ..timings import Timings
  from .. import timings
  from .. import handleprops
  from ..win32_element_info import HwndElementInfo
  from .. import backend
  
  # I leave this optional because PIL is a large dependency
  try:
      from PIL import ImageGrab
  except ImportError:
      ImageGrab = None
  
  # also import MenuItemNotEnabled so that it is
  # accessible from HwndWrapper module
  from .menuwrapper import Menu #, MenuItemNotEnabled
  
  from ..base_wrapper import BaseWrapper
  from ..base_wrapper import BaseMeta
  from .. import deprecated
  
  
  #====================================================================
  class ControlNotEnabled(RuntimeError):
  
      """Raised when a control is not enabled"""
      pass
  
  #====================================================================
  class ControlNotVisible(RuntimeError):
  
      """Raised when a control is not visible"""
      pass
  
  #====================================================================
  class InvalidWindowHandle(RuntimeError):
  
      """Raised when an invalid handle is passed to HwndWrapper"""
  
      def __init__(self, hwnd):
          """Initialise the RuntimError parent with the mesage"""
          RuntimeError.__init__(self,
              "Handle {0} is not a vaild window handle".format(hwnd))
  
  #=========================================================================
  class HwndMeta(BaseMeta):
  
      """Metaclass for HwndWrapper objects"""
      re_wrappers = {}
      str_wrappers = {}
  
      def __init__(cls, name, bases, attrs):
          """
          Register the class names
  
          Both the regular expression or the classes directly are registered.
          """
          BaseMeta.__init__(cls, name, bases, attrs)
  
          for win_class in cls.windowclasses:
              HwndMeta.re_wrappers[re.compile(win_class)] = cls
              HwndMeta.str_wrappers[win_class] = cls
  
      @staticmethod
      def find_wrapper(element):
          """Find the correct wrapper for this native element"""
          if isinstance(element, six.integer_types):
              element = HwndElementInfo(element)
          class_name = element.class_name
  
          try:
              return HwndMeta.str_wrappers[class_name]
          except KeyError:
              wrapper_match = None
  
              for regex, wrapper in HwndMeta.re_wrappers.items():
                  if regex.match(class_name):
                      wrapper_match = wrapper
                      HwndMeta.str_wrappers[class_name] = wrapper
  
                      return wrapper
  
          # if it is a dialog then override the wrapper we found
          # and make it a DialogWrapper
          if handleprops.is_toplevel_window(element.handle):
              wrapper_match = DialogWrapper
  
          if wrapper_match is None:
              wrapper_match = HwndWrapper
          return wrapper_match
  
  #====================================================================
  @six.add_metaclass(HwndMeta)
  class HwndWrapper(BaseWrapper):
  
      """
      Default wrapper for controls.
  
      All other wrappers are derived from this.
  
      This class wraps a lot of functionality of underlying windows API
      features for working with windows.
  
      Most of the methods apply to every single window type. For example
      you can click() on any window.
  
      Most of the methods of this class are simple wrappers around
      API calls and as such they try do the simplest thing possible.
  
      An HwndWrapper object can be passed directly to a ctypes wrapped
      C function - and it will get converted to a Long with the value of
      it's handle (see ctypes, _as_parameter_).
      """
      handle = None
  
      # -----------------------------------------------------------
      def __new__(cls, element):
          """Construct the control wrapper"""
          return super(HwndWrapper, cls)._create_wrapper(cls, element, HwndWrapper)
  
      # -----------------------------------------------------------
      def __init__(self, element_info):
          """
          Initialize the control
  
          * **element_info** is either a valid HwndElementInfo or it can be an
            instance or subclass of HwndWrapper.
          If the handle is not valid then an InvalidWindowHandle error
          is raised.
          """
          if isinstance(element_info, six.integer_types):
              element_info = HwndElementInfo(element_info)
          if hasattr(element_info, "element_info"):
              element_info = element_info.element_info
  
          BaseWrapper.__init__(self, element_info, backend.registry.backends['win32'])
  
          # verify that we have been passed in a valid windows handle
          if not win32functions.IsWindow(self.handle):
              raise InvalidWindowHandle(self.handle)
  
          # make it so that ctypes conversion happens correctly
          self._as_parameter_ = self.handle
  
      @property
      def writable_props(self):
          """Extend default properties list."""
          props = super(HwndWrapper, self).writable_props
          props.extend(['style',
                        'exstyle',
                        'user_data',
                        'context_help_id',
                        'fonts',
                        'client_rects',
                        'is_unicode',
                        'menu_items',
                        'automation_id',
                        ])
          return props
  
      # -----------------------------------------------------------
      def style(self):
          """
          Returns the style of window
  
          Return value is a long.
  
          Combination of WS_* and specific control specific styles.
          See HwndWrapper.has_style() to easily check if the window has a
          particular style.
          """
          return handleprops.style(self)
      # Non PEP-8 alias
      Style = deprecated(style)
  
      # -----------------------------------------------------------
      def exstyle(self):
          """
          Returns the Extended style of window
  
          Return value is a long.
  
          Combination of WS_* and specific control specific styles.
          See HwndWrapper.has_style() to easily check if the window has a
          particular style.
          """
          return handleprops.exstyle(self)
      # Non PEP-8 alias
      ExStyle = deprecated(exstyle, deprecated_name='ExStyle')
  
      #------------------------------------------------------------
      def automation_id(self):
          """Return the .NET name of the control"""
          return self.element_info.automation_id
  
      #------------------------------------------------------------
      def control_type(self):
          """Return the .NET type of the control"""
          return self.element_info.control_type
  
      #------------------------------------------------------------
      def full_control_type(self):
          """Return the .NET type of the control (full, uncut)"""
          return self.element_info.full_control_type
  
      # -----------------------------------------------------------
      def user_data(self):
          """
          Extra data associted with the window
  
          This value is a long value that has been associated with the window
          and rarely has useful data (or at least data that you know the use
          of).
          """
          return handleprops.userdata(self)
      # Non PEP-8 alias
      UserData = deprecated(user_data)
  
      # -----------------------------------------------------------
      def context_help_id(self):
          """Return the Context Help ID of the window"""
          return handleprops.contexthelpid(self)
      # Non PEP-8 alias
      ContextHelpID = deprecated(context_help_id, deprecated_name='ContextHelpID')
  
      # -----------------------------------------------------------
      def is_active(self):
          """Whether the window is active or not"""
          return self.top_level_parent() == self.get_active()
      # Non PEP-8 alias
      IsActive = deprecated(is_active)
  
      # -----------------------------------------------------------
      def is_unicode(self):
          """
          Whether the window is unicode or not
  
          A window is Unicode if it was registered by the Wide char version
          of RegisterClass(Ex).
          """
          return handleprops.isunicode(self)
      # Non PEP-8 alias
      IsUnicode = deprecated(is_unicode)
  
      # -----------------------------------------------------------
      def client_rect(self):
          """
          Returns the client rectangle of window
  
          The client rectangle is the window rectangle minus any borders that
          are not available to the control for drawing.
  
          Both top and left are always 0 for this method.
  
          This method returns a RECT structure, Which has attributes - top,
          left, right, bottom. and has methods width() and height().
          See win32structures.RECT for more information.
          """
          return handleprops.clientrect(self)
      # Non PEP-8 alias
      ClientRect = deprecated(client_rect)
  
      # -----------------------------------------------------------
      #def client_to_screen(self, client_point):
      #    """Maps point from client to screen coordinates"""
      #    point = win32structures.POINT()
      #    if isinstance(client_point, win32structures.POINT):
      #        point.x = client_point.x
      #        point.y = client_point.y
      #    else:
      #        point.x = client_point[0]
      #        point.y = client_point[1]
      #    win32functions.client_to_screen(self, ctypes.byref(point))
      #
      #    # return tuple in any case because
      #    # coords param is always expected to be tuple
      #    return point.x, point.y
  
      # -----------------------------------------------------------
      def font(self):
          """
          Return the font of the window
  
          The font of the window is used to draw the text of that window.
          It is a structure which has attributes for font name, height, width
          etc.
  
          See win32structures.LOGFONTW for more information.
          """
          return handleprops.font(self)
      # Non PEP-8 alias
      Font = deprecated(font)
  
      # -----------------------------------------------------------
      def has_style(self, style):
          """Return True if the control has the specified style"""
          return handleprops.has_style(self, style)
      # Non PEP-8 alias
      HasStyle = deprecated(has_style)
  
      # -----------------------------------------------------------
      def has_exstyle(self, exstyle):
          """Return True if the control has the specified extended style"""
          return handleprops.has_exstyle(self, exstyle)
      # Non PEP-8 alias
      HasExStyle = deprecated(has_exstyle, deprecated_name='HasExStyle')
  
      # -----------------------------------------------------------
      def is_dialog(self):
          """Return true if the control is a top level window"""
          if not ("isdialog" in self._cache.keys()):
              self._cache['isdialog'] = handleprops.is_toplevel_window(self)
  
          return self._cache['isdialog']
  
      # -----------------------------------------------------------
      def client_rects(self):
          """
          Return the client rect for each item in this control
  
          It is a list of rectangles for the control. It is frequently over-ridden
          to extract all rectangles from a control with multiple items.
  
          It is always a list with one or more rectangles:
  
            * First elemtent is the client rectangle of the control
            * Subsequent elements contain the client rectangle of any items of
              the control (e.g. items in a listbox/combobox, tabs in a
              tabcontrol)
          """
  
          return [self.client_rect(), ]
      # Non PEP-8 alias
      ClientRects = deprecated(client_rects)
  
      # -----------------------------------------------------------
      def fonts(self):
          """
          Return the font for each item in this control
  
          It is a list of fonts for the control. It is frequently over-ridden
          to extract all fonts from a control with multiple items.
  
          It is always a list with one or more fonts:
  
            * First elemtent is the control font
            * Subsequent elements contain the font of any items of
              the control (e.g. items in a listbox/combobox, tabs in a
              tabcontrol)
          """
          return [self.font(), ]
      # Non PEP-8 alias
      Fonts = deprecated(fonts)
  
      # -----------------------------------------------------------
      def send_command(self, commandID):
          return self.send_message(win32defines.WM_COMMAND, commandID)
      # Non PEP-8 alias
      SendCommand = deprecated(send_command)
  
      # -----------------------------------------------------------
      def post_command(self, commandID):
          return self.post_message(win32defines.WM_COMMAND, commandID)
      # Non PEP-8 alias
      PostCommand = deprecated(post_command)
  
      # -----------------------------------------------------------
      #def notify(self, code):
      #    "Send a notification to the parent (not tested yet)"
  
      #    # now we need to notify the parent that the state has changed
      #    nmhdr = win32structures.NMHDR()
      #    nmhdr.hwndFrom = self.handle
      #    nmhdr.idFrom = self.control_id()
      #    nmhdr.code = code
  
      #    from ..remote_memory_block import RemoteMemoryBlock
      #    remote_mem = RemoteMemoryBlock(self, size=ctypes.sizeof(nmhdr))
      #    remote_mem.Write(nmhdr, size=ctypes.sizeof(nmhdr))
  
      #    retval = self.parent().send_message(
      #        win32defines.WM_NOTIFY,
      #        self.handle,
      #        remote_mem)
      #    #if retval != win32defines.TRUE:
      #    #    print('retval = ' + str(retval))
      #    #    raise ctypes.WinError()
      #    del remote_mem
  
      #    return retval
      # Non PEP-8 alias
      #Notify = deprecated(notify)
  
      # -----------------------------------------------------------
      def _ensure_enough_privileges(self, message_name):
          """Ensure the Python process has enough rights to send some window messages"""
          pid = handleprops.processid(self.handle)
          if not handleprops.has_enough_privileges(pid):
              raise RuntimeError('Not enough rights to use {} message/function for target process ' \
                  '(to resolve it run the script as Administrator)'.format(message_name))
  
      # -----------------------------------------------------------
      def send_message(self, message, wparam = 0, lparam = 0):
          """Send a message to the control and wait for it to return"""
          wParamAddress = wparam
          if hasattr(wparam, 'mem_address'):
              wParamAddress = wparam.mem_address
          lParamAddress = lparam
          if hasattr(lparam, 'mem_address'):
              lParamAddress = lparam.mem_address
  
          CArgObject = type(ctypes.byref(ctypes.c_int(0)))
          if isinstance(wparam, CArgObject):
              wParamAddress = ctypes.addressof(wparam._obj)
          if isinstance(lparam, CArgObject):
              lParamAddress = ctypes.addressof(lparam._obj)
  
          return win32gui.SendMessage(self.handle, message, wParamAddress, lParamAddress)
  
      # Non PEP-8 alias
      SendMessage = deprecated(send_message)
  
      # -----------------------------------------------------------
      def send_chars(self,
                     chars,
                     with_spaces=True,
                     with_tabs=True,
                     with_newlines=True):
          """
          Silently send a character string to the control in an inactive window
  
          If a virtual key with no corresponding character is encountered
          (e.g. VK_LEFT, VK_DELETE), a KeySequenceError is raised. Consider using
          the method send_keystrokes for such input.
          """
          input_locale_id = ctypes.windll.User32.GetKeyboardLayout(0)
          keys = keyboard.parse_keys(chars, with_spaces, with_tabs, with_newlines)
  
          for key in keys:
              key_info = key.get_key_info()
              flags = key_info[2]
  
              unicode_char = (
                  flags & keyboard.KEYEVENTF_UNICODE ==
                  keyboard.KEYEVENTF_UNICODE)
  
              if unicode_char:
                  _, char = key_info[:2]
                  vk = ctypes.windll.User32.VkKeyScanExW(char, input_locale_id) & 0xFF
                  scan = keyboard.MapVirtualKey(vk, 0)
              else:
                  vk, scan = key_info[:2]
                  char = keyboard.MapVirtualKey(vk, 2)
  
              if char > 0:
                  lparam = 1 << 0 | scan << 16 | (flags & 1) << 24
                  win32api.SendMessage(self.handle, win32con.WM_CHAR, char, lparam)
              else:
                  raise keyboard.KeySequenceError(
                      'no WM_CHAR code for {key}, use method send_keystrokes instead'.
                      format(key=key))
  
      # -----------------------------------------------------------
      def send_keystrokes(self,
                     keystrokes,
                     with_spaces=True,
                     with_tabs=True,
                     with_newlines=True):
          """
          Silently send keystrokes to the control in an inactive window
  
          Parses modifiers Shift(+), Control(^), Menu(%) and Sequences like "{TAB}", "{ENTER}"
          For more information about Sequences and Modifiers navigate to keyboard.py
  
          Due to the fact that each application handles input differently and this method
          is meant to be used on inactive windows, it may work only partially depending
          on the target app. If the window being inactive is not essential, use the robust
          type_keys method.
          """
          user32 = ctypes.windll.User32
          PBYTE256 = ctypes.c_ubyte * 256
  
          win32gui.SendMessage(self.handle, win32con.WM_ACTIVATE,
                               win32con.WA_ACTIVE, 0)
          target_thread_id = user32.GetWindowThreadProcessId(self.handle, None)
          current_thread_id = win32api.GetCurrentThreadId()
          attach_success = user32.AttachThreadInput(target_thread_id, current_thread_id, True) != 0
          if not attach_success:
              warnings.warn('Failed to attach app\'s thread to the current thread\'s message queue',
                            UserWarning, stacklevel=2)
  
          keyboard_state_stack = [PBYTE256()]
          user32.GetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
  
          input_locale_id = ctypes.windll.User32.GetKeyboardLayout(0)
          context_code = 0
  
          keys = keyboard.parse_keys(keystrokes, with_spaces, with_tabs, with_newlines)
          key_combos_present = any([isinstance(k, keyboard.EscapedKeyAction) for k in keys])
          if key_combos_present:
              warnings.warn('Key combinations may or may not work depending on the target app',
                            UserWarning, stacklevel=2)
  
          try:
              for key in keys:
                  vk, scan, flags = key.get_key_info()
  
                  if vk == keyboard.VK_MENU or context_code == 1:
                      down_msg, up_msg = win32con.WM_SYSKEYDOWN, win32con.WM_SYSKEYUP
                  else:
                      down_msg, up_msg = win32con.WM_KEYDOWN, win32con.WM_KEYUP
  
                  repeat = 1
                  shift_state = 0
                  unicode_codepoint = flags & keyboard.KEYEVENTF_UNICODE != 0
                  if unicode_codepoint:
                      char = scan
                      vk_with_flags = user32.VkKeyScanExW(char, input_locale_id)
                      vk = vk_with_flags & 0xFF
                      shift_state = (vk_with_flags & 0xFF00) >> 8
                      scan = keyboard.MapVirtualKey(vk, 0)
  
                  if key.down and vk > 0:
                      new_keyboard_state = copy.deepcopy(keyboard_state_stack[-1])
  
                      new_keyboard_state[vk] |= 128
                      if shift_state & 1 == 1:
                          new_keyboard_state[keyboard.VK_SHIFT] |= 128
                      # NOTE: if there are characters with CTRL or ALT in the shift
                      # state, make sure to add these keys to new_keyboard_state
  
                      keyboard_state_stack.append(new_keyboard_state)
  
                      lparam = (
                          repeat << 0 |
                          scan << 16 |
                          (flags & 1) << 24 |
                          context_code << 29 |
                          0 << 31)
  
                      user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
                      win32api.PostMessage(self.handle, down_msg, vk, lparam)
                      if vk == keyboard.VK_MENU:
                          context_code = 1
  
                      # a delay for keyboard state to take effect
                      time.sleep(0.01)
  
                  if key.up and vk > 0:
                      keyboard_state_stack.pop()
  
                      lparam = (
                          repeat << 0 |
                          scan << 16 |
                          (flags & 1) << 24 |
                          context_code << 29 |
                          1 << 30 |
                          1 << 31)
  
                      win32api.PostMessage(self.handle, up_msg, vk, lparam)
                      user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[-1]))
  
                      if vk == keyboard.VK_MENU:
                          context_code = 0
  
                      # a delay for keyboard state to take effect
                      time.sleep(0.01)
  
          except pywintypes.error as e:
              if e.winerror == 1400:
                  warnings.warn('Application exited before the end of keystrokes',
                                UserWarning, stacklevel=2)
              else:
                  warnings.warn(e.strerror, UserWarning, stacklevel=2)
              user32.SetKeyboardState(ctypes.byref(keyboard_state_stack[0]))
  
          if attach_success:
              user32.AttachThreadInput(target_thread_id, current_thread_id, False)
  
      # -----------------------------------------------------------
      def send_message_timeout(
          self,
          message,
          wparam = 0,
          lparam = 0,
          timeout = None,
          timeoutflags = win32defines.SMTO_NORMAL):
          """
          Send a message to the control and wait for it to return or to timeout
  
          If no timeout is given then a default timeout of .01 of a second will
          be used.
          """
  
          if timeout is None:
              timeout = Timings.sendmessagetimeout_timeout
  
          result = -1
          try:
              (_, result) = win32gui.SendMessageTimeout(
                      int(self.handle),
                      message,
                      wparam,
                      lparam,
                      timeoutflags,
                      int(timeout * 1000)
                      )
          except Exception as exc:
              #import traceback
              #print('____________________________________________________________')
              #print('self.handle =', int(self.handle), ', message =', message,
              #      ', wparam =', wparam, ', lparam =', lparam, ', timeout =', timeout)
              #print('Exception: ', exc)
              #print(traceback.format_exc())
              result = str(exc)
  
          return result #result.value
      # Non PEP-8 alias
      SendMessageTimeout = deprecated(send_message_timeout)
  
      # -----------------------------------------------------------
      def post_message(self, message, wparam = 0, lparam = 0):
          """Post a message to the control message queue and return"""
          return win32functions.PostMessage(self, message, wparam, lparam)
  
      # Non PEP-8 alias
      PostMessage = deprecated(post_message)
  
  #    # -----------------------------------------------------------
  #    def notify_menu_select(self, menu_id):
  #        """Notify the dialog that one of it's menu items was selected
  #
  #        **This method is Deprecated**
  #        """
  #
  #        import warnings
  #        warning_msg = "HwndWrapper.NotifyMenuSelect() is deprecated - " \
  #            "equivalent functionality is being moved to the MenuWrapper class."
  #        warnings.warn(warning_msg, DeprecationWarning)
  #
  #        self.set_focus()
  #
  #        msg = win32defines.WM_COMMAND
  #        return self.send_message_timeout(
  #            msg,
  #            win32functions.MakeLong(0, menu_id), #wparam
  #            )
      # Non PEP-8 alias
      # NotifyMenuSelect = deprecated(notify_menu_select)
  
      # -----------------------------------------------------------
      def notify_parent(self, message, controlID = None):
          """Send the notification message to parent of this control"""
          if controlID is None:
              controlID = self.control_id()
  
          return self.parent().post_message(
              win32defines.WM_COMMAND,
              win32functions.MakeLong(message, controlID),
              self)
      # Non PEP-8 alias
      NotifyParent = deprecated(notify_parent)
  
      # -----------------------------------------------------------
      def __hash__(self):
          """Returns the hash value of the handle"""
          return hash(self.handle)
  
      #-----------------------------------------------------------
      def wait_for_idle(self):
          """Backend specific function to wait for idle state of a thread or a window"""
          win32functions.WaitGuiThreadIdle(self)
  
      # -----------------------------------------------------------
      def click(
          self, button = "left", pressed = "", coords = (0, 0), double = False, absolute = False):
          """
          Simulates a mouse click on the control
  
          This method sends WM_* messages to the control, to do a more
          'realistic' mouse click use click_input() which uses mouse_event() API
          to perform the click.
  
          This method does not require that the control be visible on the screen
          (i.e. it can be hidden beneath another window and it will still work).
          """
          self.verify_actionable()
          self._ensure_enough_privileges('WM_*BUTTONDOWN/UP')
  
          _perform_click(self, button, pressed, coords, double, absolute=absolute)
          return self
      # Non PEP-8 alias
      Click = deprecated(click)
  
      # -----------------------------------------------------------
      def close_click(
          self, button = "left", pressed = "", coords = (0, 0), double = False):
          """
          Perform a click action that should make the window go away
  
          The only difference from click is that there are extra delays
          before and after the click action.
          """
          time.sleep(Timings.before_closeclick_wait)
  
          _perform_click(self, button, pressed, coords, double)
  
          def has_closed():
              closed = not (
                      win32functions.IsWindow(self) or
                      win32functions.IsWindow(self.parent()))
              if not closed:
                  # try closing again
                  try:
                      _perform_click(self, button, pressed, coords, double)
                  except Exception:
                      return True # already closed
              return closed
  
          # Keep waiting until both this control and it's parent
          # are no longer valid controls
          timings.wait_until(
              Timings.closeclick_dialog_close_wait,
              Timings.closeclick_retry,
              has_closed
          )
  
          time.sleep(Timings.after_closeclick_wait)
  
          return self
      # Non PEP-8 alias
      CloseClick = deprecated(close_click)
  
      # -----------------------------------------------------------
      def close_alt_f4(self):
          """Close the window by pressing Alt+F4 keys."""
          time.sleep(Timings.before_closeclick_wait)
          self.type_keys('%{F4}')
          time.sleep(Timings.after_closeclick_wait)
  
          return self
      # Non PEP-8 alias
      CloseAltF4 = deprecated(close_alt_f4)
  
      # -----------------------------------------------------------
      def double_click(
          self, button = "left", pressed = "", coords = (0, 0)):
          """Perform a double click action"""
          _perform_click(self, button, pressed, coords, double = True)
          return self
      # Non PEP-8 alias
      DoubleClick = deprecated(double_click)
  
      # -----------------------------------------------------------
      def right_click(
          self, pressed = "", coords = (0, 0)):
          """Perform a right click action"""
          _perform_click(
              self, "right", "right " + pressed, coords, button_up = False)
          _perform_click(self, "right", pressed, coords, button_down = False)
          return self
      # Non PEP-8 alias
      RightClick = deprecated(right_click)
  
      # -----------------------------------------------------------
      def press_mouse(self, button ="left", coords = (0, 0), pressed =""):
          """Press the mouse button"""
          #flags, click_point = _calc_flags_and_coords(pressed, coords)
  
          _perform_click(self, button, pressed, coords, button_down=True, button_up=False)
          return self
      # Non PEP-8 alias
      PressMouse = deprecated(press_mouse)
  
      # -----------------------------------------------------------
      def release_mouse(self, button ="left", coords = (0, 0), pressed =""):
          """Release the mouse button"""
          #flags, click_point = _calc_flags_and_coords(pressed, coords)
          _perform_click(self, button, pressed, coords, button_down=False, button_up=True)
          return self
      # Non PEP-8 alias
      ReleaseMouse = deprecated(release_mouse)
  
      # -----------------------------------------------------------
      def move_mouse(self, coords = (0, 0), pressed ="", absolute = False):
          """Move the mouse by WM_MOUSEMOVE"""
          if not absolute:
              self.actions.log('Moving mouse to relative (client) coordinates ' + str(coords).replace('\n', ', '))
  
          _perform_click(self, button='move', coords=coords, absolute=absolute, pressed=pressed)
  
          win32functions.WaitGuiThreadIdle(self)
          return self
      # Non PEP-8 alias
      MoveMouse = deprecated(move_mouse)
  
      # -----------------------------------------------------------
      def drag_mouse(self, button ="left",
                     press_coords = (0, 0),
                     release_coords = (0, 0),
                     pressed = ""):
          """Drag the mouse"""
          if isinstance(press_coords, win32structures.POINT):
              press_coords = (press_coords.x, press_coords.y)
  
          if isinstance(release_coords, win32structures.POINT):
              release_coords = (release_coords.x, release_coords.y)
  
          _pressed = pressed
          if not _pressed:
              _pressed = "left"
  
          self.press_mouse(button, press_coords, pressed=pressed)
          for i in range(5):
              self.move_mouse((press_coords[0] + i, press_coords[1]), pressed=_pressed)
              time.sleep(Timings.drag_n_drop_move_mouse_wait)
          self.move_mouse(release_coords, pressed=_pressed)
          time.sleep(Timings.before_drop_wait)
          self.release_mouse(button, release_coords, pressed=pressed)
          time.sleep(Timings.after_drag_n_drop_wait)
          return self
      # Non PEP-8 alias
      DragMouse = deprecated(drag_mouse)
  
      # -----------------------------------------------------------
      def set_window_text(self, text, append = False):
          """Set the text of the window"""
          self.verify_actionable()
  
          if append:
              text = self.window_text() + text
  
          text = ctypes.c_wchar_p(six.text_type(text))
          self.post_message(win32defines.WM_SETTEXT, 0, text)
          win32functions.WaitGuiThreadIdle(self)
  
          self.actions.log('Set text to the ' + self.friendly_class_name() + ': ' + str(text))
          return self
      # Non PEP-8 alias
      SetWindowText = deprecated(set_window_text)
  
      # -----------------------------------------------------------
      def debug_message(self, text):
          """Write some debug text over the window"""
          # don't draw if dialog is not visible
  
          dc = win32functions.CreateDC("DISPLAY", None, None, None )
  
          if not dc:
              raise ctypes.WinError()
  
          rect = self.rectangle()
  
          #ret = win32functions.TextOut(
          #    dc, rect.left, rect.top, six.text_type(text), len(text))
          ret = win32functions.DrawText(
              dc,
              six.text_type(text),
              len(text),
              ctypes.byref(rect),
              win32defines.DT_SINGLELINE)
  
          # delete the Display context that we created
          win32functions.DeleteDC(dc)
  
          if not ret:
              raise ctypes.WinError()
  
          return self
      # Non PEP-8 alias
      DebugMessage = deprecated(debug_message)
  
      # -----------------------------------------------------------
      def set_transparency(self, alpha = 120):
          """Set the window transparency from 0 to 255 by alpha attribute"""
          if not (0 <= alpha <= 255):
              raise ValueError('alpha should be in [0, 255] interval!')
          # TODO: implement SetExStyle method
          win32gui.SetWindowLong(self.handle, win32defines.GWL_EXSTYLE, self.exstyle() | win32con.WS_EX_LAYERED)
          win32gui.SetLayeredWindowAttributes(self.handle, win32api.RGB(0,0,0), alpha, win32con.LWA_ALPHA)
      # Non PEP-8 alias
      SetTransparency = deprecated(set_transparency)
  
      # -----------------------------------------------------------
      def popup_window(self):
          """Return owned enabled Popup window wrapper if shown.
  
          If there is no enabled popups at that time, it returns **self**.
          See MSDN reference:
          https://msdn.microsoft.com/en-us/library/windows/desktop/ms633515.aspx
  
          Please do not use in production code yet - not tested fully
          """
          popup = win32functions.GetWindow(self, win32defines.GW_ENABLEDPOPUP)
  
          return popup
      # Non PEP-8 alias
      PopupWindow = deprecated(popup_window)
  
      # -----------------------------------------------------------
      def owner(self):
          """Return the owner window for the window if it exists
  
          Returns None if there is no owner"""
          owner = win32functions.GetWindow(self, win32defines.GW_OWNER)
          if owner:
              return HwndWrapper(owner)
          else:
              return None
      # Non PEP-8 alias
      Owner = deprecated(owner)
  
      # -----------------------------------------------------------
  #    def context_menu_select(self, path, x = None, y = None):
  #        "TODO context_menu_select Not Implemented"
  #        pass
  #        #raise NotImplementedError(
  #        #    "HwndWrapper.ContextMenuSelect not implemented yet")
  #    # Non PEP-8 alias
  #    ContextMenuSelect = deprecated(context_menu_select)
  
      # -----------------------------------------------------------
      def _menu_handle(self):
          """Simple overridable method to get the menu handle"""
          hMenu = win32gui.GetMenu(self.handle)
          is_main_menu = True
          if not hMenu:
              self._ensure_enough_privileges('MN_GETHMENU')
              hMenu = self.send_message(self.handle, win32defines.MN_GETHMENU);
              is_main_menu = False
          return (hMenu, is_main_menu)
  
      # -----------------------------------------------------------
      def menu(self):
          "Return the menu of the control"
          hMenu, is_main_menu = self._menu_handle()
          if hMenu: # and win32functions.IsMenu(menu_hwnd):
              return Menu(self, hMenu, is_main_menu=is_main_menu)
          return None
      # Non PEP-8 alias
      Menu = deprecated(menu)
  
      # -----------------------------------------------------------
      def menu_item(self, path, exact = False):
          """Return the menu item specified by path
  
          Path can be a string in the form "MenuItem->MenuItem->MenuItem..."
          where each MenuItem is the text of an item at that level of the menu.
          E.g. ::
  
            File->Export->ExportAsPNG
  
          spaces are not important so you could also have written... ::
  
            File -> Export -> Export As PNG
  
          """
          if self.appdata is not None:
              menu_appdata = self.appdata['menu_items']
          else:
              menu_appdata = None
  
          menu = self.menu()
          if menu:
              return self.menu().get_menu_path(path, appdata = menu_appdata, exact=exact)[-1]
  
          raise RuntimeError("There is no menu.")
      # Non PEP-8 alias
      MenuItem = deprecated(menu_item)
  
      # -----------------------------------------------------------
      def menu_items(self):
          """Return the menu items for the dialog
  
          If there are no menu items then return an empty list
          """
          if self.is_dialog() and self.menu():
              #menu_handle = win32functions.GetMenu(self)
              #self.send_message(win32defines.WM_INITMENU, menu_handle)
              return self.menu().get_properties()['menu_items']
  
              #self.send_message(win32defines.WM_INITMENU, menu_handle)
              #return _GetMenuItems(menu_handle, self)
          else:
              return []
      # Non PEP-8 alias
      MenuItems = deprecated(menu_items)
  
  #    # -----------------------------------------------------------
  #    def menu_click(self, path):
  #        "Select the MenuItem specifed in path"
  #
  #        self.verify_actionable()
  #
  #        self.set_focus()
  #
  #        menu = Menu(self, self._menu_handle())
  #
  #        path_items = menu.get_menu_path(path)
  #
  #        for menu_item in path_items:
  #            if not menu_item.is_enabled():
  #                raise MenuItemNotEnabled(
  #                    "MenuItem '%s' is disabled"% menu_item.text())
  #
  #            menu_item.click()
  #
  #        return self
  #    # Non PEP-8 alias
  #    MenuClick = deprecated(menu_click)
  
      # -----------------------------------------------------------
      def menu_select(self, path, exact=False, ):
          """Find a menu item specified by the path
  
          The full path syntax is specified in:
          :py:meth:`.controls.menuwrapper.Menu.get_menu_path`
          """
  
          self.verify_actionable()
  
          self.menu_item(path, exact=exact).select()
      # Non PEP-8 alias
      MenuSelect = deprecated(menu_select)
  
      # -----------------------------------------------------------
      def move_window(
          self,
          x = None,
          y = None,
          width = None,
          height = None,
          repaint = True):
          """Move the window to the new coordinates
  
          * **x** Specifies the new left position of the window.
            Defaults to the current left position of the window.
          * **y** Specifies the new top position of the window.
            Defaults to the current top position of the window.
          * **width** Specifies the new width of the window. Defaults to the
            current width of the window.
          * **height** Specifies the new height of the window. Default to the
            current height of the window.
          * **repaint** Whether the window should be repainted or not.
            Defaults to True
  
          """
  
          cur_rect = self.rectangle()
  
          # if no X is specified - so use current coordinate
          if x is None:
              x = cur_rect.left
          else:
              try:
                  y = x.top
                  width = x.width()
                  height = x.height()
                  x = x.left
              except AttributeError:
                  pass
  
          # if no Y is specified - so use current coordinate
          if y is None:
              y = cur_rect.top
  
          # if no width is specified - so use current width
          if width is None:
              width = cur_rect.width()
  
          # if no height is specified - so use current height
          if height is None:
              height = cur_rect.height()
  
          # ask for the window to be moved
          ret = win32functions.MoveWindow(self, x, y, width, height, repaint)
  
          # check that it worked correctly
          if not ret:
              raise ctypes.WinError()
  
          win32functions.WaitGuiThreadIdle(self)
          time.sleep(Timings.after_movewindow_wait)
      # Non PEP-8 alias
      MoveWindow = deprecated(move_window)
  
      # -----------------------------------------------------------
      def close(self, wait_time = 0):
          """Close the window
  
          Code modified from http://msdn.microsoft.com/msdnmag/issues/02/08/CQA/
  
          """
          window_text = self.window_text()
  
          # tell the window it must close
          self.post_message(win32defines.WM_CLOSE)
  
          #unused var: start = time.time()
          # Keeps trying while
          #    we have not timed out and
          #    window is still a valid handle and
          #    window is still visible
          # any one of these conditions evaluates to false means the window is
          # closed or we have timed out
          def has_closed():
              return not (win32functions.IsWindow(self) and self.is_visible())
  
          if not wait_time:
              wait_time = Timings.closeclick_dialog_close_wait
  
          # Keep waiting until both this control and it's parent
          # are no longer valid controls
          timings.wait_until(
              wait_time,
              Timings.closeclick_retry,
              has_closed
          )
  
          self.actions.log('Closed window "{0}"'.format(window_text))
      # Non PEP-8 alias
      Close = deprecated(close)
  
      # -----------------------------------------------------------
      def maximize(self):
          """Maximize the window"""
          win32functions.ShowWindow(self, win32defines.SW_MAXIMIZE)
          self.actions.log('Maximized window "{0}"'.format(self.window_text()))
          return self
      # Non PEP-8 alias
      Maximize = deprecated(maximize)
  
      # -----------------------------------------------------------
      def minimize(self):
          """Minimize the window"""
          win32functions.ShowWindow(self, win32defines.SW_MINIMIZE)
          # TODO: wait while window is minimized
          self.actions.log('Minimized window "{0}"'.format(self.window_text()))
          return self
      # Non PEP-8 alias
      Minimize = deprecated(minimize)
  
      # -----------------------------------------------------------
      def restore(self):
          """Restore the window to its previous state (normal or maximized)"""
          win32functions.ShowWindow(self, win32defines.SW_RESTORE)
          self.actions.log('Restored window "{0}"'.format(self.window_text()))
          return self
      # Non PEP-8 alias
      Restore = deprecated(restore)
  
      # -----------------------------------------------------------
      def get_show_state(self):
          """Get the show state and Maximized/minimzed/restored state
  
          Returns a value that is a union of the following
  
          * SW_HIDE the window is hidden.
          * SW_MAXIMIZE the window is maximized
          * SW_MINIMIZE the window is minimized
          * SW_RESTORE the window is in the 'restored'
            state (neither minimized or maximized)
          * SW_SHOW The window is not hidden
          """
  
          wp = win32structures.WINDOWPLACEMENT()
          wp.lenght = ctypes.sizeof(wp)
  
          ret = win32functions.GetWindowPlacement(self, ctypes.byref(wp))
  
          if not ret:
              raise ctypes.WinError()
  
          return wp.showCmd
      # Non PEP-8 alias
      GetShowState = deprecated(get_show_state)
  
      # -----------------------------------------------------------
      def is_minimized(self):
          """Indicate whether the window is minimized or not"""
          return self.get_show_state() == win32defines.SW_SHOWMINIMIZED
  
      # -----------------------------------------------------------
      def is_maximized(self):
          """Indicate whether the window is maximized or not"""
          return self.get_show_state() == win32defines.SW_SHOWMAXIMIZED
  
      # -----------------------------------------------------------
      def is_normal(self):
          """Indicate whether the window is normal (i.e. not minimized and not maximized)"""
          return self.get_show_state() == win32defines.SW_SHOWNORMAL
  
      # -----------------------------------------------------------
      def get_active(self):
          """Return a handle to the active window within the process"""
          gui_info = win32structures.GUITHREADINFO()
          gui_info.cbSize = ctypes.sizeof(gui_info)
          window_thread_id, _ = win32process.GetWindowThreadProcessId(int(self.handle))
          ret = win32functions.GetGUIThreadInfo(
              window_thread_id,
              ctypes.byref(gui_info))
  
          if not ret:
              raise ctypes.WinError()
  
          hwndActive = gui_info.hwndActive
          if hwndActive:
              return HwndWrapper(hwndActive)
          else:
              return None
      # Non PEP-8 alias
      GetActive = deprecated(get_active)
  
      # -----------------------------------------------------------
      def get_focus(self):
          """Return the control in the process of this window that has the Focus
          """
  
          gui_info = win32structures.GUITHREADINFO()
          gui_info.cbSize = ctypes.sizeof(gui_info)
          window_thread_id, _ = win32process.GetWindowThreadProcessId(self.handle)
          ret = win32functions.GetGUIThreadInfo(
              window_thread_id,
              ctypes.byref(gui_info))
  
          if not ret:
              return None
  
          return HwndWrapper(gui_info.hwndFocus)
      # Non PEP-8 alias
      GetFocus = deprecated(get_focus)
  
      # -----------------------------------------------------------
      def set_focus(self):
          """
          Set the focus to this control.
  
          Bring the window to the foreground first.
          The system restricts which processes can set the foreground window
          (https://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).aspx)
          so the mouse cursor is removed from the screen to prevent any side effects.
          """
          # "steal the focus" if there is another active window
          # otherwise it is already into the foreground and no action required
          if not self.has_focus():
              # Notice that we need to move the mouse out of the screen
              # but we don't use the built-in methods of the class:
              # self.mouse_move doesn't do the job well even with absolute=True
              # self.move_mouse_input can't be used as it calls click_input->set_focus
              mouse.move(coords=(-10000, 500))  # move the mouse out of screen to the left
  
              # change active window
              if self.is_minimized():
                  if self.was_maximized():
                      self.maximize()
                  else:
                      self.restore()
              else:
                  win32gui.ShowWindow(self.handle, win32con.SW_SHOW)
              win32gui.SetForegroundWindow(self.handle)
  
              # make sure that we are idle before returning
              win32functions.WaitGuiThreadIdle(self)
  
              # only sleep if we had to change something!
              time.sleep(Timings.after_setfocus_wait)
  
          return self
      # Non PEP-8 alias
      SetFocus = deprecated(set_focus)
  
      def has_focus(self):
          """Check the window is in focus (foreground)"""
          return self.handle == win32gui.GetForegroundWindow()
  
      def has_keyboard_focus(self):
          """Check the keyboard focus on this control."""
          control_thread = win32process.GetWindowThreadProcessId(self.handle)[0]
          win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 1)
          focused = win32gui.GetFocus()
          win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 0)
  
          win32functions.WaitGuiThreadIdle(self)
  
          return self.handle == focused
  
      def set_keyboard_focus(self):
          """Set the keyboard focus to this control."""
          control_thread = win32process.GetWindowThreadProcessId(self.handle)[0]
          win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 1)
          win32gui.SetFocus(self.handle)
          win32process.AttachThreadInput(control_thread, win32api.GetCurrentThreadId(), 0)
  
          win32functions.WaitGuiThreadIdle(self)
  
          time.sleep(Timings.after_setfocus_wait)
          return self
  
      # -----------------------------------------------------------
      def set_application_data(self, appdata):
          """Application data is data from a previous run of the software
  
          It is essential for running scripts written for one spoke language
          on a different spoken language
          """
          self.appdata = appdata
  
  
      _scroll_types = {"left": {
              "line" : win32defines.SB_LINELEFT,
              "page" : win32defines.SB_PAGELEFT,
              "end" :  win32defines.SB_LEFT,
              },
          "right": {
                  "line" : win32defines.SB_LINERIGHT,
                  "page" : win32defines.SB_PAGERIGHT,
                  "end" :  win32defines.SB_RIGHT,
              },
          "up": {
                  "line" : win32defines.SB_LINEUP,
                  "page" : win32defines.SB_PAGEUP,
                  "end" :  win32defines.SB_TOP,
              },
          "down": {
                  "line" : win32defines.SB_LINEDOWN,
                  "page" : win32defines.SB_PAGEDOWN,
                  "end" :  win32defines.SB_BOTTOM,
              },
          }
      # Non PEP-8 alias
      SetApplicationData = deprecated(set_application_data)
  
      # -----------------------------------------------------------
      def scroll(self, direction, amount, count = 1, retry_interval = None):
          """Ask the control to scroll itself
  
          **direction** can be any of "up", "down", "left", "right"
          **amount** can be one of "line", "page", "end"
          **count** (optional) the number of times to scroll
          """
          self._ensure_enough_privileges('WM_HSCROLL/WM_VSCROLL')
  
          # check which message we want to send
          if direction.lower() in ("left", "right"):
              message = win32defines.WM_HSCROLL
          elif direction.lower() in ("up", "down"):
              message = win32defines.WM_VSCROLL
  
          # the constant that matches direction, and how much
          try:
              scroll_type = \
                  self._scroll_types[direction.lower()][amount.lower()]
          except KeyError:
              raise ValueError("""Wrong arguments:
                  direction can be any of "up", "down", "left", "right"
                  amount can be any of "line", "page", "end"
                  """)
  
          # Scroll as often as we have been asked to
          if retry_interval is None:
              retry_interval = Timings.scroll_step_wait
          while count > 0:
              self.send_message(message, scroll_type)
              time.sleep(retry_interval)
              count -= 1
  
          return self
      # Non PEP-8 alias
      Scroll = deprecated(scroll)
  
      # -----------------------------------------------------------
      def get_toolbar(self):
          """Get the first child toolbar if it exists"""
  
          for child in self.children():
              if child.__class__.__name__ == 'ToolbarWrapper':
                  return child
  
          return None
      # Non PEP-8 alias
      GetToolbar = deprecated(get_toolbar)
  
      # Non PEP-8 aliases for BaseWrapper methods
      # We keep them for the backward compatibility in legacy scripts
      ClickInput = deprecated(BaseWrapper.click_input)
      DoubleClickInput = deprecated(BaseWrapper.double_click_input)
      RightClickInput = deprecated(BaseWrapper.right_click_input)
      VerifyVisible = deprecated(BaseWrapper.verify_visible)
      _NeedsImageProp = deprecated(BaseWrapper._needs_image_prop, deprecated_name='_NeedsImageProp')
      FriendlyClassName = deprecated(BaseWrapper.friendly_class_name)
      Class = deprecated(BaseWrapper.class_name, deprecated_name='Class')
      WindowText = deprecated(BaseWrapper.window_text)
      ControlID = deprecated(BaseWrapper.control_id, deprecated_name='ControlID')
      IsVisible = deprecated(BaseWrapper.is_visible)
      IsEnabled = deprecated(BaseWrapper.is_enabled)
      Rectangle = deprecated(BaseWrapper.rectangle)
      ClientToScreen = deprecated(BaseWrapper.client_to_screen)
      ProcessID = deprecated(BaseWrapper.process_id, deprecated_name='ProcessID')
      IsDialog = deprecated(BaseWrapper.is_dialog)
      Parent = deprecated(BaseWrapper.parent)
      TopLevelParent = deprecated(BaseWrapper.top_level_parent)
      Texts = deprecated(BaseWrapper.texts)
      Children = deprecated(BaseWrapper.children)
      CaptureAsImage = deprecated(BaseWrapper.capture_as_image)
      GetProperties = deprecated(BaseWrapper.get_properties)
      DrawOutline = deprecated(BaseWrapper.draw_outline)
      IsChild = deprecated(BaseWrapper.is_child)
      VerifyActionable = deprecated(BaseWrapper.verify_actionable)
      VerifyEnabled = deprecated(BaseWrapper.verify_enabled)
      PressMouseInput = deprecated(BaseWrapper.press_mouse_input)
      ReleaseMouseInput = deprecated(BaseWrapper.release_mouse_input)
      MoveMouseInput = deprecated(BaseWrapper.move_mouse_input)
      DragMouseInput = deprecated(BaseWrapper.drag_mouse_input)
      WheelMouseInput = deprecated(BaseWrapper.wheel_mouse_input)
      TypeKeys = deprecated(BaseWrapper.type_keys)
  
  
  #====================================================================
  # the main reason for this is just to make sure that
  # a Dialog is a known class - and we don't need to take
  # an image of it (as an unknown control class)
  class DialogWrapper(HwndWrapper):
  
      """Wrap a dialog"""
  
      friendlyclassname = "Dialog"
      #windowclasses = ["#32770", ]
      can_be_label = True
  
      #-----------------------------------------------------------
      def __init__(self, hwnd):
          """Initialize the DialogWrapper
  
          The only extra functionality here is to modify self.friendlyclassname
          to make it "Dialog" if the class is "#32770" otherwise to leave it
          the same as the window class.
          """
          HwndWrapper.__init__(self, hwnd)
  
          if self.class_name() == "#32770":
              self.friendlyclassname = "Dialog"
          else:
              self.friendlyclassname = self.class_name()
  
      #-----------------------------------------------------------
      def run_tests(self, tests_to_run = None, ref_controls = None):
          """Run the tests on dialog"""
          # the tests package is imported only when running unittests
          from .. import tests
  
          # get all the controls
          controls = [self] + self.children()
  
          # add the reference controls
          if ref_controls is not None:
              matched_flags = controlproperties.SetReferenceControls(
                  controls, ref_controls)
  
              # todo: allow some checking of how well the controls matched
              # matched_flags says how well they matched
              # 1 = same number of controls
              # 2 = ID's matched
              # 4 = control classes matched
              # i.e. 1 + 2 + 4 = perfect match
  
          return tests.run_tests(controls, tests_to_run)
      # Non PEP-8 alias
      RunTests = deprecated(run_tests)
  
      #-----------------------------------------------------------
      def write_to_xml(self, filename):
          """Write the dialog an XML file (requires elementtree)"""
          controls = [self] + self.children()
          props = [ctrl.get_properties() for ctrl in controls]
  
          from .. import xml_helpers
          xml_helpers.WriteDialogToFile(filename, props)
      # Non PEP-8 alias
      WriteToXML = deprecated(write_to_xml)
  
      #-----------------------------------------------------------
      def client_area_rect(self):
          """Return the client area rectangle
  
          From MSDN:
          The client area of a control is the bounds of the control, minus the
          nonclient elements such as scroll bars, borders, title bars, and
          menus.
          """
          rect = win32structures.RECT(self.rectangle())
          self.send_message(win32defines.WM_NCCALCSIZE, 0, ctypes.byref(rect))
          return rect
      # Non PEP-8 alias
      ClientAreaRect = deprecated(client_area_rect)
  
      #-----------------------------------------------------------
      def hide_from_taskbar(self):
          """Hide the dialog from the Windows taskbar"""
          win32functions.ShowWindow(self, win32defines.SW_HIDE)
          win32functions.SetWindowLongPtr(self, win32defines.GWL_EXSTYLE, self.exstyle() | win32defines.WS_EX_TOOLWINDOW)
          win32functions.ShowWindow(self, win32defines.SW_SHOW)
      # Non PEP-8 alias
      HideFromTaskbar = deprecated(hide_from_taskbar)
  
      #-----------------------------------------------------------
      def show_in_taskbar(self):
          """Show the dialog in the Windows taskbar"""
          win32functions.ShowWindow(self, win32defines.SW_HIDE)
          win32functions.SetWindowLongPtr(self, win32defines.GWL_EXSTYLE,
              self.exstyle() | win32defines.WS_EX_APPWINDOW)
          win32functions.ShowWindow(self, win32defines.SW_SHOW)
      # Non PEP-8 alias
      ShowInTaskbar = deprecated(show_in_taskbar)
  
      #-----------------------------------------------------------
      def is_in_taskbar(self):
          """Check whether the dialog is shown in the Windows taskbar
  
          Thanks to David Heffernan for the idea:
          http://stackoverflow.com/questions/30933219/hide-window-from-taskbar-without-using-ws-ex-toolwindow
          A window is represented in the taskbar if:
          It has no owner and it does not have the WS_EX_TOOLWINDOW extended style,
          or it has the WS_EX_APPWINDOW extended style.
          """
          return self.has_exstyle(win32defines.WS_EX_APPWINDOW) or \
                 (self.owner() is None and not self.has_exstyle(win32defines.WS_EX_TOOLWINDOW))
      # Non PEP-8 alias
      IsInTaskbar = deprecated(is_in_taskbar)
  
      #-----------------------------------------------------------
      def force_close(self):
          """Close the dialog forcefully using WM_QUERYENDSESSION and return the result
  
          Window has let us know that it doesn't want to die - so we abort
          this means that the app is not hung - but knows it doesn't want
          to close yet - e.g. it is asking the user if they want to save.
          """
          self.send_message_timeout(
              win32defines.WM_QUERYENDSESSION,
              timeout = .5,
              timeoutflags = (win32defines.SMTO_ABORTIFHUNG)) # |
          #win32defines.SMTO_NOTIMEOUTIFNOTHUNG)) # |
          #win32defines.SMTO_BLOCK)
  
          # get a handle we can wait on
          _, pid = win32process.GetWindowThreadProcessId(int(self.handle))
          try:
              process_wait_handle = win32api.OpenProcess(
                  win32con.SYNCHRONIZE | win32con.PROCESS_TERMINATE,
                  0,
                  pid)
          except win32gui.error:
              return True # already closed
  
          result = win32event.WaitForSingleObject(
              process_wait_handle,
              int(Timings.after_windowclose_timeout * 1000))
  
          return result != win32con.WAIT_TIMEOUT
  
  #    #-----------------------------------------------------------
  #    def read_controls_from_xml(self, filename):
  #        from pywinauto import xml_helpers
  #        [controlproperties.ControlProps(ctrl) for
  #            ctrl in xml_helpers.ReadPropertiesFromFile(handle)]
  #    # Non PEP-8 alias
  #    ReadControlsFromXML = deprecated(read_controls_from_xml)
  
  #    #-----------------------------------------------------------
  #    def add_reference(self, reference):
  #
  #        if len(self.children() != len(reference)):
  #            raise "different number of reference controls"
  #
  #        for i, ctrl in enumerate(reference):
  #        # loop over each of the controls
  #        # and set the reference
  #            if isinstance(ctrl, dict):
  #                ctrl = CtrlProps(ctrl)
  #
  #            self.
  #            if ctrl.class_name() != self.children()[i+1].class_name():
  #                print "different classes"
  #    # Non PEP-8 alias
  #    AddReference = deprecated(add_reference)
  
  
  #====================================================================
  def _perform_click(
          ctrl,
          button = "left",
          pressed = "",
          coords = (0, 0),
          double = False,
          button_down = True,
          button_up = True,
          absolute = False,
          ):
      """Low level method for performing click operations"""
      if ctrl is None:
          ctrl = HwndWrapper(win32functions.GetDesktopWindow())
      ctrl.verify_actionable()
      ctrl_text = ctrl.window_text()
      if ctrl_text is None:
          ctrl_text = six.text_type(ctrl_text)
  
      ctrl_friendly_class_name = ctrl.friendly_class_name()
  
      if isinstance(coords, win32structures.RECT):
          coords = coords.mid_point()
      # allow points objects to be passed as the coords
      elif isinstance(coords, win32structures.POINT):
          coords = [coords.x, coords.y]
      else:
          coords = list(coords)
  
      if absolute:
          coords = ctrl.client_to_screen(coords)
  
      # figure out the messages for click/press
      msgs = []
      if not double:
          if button.lower() == 'left':
              if button_down:
                  msgs.append(win32defines.WM_LBUTTONDOWN)
              if button_up:
                  msgs.append(win32defines.WM_LBUTTONUP)
          elif button.lower() == 'middle':
              if button_down:
                  msgs.append(win32defines.WM_MBUTTONDOWN)
              if button_up:
                  msgs.append(win32defines.WM_MBUTTONUP)
          elif button.lower() == 'right':
              if button_down:
                  msgs.append(win32defines.WM_RBUTTONDOWN)
              if button_up:
                  msgs.append(win32defines.WM_RBUTTONUP)
          elif button.lower() == 'move':
              msgs.append(win32defines.WM_MOUSEMOVE)
  
      # figure out the messages for double clicking
      else:
          if button.lower() == 'left':
              msgs = (
                  win32defines.WM_LBUTTONDOWN,
                  win32defines.WM_LBUTTONUP,
                  win32defines.WM_LBUTTONDBLCLK,
                  win32defines.WM_LBUTTONUP)
          elif button.lower() == 'middle':
              msgs = (
                  win32defines.WM_MBUTTONDOWN,
                  win32defines.WM_MBUTTONUP,
                  win32defines.WM_MBUTTONDBLCLK,
                  win32defines.WM_MBUTTONUP)
          elif button.lower() == 'right':
              msgs = (
                  win32defines.WM_RBUTTONDOWN,
                  win32defines.WM_RBUTTONUP,
                  win32defines.WM_RBUTTONDBLCLK,
                  win32defines.WM_RBUTTONUP)
          elif button.lower() == 'move':
              msgs.append(win32defines.WM_MOUSEMOVE)
  
      # figure out the flags and pack coordinates
      flags, click_point = _calc_flags_and_coords(pressed, coords)
  
      #control_thread = win32functions.GetWindowThreadProcessId(ctrl, 0)
      #win32functions.AttachThreadInput(win32functions.GetCurrentThreadId(), control_thread, win32defines.TRUE)
      # TODO: check return value of AttachThreadInput properly
  
      # send each message
      for msg in msgs:
          win32functions.PostMessage(ctrl, msg, win32structures.WPARAM(flags), win32structures.LPARAM(click_point))
          #ctrl.post_message(msg, flags, click_point)
          #flags = 0
  
          time.sleep(Timings.sendmessagetimeout_timeout)
  
          # wait until the thread can accept another message
          win32functions.WaitGuiThreadIdle(ctrl)
  
      # detach the Python process with the process that self is in
      #win32functions.AttachThreadInput(win32functions.GetCurrentThreadId(), control_thread, win32defines.FALSE)
      # TODO: check return value of AttachThreadInput properly
  
      # wait a certain(short) time after the click
      time.sleep(Timings.after_click_wait)
  
      if button.lower() == 'move':
          message = 'Moved mouse over ' + ctrl_friendly_class_name + ' "' + ctrl_text + \
                    '" to screen point ' + str(tuple(coords)) + ' by WM_MOUSEMOVE'
      else:
          message = 'Clicked ' + ctrl_friendly_class_name + ' "' + ctrl_text + \
                    '" by ' + str(button) + ' button event ' + str(tuple(coords))
          if double:
              message = 'Double-c' + message[1:]
      ActionLogger().log(message)
  
  _mouse_flags = {
      "left": win32defines.MK_LBUTTON,
      "right": win32defines.MK_RBUTTON,
      "middle": win32defines.MK_MBUTTON,
      "shift": win32defines.MK_SHIFT,
      "control": win32defines.MK_CONTROL,
  }
  
  #====================================================================
  def _calc_flags_and_coords(pressed, coords):
      """Calculate the flags to use and the coordinates for mouse actions"""
      flags = 0
  
      for key in pressed.split():
          flags |= _mouse_flags[key.lower()]
  
      click_point = win32functions.MakeLong(coords[1], coords[0])
  
      return flags, click_point
  
  #====================================================================
  class _DummyControl(dict):
  
      """A subclass of dict so that we can assign attributes"""
      pass
  
  #====================================================================
  def get_dialog_props_from_handle(hwnd):
      """Get the properties of all the controls as a list of dictionaries"""
      # wrap the dialog handle and start a new list for the
      # controls on the dialog
      try:
          controls = [hwnd, ]
          controls.extend(hwnd.children())
      except AttributeError:
          controls = [HwndWrapper(hwnd), ]
  
          # add all the children of the dialog
          controls.extend(controls[0].children())
  
      props = []
  
      # Add each control to the properties for this dialog
      for ctrl in controls:
          # Get properties for each control and wrap them in
          # _DummyControl so that we can assign handle
          ctrl_props = _DummyControl(ctrl.get_properties())
  
          # assign the handle
          ctrl_props.handle = ctrl.handle
  
          # offset the rectangle from the dialog rectangle
          ctrl_props['rectangle'] -= controls[0].rectangle()
  
          props.append(ctrl_props)
  
      return props
  # Non PEP-8 alias
  GetDialogPropsFromHandle = deprecated(get_dialog_props_from_handle)
  
  
  backend.register('win32', HwndElementInfo, HwndWrapper)
  backend.registry.backends['win32'].dialog_class = DialogWrapper
  backend.activate('win32') # default
  