Package winappdbg :: Module window
[hide private]
[frames] | no frames]

Source Code for Module winappdbg.window

  1  #!~/.wine/drive_c/Python25/python.exe 
  2  # -*- coding: utf-8 -*- 
  3   
  4  # Copyright (c) 2009-2014, Mario Vilas 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are met: 
  9  # 
 10  #     * Redistributions of source code must retain the above copyright notice, 
 11  #       this list of conditions and the following disclaimer. 
 12  #     * Redistributions in binary form must reproduce the above copyright 
 13  #       notice,this list of conditions and the following disclaimer in the 
 14  #       documentation and/or other materials provided with the distribution. 
 15  #     * Neither the name of the copyright holder nor the names of its 
 16  #       contributors may be used to endorse or promote products derived from 
 17  #       this software without specific prior written permission. 
 18  # 
 19  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 20  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 21  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 22  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 23  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 24  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 25  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 26  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 27  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 28  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 29  # POSSIBILITY OF SUCH DAMAGE. 
 30   
 31  """ 
 32  Window instrumentation. 
 33   
 34  @group Instrumentation: 
 35      Window 
 36  """ 
 37   
 38  __revision__ = "$Id: window.py 1299 2013-12-20 09:30:55Z qvasimodo $" 
 39   
 40  __all__ = ['Window'] 
 41   
 42  import win32 
 43   
 44  # delayed imports 
 45  Process = None 
 46  Thread  = None 
47 48 #============================================================================== 49 50 # Unlike Process, Thread and Module, there's no container for Window objects. 51 # That's because Window objects don't really store any data besides the handle. 52 53 # XXX TODO 54 # * implement sending fake user input (mouse and keyboard messages) 55 # * maybe implement low-level hooks? (they don't require a dll to be injected) 56 57 # XXX TODO 58 # 59 # Will it be possible to implement window hooks too? That requires a DLL to be 60 # injected in the target process. Perhaps with CPython it could be done easier, 61 # compiling a native extension is the safe bet, but both require having a non 62 # pure Python module, which is something I was trying to avoid so far. 63 # 64 # Another possibility would be to malloc some CC's in the target process and 65 # point the hook callback to it. We'd need to have the remote procedure call 66 # feature first as (I believe) the hook can't be set remotely in this case. 67 68 -class Window (object):
69 """ 70 Interface to an open window in the current desktop. 71 72 @group Properties: 73 get_handle, get_pid, get_tid, 74 get_process, get_thread, 75 set_process, set_thread, 76 get_classname, get_style, get_extended_style, 77 get_text, set_text, 78 get_placement, set_placement, 79 get_screen_rect, get_client_rect, 80 screen_to_client, client_to_screen 81 82 @group State: 83 is_valid, is_visible, is_enabled, is_maximized, is_minimized, is_child, 84 is_zoomed, is_iconic 85 86 @group Navigation: 87 get_parent, get_children, get_root, get_tree, 88 get_child_at 89 90 @group Instrumentation: 91 enable, disable, show, hide, maximize, minimize, restore, move, kill 92 93 @group Low-level access: 94 send, post 95 96 @type hWnd: int 97 @ivar hWnd: Window handle. 98 99 @type dwProcessId: int 100 @ivar dwProcessId: Global ID of the process that owns this window. 101 102 @type dwThreadId: int 103 @ivar dwThreadId: Global ID of the thread that owns this window. 104 105 @type process: L{Process} 106 @ivar process: Process that owns this window. 107 Use the L{get_process} method instead. 108 109 @type thread: L{Thread} 110 @ivar thread: Thread that owns this window. 111 Use the L{get_thread} method instead. 112 113 @type classname: str 114 @ivar classname: Window class name. 115 116 @type text: str 117 @ivar text: Window text (caption). 118 119 @type placement: L{win32.WindowPlacement} 120 @ivar placement: Window placement in the desktop. 121 """ 122
123 - def __init__(self, hWnd = None, process = None, thread = None):
124 """ 125 @type hWnd: int or L{win32.HWND} 126 @param hWnd: Window handle. 127 128 @type process: L{Process} 129 @param process: (Optional) Process that owns this window. 130 131 @type thread: L{Thread} 132 @param thread: (Optional) Thread that owns this window. 133 """ 134 self.hWnd = hWnd 135 self.dwProcessId = None 136 self.dwThreadId = None 137 self.set_process(process) 138 self.set_thread(thread)
139 140 @property
141 - def _as_parameter_(self):
142 """ 143 Compatibility with ctypes. 144 Allows passing transparently a Window object to an API call. 145 """ 146 return self.get_handle()
147
148 - def get_handle(self):
149 """ 150 @rtype: int 151 @return: Window handle. 152 @raise ValueError: No window handle set. 153 """ 154 if self.hWnd is None: 155 raise ValueError("No window handle set!") 156 return self.hWnd
157
158 - def get_pid(self):
159 """ 160 @rtype: int 161 @return: Global ID of the process that owns this window. 162 """ 163 if self.dwProcessId is not None: 164 return self.dwProcessId 165 self.__get_pid_and_tid() 166 return self.dwProcessId
167
168 - def get_tid(self):
169 """ 170 @rtype: int 171 @return: Global ID of the thread that owns this window. 172 """ 173 if self.dwThreadId is not None: 174 return self.dwThreadId 175 self.__get_pid_and_tid() 176 return self.dwThreadId
177
178 - def __get_pid_and_tid(self):
179 "Internally used by get_pid() and get_tid()." 180 self.dwThreadId, self.dwProcessId = \ 181 win32.GetWindowThreadProcessId(self.get_handle())
182
183 - def __load_Process_class(self):
184 global Process # delayed import 185 if Process is None: 186 from process import Process
187
188 - def __load_Thread_class(self):
189 global Thread # delayed import 190 if Thread is None: 191 from thread import Thread
192
193 - def get_process(self):
194 """ 195 @rtype: L{Process} 196 @return: Parent Process object. 197 """ 198 if self.__process is not None: 199 return self.__process 200 self.__load_Process_class() 201 self.__process = Process(self.get_pid()) 202 return self.__process
203
204 - def set_process(self, process = None):
205 """ 206 Manually set the parent process. Use with care! 207 208 @type process: L{Process} 209 @param process: (Optional) Process object. Use C{None} to autodetect. 210 """ 211 if process is None: 212 self.__process = None 213 else: 214 self.__load_Process_class() 215 if not isinstance(process, Process): 216 msg = "Parent process must be a Process instance, " 217 msg += "got %s instead" % type(process) 218 raise TypeError(msg) 219 self.dwProcessId = process.get_pid() 220 self.__process = process
221
222 - def get_thread(self):
223 """ 224 @rtype: L{Thread} 225 @return: Parent Thread object. 226 """ 227 if self.__thread is not None: 228 return self.__thread 229 self.__load_Thread_class() 230 self.__thread = Thread(self.get_tid()) 231 return self.__thread
232
233 - def set_thread(self, thread = None):
234 """ 235 Manually set the thread process. Use with care! 236 237 @type thread: L{Thread} 238 @param thread: (Optional) Thread object. Use C{None} to autodetect. 239 """ 240 if thread is None: 241 self.__thread = None 242 else: 243 self.__load_Thread_class() 244 if not isinstance(thread, Thread): 245 msg = "Parent thread must be a Thread instance, " 246 msg += "got %s instead" % type(thread) 247 raise TypeError(msg) 248 self.dwThreadId = thread.get_tid() 249 self.__thread = thread
250
251 - def __get_window(self, hWnd):
252 """ 253 User internally to get another Window from this one. 254 It'll try to copy the parent Process and Thread references if possible. 255 """ 256 window = Window(hWnd) 257 if window.get_pid() == self.get_pid(): 258 window.set_process( self.get_process() ) 259 if window.get_tid() == self.get_tid(): 260 window.set_thread( self.get_thread() ) 261 return window
262 263 #------------------------------------------------------------------------------ 264
265 - def get_classname(self):
266 """ 267 @rtype: str 268 @return: Window class name. 269 270 @raise WindowsError: An error occured while processing this request. 271 """ 272 return win32.GetClassName( self.get_handle() )
273
274 - def get_style(self):
275 """ 276 @rtype: int 277 @return: Window style mask. 278 279 @raise WindowsError: An error occured while processing this request. 280 """ 281 return win32.GetWindowLongPtr( self.get_handle(), win32.GWL_STYLE )
282
283 - def get_extended_style(self):
284 """ 285 @rtype: int 286 @return: Window extended style mask. 287 288 @raise WindowsError: An error occured while processing this request. 289 """ 290 return win32.GetWindowLongPtr( self.get_handle(), win32.GWL_EXSTYLE )
291
292 - def get_text(self):
293 """ 294 @see: L{set_text} 295 @rtype: str 296 @return: Window text (caption) on success, C{None} on error. 297 """ 298 try: 299 return win32.GetWindowText( self.get_handle() ) 300 except WindowsError: 301 return None
302
303 - def set_text(self, text):
304 """ 305 Set the window text (caption). 306 307 @see: L{get_text} 308 309 @type text: str 310 @param text: New window text. 311 312 @raise WindowsError: An error occured while processing this request. 313 """ 314 win32.SetWindowText( self.get_handle(), text )
315
316 - def get_placement(self):
317 """ 318 Retrieve the window placement in the desktop. 319 320 @see: L{set_placement} 321 322 @rtype: L{win32.WindowPlacement} 323 @return: Window placement in the desktop. 324 325 @raise WindowsError: An error occured while processing this request. 326 """ 327 return win32.GetWindowPlacement( self.get_handle() )
328
329 - def set_placement(self, placement):
330 """ 331 Set the window placement in the desktop. 332 333 @see: L{get_placement} 334 335 @type placement: L{win32.WindowPlacement} 336 @param placement: Window placement in the desktop. 337 338 @raise WindowsError: An error occured while processing this request. 339 """ 340 win32.SetWindowPlacement( self.get_handle(), placement )
341
342 - def get_screen_rect(self):
343 """ 344 Get the window coordinates in the desktop. 345 346 @rtype: L{win32.Rect} 347 @return: Rectangle occupied by the window in the desktop. 348 349 @raise WindowsError: An error occured while processing this request. 350 """ 351 return win32.GetWindowRect( self.get_handle() )
352
353 - def get_client_rect(self):
354 """ 355 Get the window's client area coordinates in the desktop. 356 357 @rtype: L{win32.Rect} 358 @return: Rectangle occupied by the window's client area in the desktop. 359 360 @raise WindowsError: An error occured while processing this request. 361 """ 362 cr = win32.GetClientRect( self.get_handle() ) 363 cr.left, cr.top = self.client_to_screen(cr.left, cr.top) 364 cr.right, cr.bottom = self.client_to_screen(cr.right, cr.bottom) 365 return cr
366 367 # XXX TODO 368 # * properties x, y, width, height 369 # * properties left, top, right, bottom 370 371 process = property(get_process, set_process, doc="") 372 thread = property(get_thread, set_thread, doc="") 373 classname = property(get_classname, doc="") 374 style = property(get_style, doc="") 375 exstyle = property(get_extended_style, doc="") 376 text = property(get_text, set_text, doc="") 377 placement = property(get_placement, set_placement, doc="") 378 379 #------------------------------------------------------------------------------ 380
381 - def client_to_screen(self, x, y):
382 """ 383 Translates window client coordinates to screen coordinates. 384 385 @note: This is a simplified interface to some of the functionality of 386 the L{win32.Point} class. 387 388 @see: {win32.Point.client_to_screen} 389 390 @type x: int 391 @param x: Horizontal coordinate. 392 @type y: int 393 @param y: Vertical coordinate. 394 395 @rtype: tuple( int, int ) 396 @return: Translated coordinates in a tuple (x, y). 397 398 @raise WindowsError: An error occured while processing this request. 399 """ 400 return tuple( win32.ClientToScreen( self.get_handle(), (x, y) ) )
401
402 - def screen_to_client(self, x, y):
403 """ 404 Translates window screen coordinates to client coordinates. 405 406 @note: This is a simplified interface to some of the functionality of 407 the L{win32.Point} class. 408 409 @see: {win32.Point.screen_to_client} 410 411 @type x: int 412 @param x: Horizontal coordinate. 413 @type y: int 414 @param y: Vertical coordinate. 415 416 @rtype: tuple( int, int ) 417 @return: Translated coordinates in a tuple (x, y). 418 419 @raise WindowsError: An error occured while processing this request. 420 """ 421 return tuple( win32.ScreenToClient( self.get_handle(), (x, y) ) )
422 423 #------------------------------------------------------------------------------ 424
425 - def get_parent(self):
426 """ 427 @see: L{get_children} 428 @rtype: L{Window} or None 429 @return: Parent window. Returns C{None} if the window has no parent. 430 @raise WindowsError: An error occured while processing this request. 431 """ 432 hWnd = win32.GetParent( self.get_handle() ) 433 if hWnd: 434 return self.__get_window(hWnd)
435
436 - def get_children(self):
437 """ 438 @see: L{get_parent} 439 @rtype: list( L{Window} ) 440 @return: List of child windows. 441 @raise WindowsError: An error occured while processing this request. 442 """ 443 return [ 444 self.__get_window(hWnd) \ 445 for hWnd in win32.EnumChildWindows( self.get_handle() ) 446 ]
447
448 - def get_tree(self):
449 """ 450 @see: L{get_root} 451 @rtype: dict( L{Window} S{->} dict( ... ) ) 452 @return: Dictionary of dictionaries forming a tree of child windows. 453 @raise WindowsError: An error occured while processing this request. 454 """ 455 subtree = dict() 456 for aWindow in self.get_children(): 457 subtree[ aWindow ] = aWindow.get_tree() 458 return subtree
459
460 - def get_root(self):
461 """ 462 @see: L{get_tree} 463 @rtype: L{Window} 464 @return: If this is a child window, return the top-level window it 465 belongs to. 466 If this window is already a top-level window, returns itself. 467 @raise WindowsError: An error occured while processing this request. 468 """ 469 hWnd = self.get_handle() 470 history = set() 471 hPrevWnd = hWnd 472 while hWnd and hWnd not in history: 473 history.add(hWnd) 474 hPrevWnd = hWnd 475 hWnd = win32.GetParent(hWnd) 476 if hWnd in history: 477 # See: https://docs.google.com/View?id=dfqd62nk_228h28szgz 478 return self 479 if hPrevWnd != self.get_handle(): 480 return self.__get_window(hPrevWnd) 481 return self
482
483 - def get_child_at(self, x, y, bAllowTransparency = True):
484 """ 485 Get the child window located at the given coordinates. If no such 486 window exists an exception is raised. 487 488 @see: L{get_children} 489 490 @type x: int 491 @param x: Horizontal coordinate. 492 493 @type y: int 494 @param y: Vertical coordinate. 495 496 @type bAllowTransparency: bool 497 @param bAllowTransparency: If C{True} transparent areas in windows are 498 ignored, returning the window behind them. If C{False} transparent 499 areas are treated just like any other area. 500 501 @rtype: L{Window} 502 @return: Child window at the requested position, or C{None} if there 503 is no window at those coordinates. 504 """ 505 try: 506 if bAllowTransparency: 507 hWnd = win32.RealChildWindowFromPoint( self.get_handle(), (x, y) ) 508 else: 509 hWnd = win32.ChildWindowFromPoint( self.get_handle(), (x, y) ) 510 if hWnd: 511 return self.__get_window(hWnd) 512 except WindowsError: 513 pass 514 return None
515 516 #------------------------------------------------------------------------------ 517
518 - def is_valid(self):
519 """ 520 @rtype: bool 521 @return: C{True} if the window handle is still valid. 522 """ 523 return win32.IsWindow( self.get_handle() )
524
525 - def is_visible(self):
526 """ 527 @see: {show}, {hide} 528 @rtype: bool 529 @return: C{True} if the window is in a visible state. 530 """ 531 return win32.IsWindowVisible( self.get_handle() )
532
533 - def is_enabled(self):
534 """ 535 @see: {enable}, {disable} 536 @rtype: bool 537 @return: C{True} if the window is in an enabled state. 538 """ 539 return win32.IsWindowEnabled( self.get_handle() )
540
541 - def is_maximized(self):
542 """ 543 @see: L{maximize} 544 @rtype: bool 545 @return: C{True} if the window is maximized. 546 """ 547 return win32.IsZoomed( self.get_handle() )
548
549 - def is_minimized(self):
550 """ 551 @see: L{minimize} 552 @rtype: bool 553 @return: C{True} if the window is minimized. 554 """ 555 return win32.IsIconic( self.get_handle() )
556
557 - def is_child(self):
558 """ 559 @see: L{get_parent} 560 @rtype: bool 561 @return: C{True} if the window is a child window. 562 """ 563 return win32.IsChild( self.get_handle() )
564 565 is_zoomed = is_maximized 566 is_iconic = is_minimized 567 568 #------------------------------------------------------------------------------ 569
570 - def enable(self):
571 """ 572 Enable the user input for the window. 573 574 @see: L{disable} 575 576 @raise WindowsError: An error occured while processing this request. 577 """ 578 win32.EnableWindow( self.get_handle(), True )
579
580 - def disable(self):
581 """ 582 Disable the user input for the window. 583 584 @see: L{enable} 585 586 @raise WindowsError: An error occured while processing this request. 587 """ 588 win32.EnableWindow( self.get_handle(), False )
589
590 - def show(self, bAsync = True):
591 """ 592 Make the window visible. 593 594 @see: L{hide} 595 596 @type bAsync: bool 597 @param bAsync: Perform the request asynchronously. 598 599 @raise WindowsError: An error occured while processing this request. 600 """ 601 if bAsync: 602 win32.ShowWindowAsync( self.get_handle(), win32.SW_SHOW ) 603 else: 604 win32.ShowWindow( self.get_handle(), win32.SW_SHOW )
605
606 - def hide(self, bAsync = True):
607 """ 608 Make the window invisible. 609 610 @see: L{show} 611 612 @type bAsync: bool 613 @param bAsync: Perform the request asynchronously. 614 615 @raise WindowsError: An error occured while processing this request. 616 """ 617 if bAsync: 618 win32.ShowWindowAsync( self.get_handle(), win32.SW_HIDE ) 619 else: 620 win32.ShowWindow( self.get_handle(), win32.SW_HIDE )
621
622 - def maximize(self, bAsync = True):
623 """ 624 Maximize the window. 625 626 @see: L{minimize}, L{restore} 627 628 @type bAsync: bool 629 @param bAsync: Perform the request asynchronously. 630 631 @raise WindowsError: An error occured while processing this request. 632 """ 633 if bAsync: 634 win32.ShowWindowAsync( self.get_handle(), win32.SW_MAXIMIZE ) 635 else: 636 win32.ShowWindow( self.get_handle(), win32.SW_MAXIMIZE )
637
638 - def minimize(self, bAsync = True):
639 """ 640 Minimize the window. 641 642 @see: L{maximize}, L{restore} 643 644 @type bAsync: bool 645 @param bAsync: Perform the request asynchronously. 646 647 @raise WindowsError: An error occured while processing this request. 648 """ 649 if bAsync: 650 win32.ShowWindowAsync( self.get_handle(), win32.SW_MINIMIZE ) 651 else: 652 win32.ShowWindow( self.get_handle(), win32.SW_MINIMIZE )
653
654 - def restore(self, bAsync = True):
655 """ 656 Unmaximize and unminimize the window. 657 658 @see: L{maximize}, L{minimize} 659 660 @type bAsync: bool 661 @param bAsync: Perform the request asynchronously. 662 663 @raise WindowsError: An error occured while processing this request. 664 """ 665 if bAsync: 666 win32.ShowWindowAsync( self.get_handle(), win32.SW_RESTORE ) 667 else: 668 win32.ShowWindow( self.get_handle(), win32.SW_RESTORE )
669
670 - def move(self, x = None, y = None, width = None, height = None, 671 bRepaint = True):
672 """ 673 Moves and/or resizes the window. 674 675 @note: This is request is performed syncronously. 676 677 @type x: int 678 @param x: (Optional) New horizontal coordinate. 679 680 @type y: int 681 @param y: (Optional) New vertical coordinate. 682 683 @type width: int 684 @param width: (Optional) Desired window width. 685 686 @type height: int 687 @param height: (Optional) Desired window height. 688 689 @type bRepaint: bool 690 @param bRepaint: 691 (Optional) C{True} if the window should be redrawn afterwards. 692 693 @raise WindowsError: An error occured while processing this request. 694 """ 695 if None in (x, y, width, height): 696 rect = self.get_screen_rect() 697 if x is None: 698 x = rect.left 699 if y is None: 700 y = rect.top 701 if width is None: 702 width = rect.right - rect.left 703 if height is None: 704 height = rect.bottom - rect.top 705 win32.MoveWindow(self.get_handle(), x, y, width, height, bRepaint)
706
707 - def kill(self):
708 """ 709 Signals the program to quit. 710 711 @note: This is an asyncronous request. 712 713 @raise WindowsError: An error occured while processing this request. 714 """ 715 self.post(win32.WM_QUIT)
716
717 - def send(self, uMsg, wParam = None, lParam = None, dwTimeout = None):
718 """ 719 Send a low-level window message syncronically. 720 721 @type uMsg: int 722 @param uMsg: Message code. 723 724 @param wParam: 725 The type and meaning of this parameter depends on the message. 726 727 @param lParam: 728 The type and meaning of this parameter depends on the message. 729 730 @param dwTimeout: Optional timeout for the operation. 731 Use C{None} to wait indefinitely. 732 733 @rtype: int 734 @return: The meaning of the return value depends on the window message. 735 Typically a value of C{0} means an error occured. You can get the 736 error code by calling L{win32.GetLastError}. 737 """ 738 if dwTimeout is None: 739 return win32.SendMessage(self.get_handle(), uMsg, wParam, lParam) 740 return win32.SendMessageTimeout( 741 self.get_handle(), uMsg, wParam, lParam, 742 win32.SMTO_ABORTIFHUNG | win32.SMTO_ERRORONEXIT, dwTimeout)
743
744 - def post(self, uMsg, wParam = None, lParam = None):
745 """ 746 Post a low-level window message asyncronically. 747 748 @type uMsg: int 749 @param uMsg: Message code. 750 751 @param wParam: 752 The type and meaning of this parameter depends on the message. 753 754 @param lParam: 755 The type and meaning of this parameter depends on the message. 756 757 @raise WindowsError: An error occured while sending the message. 758 """ 759 win32.PostMessage(self.get_handle(), uMsg, wParam, lParam)
760