Class: WinWindow

Inherits:
Object
  • Object
show all
Defined in:
lib/winwindow.rb,
lib/winwindow/ext.rb

Overview

extensions to the language which are external to what the WinWindow library itself does

Defined Under Namespace

Modules: AttachLib, Waiter, WinGDI, WinKernel, WinUser Classes: Error, MatchError, NotExistsError, SystemError, WaiterError

Constant Summary collapse

Enumerator =

:nodoc:

Object.const_defined?('Enumerator') ? ::Enumerator : Enumerable::Enumerator
Types =
AttachLib::Types
WM_CLOSE =
0x0010
WM_KEYDOWN =
0x0100
WM_KEYUP =
0x0101
WM_CHAR =
0x0102
BM_CLICK =
0x00F5
WM_COMMAND =
0x0111
WM_SETTEXT =
0x000C
WM_GETTEXT =
0x000D
WM_GETTEXTLENGTH =
0xE
GW_HWNDFIRST =

– GetWindows constants

0
GW_HWNDLAST =
1
GW_HWNDNEXT =
2
GW_HWNDPREV =
3
GW_OWNER =
4
GW_CHILD =
5
GW_ENABLEDPOPUP =
6
GW_MAX =
6
GA_PARENT =

– GetAncestor constants

1
GA_ROOT =
2
GA_ROOTOWNER =
3
SW_HIDE =
0
SW_SHOWNORMAL =

Hides the window and activates another window.

1
SW_SHOWMINIMIZED =

Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.

2
SW_SHOWMAXIMIZED =

Activates the window and displays it as a minimized window.

3
SW_MAXIMIZE =

Activates the window and displays it as a maximized window.

3
SW_SHOWNOACTIVATE =

Maximizes the specified window. – there seems to be no distinct SW_MAXIMIZE (but there is a distinct SW_MINIMIZE), just the same as SW_SHOWMAXIMIZED some references define SW_MAXIMIZE as 11, which seems to just be wrong; that is correctly SW_FORCEMINIMIZE

4
SW_SHOW =

Displays a window in its most recent size and position. This value is similar to SW_SHOWNORMAL, except the window is not actived.

5
SW_MINIMIZE =

Activates the window and displays it in its current size and position.

6
SW_SHOWMINNOACTIVE =

Minimizes the specified window and activates the next top-level window in the Z order.

7
SW_SHOWNA =

Displays the window as a minimized window. This value is similar to SW_SHOWMINIMIZED, except the window is not activated.

8
SW_RESTORE =

Displays the window in its current size and position. This value is similar to SW_SHOW, except the window is not activated.

9
SW_SHOWDEFAULT =

Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when restoring a minimized window.

10
SW_FORCEMINIMIZE =

Sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application.

11
WIN_TRUE =

Windows 2000/XP: Minimizes a window, even if the thread that owns the window is not responding. This flag should only be used when minimizing windows from a different thread.

-1
WIN_FALSE =
0
LSFW_LOCK =

:stopdoc:

1
LSFW_UNLOCK =
2
VK_MENU =

:stopdoc:

0x12
KEYEVENTF_KEYDOWN =
0x0
KEYEVENTF_KEYUP =
0x2
SRCCOPY =

:stopdoc:

0xCC0020
DIB_RGB_COLORS =
0x0
GMEM_FIXED =
0x0
All =

Enumerable object that iterates over every available window

May raise a WinWindow::SystemError from WinWindow.each_window

Enumerator.new(WinWindow, :each_window)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hwnd) ⇒ WinWindow

creates a WinWindow from a given hWnd handle (integer)

raises ArgumentError if the hWnd is not an Integer greater than 0

Raises:

  • (ArgumentError)


397
398
399
400
# File 'lib/winwindow.rb', line 397

def initialize(hwnd)
  raise ArgumentError, "hwnd must be an integer greater than 0; got #{hwnd.inspect} (#{hwnd.class})" unless hwnd.is_a?(Integer) && hwnd > 0
  @hwnd=hwnd
end

Instance Attribute Details

#hwndObject (readonly)

handle to the window - a positive integer. (properly, this is a pointer, but we deal with it as a number.)



392
393
394
# File 'lib/winwindow.rb', line 392

def hwnd
  @hwnd
end

Class Method Details

.desktop_windowObject

Returns a WinWindow representing the desktop window. The desktop window covers the entire screen. The desktop window is the area on top of which other windows are painted.

msdn.microsoft.com/en-us/library/ms633504%28VS.85%29.aspx



1356
1357
1358
1359
1360
1361
1362
1363
# File 'lib/winwindow.rb', line 1356

def self.desktop_window
  hwnd=WinUser.GetDesktopWindow
  if hwnd == 0
    nil
  else
    self.new(hwnd)
  end
end

.each_windowObject

Iterates over every window yielding a WinWindow object.

use WinWindow::All if you want an Enumerable object.

Raises a WinWindow::SystemError if a System Error occurs.

msdn.microsoft.com/en-us/library/ms633497.aspx

For System Error Codes see msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx



1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
# File 'lib/winwindow.rb', line 1253

def self.each_window # :yields: win_window
  enum_windows_callback= WinUser.window_enum_callback do |hwnd,lparam|
    yield WinWindow.new(hwnd)
    WIN_TRUE
  end
  begin
    ret=WinUser.EnumWindows(enum_windows_callback, nil)
  ensure
    WinUser.remove_window_enum_callback(enum_windows_callback)
  end
  if ret==WIN_FALSE
    system_error "EnumWindows"
  end
  nil
end

.find_all_by_text(text) ⇒ Object

returns all WinWindow objects found whose text matches what is given

May raise a WinWindow::SystemError from WinWindow.each_window



1286
1287
1288
1289
1290
# File 'lib/winwindow.rb', line 1286

def self.find_all_by_text(text)
  WinWindow::All.select do |window|
    text===window.text # use triple-equals so regexps try to match, strings see if equal 
  end
end

.find_first_by_text(text) ⇒ Object

returns the first window found whose text matches what is given

May raise a WinWindow::SystemError from WinWindow.each_window



1277
1278
1279
1280
1281
# File 'lib/winwindow.rb', line 1277

def self.find_first_by_text(text)
  WinWindow::All.detect do |window|
    text===window.text # use triple-equals so regexps try to match, strings see if equal 
  end
end

.find_only_by_text(text) ⇒ Object

returns the only window matching the given text. raises a WinWindow::MatchError if more than one window matching given text is found, so that you can be sure you are returned the right one (because it’s the only one)

behavior is slightly more complex than that - if multiple windows match the given text, but are all in one heirarchy (all parents/children of each other), then this returns the highest one in the heirarchy.

if there are multiple windows with titles that match which are all in a parent/child relationship with each other, this will not error and will return the innermost child whose text matches.

May also raise a WinWindow::SystemError from WinWindow.each_window



1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
# File 'lib/winwindow.rb', line 1305

def self.find_only_by_text(text)
  matched=WinWindow::All.select do |window|
    text===window.text
  end
#    matched.reject! do |win|          # reject win where
#      matched.any? do |other_win|     # exists any other_win 
#        parent=other_win.parent
#        win_is_parent=false
#        while parent && !win_is_parent
#          win_is_parent ||= win==parent
#          parent=parent.parent
#        end
#        win_is_parent                  # such that win is parent of other_win
#      end
#    end
  matched.reject! do |win|           # reject any win where
    matched.any? do |other_win|      # any other_win
      parent=win.parent
      other_is_parent=false
      while parent && !other_is_parent
        other_is_parent ||= other_win==parent
        parent=parent.parent
      end
      other_is_parent                 # is its parent
    end
  end

  if matched.size != 1
    raise MatchError, "Found #{matched.size} windows matching #{text.inspect}; there should be one"
  else
    return matched.first
  end
end

.foreground_windowObject

Returns a WinWindow representing the current foreground window (the window with which the user is currently working).

msdn.microsoft.com/en-us/library/ms633505%28VS.85%29.aspx



1343
1344
1345
1346
1347
1348
1349
1350
# File 'lib/winwindow.rb', line 1343

def self.foreground_window
  hwnd=WinUser.GetForegroundWindow
  if hwnd == 0
    nil
  else
    self.new(hwnd)
  end
end

.handle_options(given_options, default_options, other_allowed_keys = []) ⇒ Object

takes given options and default options, and optionally a list of additional allowed keys not specified in default options (this is useful when you want to pass options along to another function but don’t want to specify a default that will clobber that function’s default) raises ArgumentError if the given options have an invalid key (defined as one not specified in default options or other_allowed_keys), and sets default values in given options where nothing is set.



10
11
12
13
14
15
16
17
18
19
# File 'lib/winwindow/ext.rb', line 10

def self.handle_options(given_options, default_options, other_allowed_keys=[]) # :nodoc:
  given_options=given_options.dup
  unless (unknown_keys=(given_options.keys-default_options.keys-other_allowed_keys)).empty?
    raise ArgumentError, "Unknown options: #{(given_options.keys-default_options.keys).map(&:inspect).join(', ')}. Known options are #{(default_options.keys+other_allowed_keys).map(&:inspect).join(', ')}"
  end
  (default_options.keys-given_options.keys).each do |key|
    given_options[key]=default_options[key]
  end
  given_options
end

.lock_set_foreground_windowObject

The foreground process can call the #lock_set_foreground_window function to disable calls to the #set_foreground! function.

Disables calls to #set_foreground!

msdn.microsoft.com/en-us/library/ms633532%28VS.85%29.aspx



675
676
677
678
# File 'lib/winwindow.rb', line 675

def self.lock_set_foreground_window
  ret= WinUser.LockSetForegroundWindow(LSFW_LOCK)
  ret != WIN_FALSE # todo: raise system error? 
end

.unlock_set_foreground_windowObject

The foreground process can call the #lock_set_foreground_window function to disable calls to the #set_foreground! function.

Enables calls to #set_foreground!

msdn.microsoft.com/en-us/library/ms633532%28VS.85%29.aspx



685
686
687
688
# File 'lib/winwindow.rb', line 685

def self.unlock_set_foreground_window
  ret= WinUser.LockSetForegroundWindow(LSFW_UNLOCK)
  ret != WIN_FALSE # todo: raise system error? 
end

Instance Method Details

#ancestor_parentObject

Retrieves the parent window. This does not include the owner, as it does with #parent

msdn.microsoft.com/en-us/library/ms633502(VS.85).aspx



494
495
496
497
# File 'lib/winwindow.rb', line 494

def ancestor_parent
  ret_hwnd=WinUser.GetAncestor(hwnd, GA_PARENT)
  @ancestor_parent= ret_hwnd > 0 ? self.class.new(ret_hwnd) : nil
end

#ancestor_rootObject

Retrieves the root window by walking the chain of parent windows.

msdn.microsoft.com/en-us/library/ms633502(VS.85).aspx



502
503
504
505
# File 'lib/winwindow.rb', line 502

def ancestor_root
  ret_hwnd=WinUser.GetAncestor(hwnd, GA_ROOT)
  @ancestor_root= ret_hwnd > 0 ? self.class.new(ret_hwnd) : nil
end

#ancestor_root_ownerObject

Retrieves the owned root window by walking the chain of parent and owner windows returned by GetParent.

msdn.microsoft.com/en-us/library/ms633502(VS.85).aspx



511
512
513
514
# File 'lib/winwindow.rb', line 511

def ancestor_root_owner
  ret_hwnd=WinUser.GetAncestor(hwnd, GA_ROOTOWNER)
  @ancestor_root_owner= ret_hwnd > 0 ? self.class.new(ret_hwnd) : nil
end

#bring_to_top!Object

brings the window to the top of the Z order. If the window is a top-level window, it is activated. If the window is a child window, the top-level parent window associated with the child window is activated.

msdn.microsoft.com/en-us/library/ms632673(VS.85).aspx



738
739
740
741
# File 'lib/winwindow.rb', line 738

def bring_to_top!
  ret=WinUser.BringWindowToTop(hwnd)
  ret != WIN_FALSE
end

#capture_to_bmp_blob(options = {}) ⇒ Object

captures this window to a bitmap image (a screenshot).

Returns the bitmap as represented by a blob (a string) of bitmap data, including the BITMAPFILEHEADER, BITMAPINFOHEADER, and data. This can be written directly to a file (though if you want that, #capture_to_bmp_file is probably what you want), or passed to ImageMagick, or whatever you like.

takes an options hash. see the documentation on #capture_to_bmp_structs for what options are accepted.



1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
# File 'lib/winwindow.rb', line 1058

def capture_to_bmp_blob(options={})
  capture_to_bmp_structs(options).map do |struct|
    if struct.is_a?(FFI::Pointer)
      ptr=struct
      size=ptr.size
    else
      ptr=struct.to_ptr
      size=struct.class.real_size
    end
    ptr.get_bytes(0, size)
  end.join("")
end

#capture_to_bmp_file(filename, options = {}) ⇒ Object

captures this window to a bitmap image (a screenshot).

stores the bitmap to a filename specified in the first argument.

takes an options hash. see the documentation on #capture_to_bmp_structs for what options are accepted.



1077
1078
1079
1080
1081
# File 'lib/winwindow.rb', line 1077

def capture_to_bmp_file(filename, options={})
  File.open(filename, 'wb') do |file|
    file.write(capture_to_bmp_blob(options))
  end
end

#capture_to_bmp_structs(options = {}) ⇒ Object

Creates a bitmap image of this window (a screenshot).

Returns the bitmap as represented by three FFI objects: a BITMAPFILEHEADER, a BITMAPINFOHEADER, and a pointer to actual bitmap data.

See also #capture_to_bmp_blob and #capture_to_bmp_file - probably more useful to the user than this method.

takes an options hash:

  • :dc => what device context to use

    • :client - captures the client area, which excludes window trimmings like title bar, resize bars, etc.

    • :window (default) - capturse the window area, including window trimmings.

  • :set_foreground => whether to try to set this to be the foreground

    • true - calls to #set_foreground!

    • false - doesn’t call to any functions to set this to be the foreground

    • :really (default) - calls to #really_set_foreground!. this is the default because really being in the foreground is rather important when taking a screenshot.



968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
# File 'lib/winwindow.rb', line 968

def capture_to_bmp_structs(options={})
  options=handle_options(options, :dc => :window, :set_foreground => :really)
  case options[:set_foreground]
  when :really
    really_set_foreground!
  when true
    set_foreground!
  when false,nil
  else
    raise ArgumentError, ":set_foreground option is invalid. expected values are :really, true, or false/nil. received #{options[:set_foreground]} (#{options[:set_foreground].class})"
  end
  if options[:set_foreground]
    # if setting foreground, sleep a tick - sometimes it still hasn't show up even when it is 
    # the foreground window; sometimes it's still only partway-drawn 
    sleep 0.2 
  end
  case options[:dc]
  when :client
    rect=self.client_rect
    dc=WinUser.GetDC(hwnd) || system_error("GetDC")
  when :window
    rect=self.window_rect
    dc=WinUser.GetWindowDC(hwnd) || system_error("GetWindowDC")
  else
    raise ArgumentError, ":dc option is invalid. expected values are :client or :window; received #{options[:dc]} (#{options[:dc].class})"
  end
  width=rect[:right]-rect[:left]
  height=rect[:bottom]-rect[:top]
  begin
    dc_mem = WinGDI.CreateCompatibleDC(dc) || system_error("CreateCompatibleDC")
    begin
      bmp = WinGDI.CreateCompatibleBitmap(dc, width, height) || system_error("CreateCompatibleBitmap")
      begin
        WinGDI.SelectObject(dc_mem, bmp) || system_error("SelectObject")
        WinGDI.BitBlt(dc_mem, 0, 0, width, height, dc, 0, 0, SRCCOPY) || system_error("BitBlt")
        
        bytes_per_pixel=3
        
        bmp_info=WinGDI::BITMAPINFOHEADER.new
        { :Size => WinGDI::BITMAPINFOHEADER.real_size, # 40
          :Width => width,
          :Height => height,
          :Planes => 1,
          :BitCount => bytes_per_pixel*8,
          :Compression => 0,
          :SizeImage => 0,
          :XPelsPerMeter => 0,
          :YPelsPerMeter => 0,
          :ClrUsed => 0,
          :ClrImportant => 0,
        }.each_pair do |key,val|
          bmp_info[key]=val
        end
        bmp_row_size=width*bytes_per_pixel
        bmp_row_size+=bmp_row_size%4 # row size must be a multiple of 4 (size of a dword)
        bmp_size=bmp_row_size*height
        
        bits=FFI::MemoryPointer.new(1, bmp_size)
        
        WinGDI.GetDIBits(dc_mem, bmp, 0, height, bits, bmp_info, DIB_RGB_COLORS) || system_error("GetDIBits")
        
        bmp_file_header=WinGDI::BITMAPFILEHEADER.new
        { :Type => 'BM'.unpack('S').first, # must be 'BM'
          :Size => WinGDI::BITMAPFILEHEADER.real_size + WinGDI::BITMAPINFOHEADER.real_size + bmp_size,
          :Reserved1 => 0,
          :Reserved2 => 0,
          :OffBits => WinGDI::BITMAPFILEHEADER.real_size + WinGDI::BITMAPINFOHEADER.real_size
        }.each_pair do |key,val|
          bmp_file_header[key]=val
        end
        return [bmp_file_header, bmp_info, bits]
      ensure
        WinGDI.DeleteObject(bmp)
      end
    ensure
      WinGDI.DeleteDC(dc_mem)
    end
  ensure
    WinUser.ReleaseDC(hwnd, dc)
  end
end

#child_button(button_text) ⇒ Object

returns a WinWindow that is a child of this that matches the given button_text (Regexp or #to_s-able) or nil if no such child exists.

“&” is stripped when matching so don’t include it. String comparison is case-insensitive.

May raise a WinWindow::SystemError from #each_child



1216
1217
1218
1219
1220
# File 'lib/winwindow.rb', line 1216

def child_button(button_text)
  children.detect do |child|
    child.class_name=='Button' && button_text.is_a?(Regexp) ? child.text.tr('&', '') =~ button_text : child.text.tr('&', '').downcase==button_text.to_s.tr('&', '').downcase
  end
end

#child_control_with_preceding_label(preceding_label_text, options = {}) ⇒ Object

Finds a child of this window which follows a label with the given text.

Options:

  • :control_class_name is the class name of the control you are looking for. Defaults to nil, which accepts any class name.

  • :label_class_name is the class name of the label preceding the control you are looking for. Defaults to ‘Static’



1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
# File 'lib/winwindow.rb', line 1229

def child_control_with_preceding_label(preceding_label_text, options={})
  options=handle_options(options, :control_class_name => nil, :label_class_name => "Static")
  
  prev_was_label=false
  control=self.children.detect do |child|
    ret=prev_was_label && (!options[:control_class_name] || child.class_name==options[:control_class_name])
    prev_was_label= child.class_name==options[:label_class_name] && preceding_label_text===child.text
    ret
  end
end

#child_of?(parent) ⇒ Boolean

tests whether a window is a child window or descendant window of a specified parent window. A child window is the direct descendant of a specified parent window if that parent window is in the chain of parent windows; the chain of parent windows leads from the original overlapped or pop-up window to the child window.

msdn.microsoft.com/en-us/library/ms633524(VS.85).aspx

Returns:

  • (Boolean)


556
557
558
559
560
# File 'lib/winwindow.rb', line 556

def child_of?(parent)
  parent_hwnd= parent.is_a?(self.class) ? parent.hwnd : parent
  child=WinUser.IsChild(parent_hwnd, hwnd)
  child!=WIN_FALSE
end

#childrenObject

returns an Enumerable object that can iterate over each child of this window, yielding a WinWindow object

may raise a WinWindow::SystemError from #each_child



1135
1136
1137
# File 'lib/winwindow.rb', line 1135

def children
  Enumerator.new(self, :each_child)
end

#children_recursive(options = {}) ⇒ Object

returns an Enumerable object that can iterate over each child of this window recursively, yielding a WinWindow object for each child.



1162
1163
1164
# File 'lib/winwindow.rb', line 1162

def children_recursive(options={})
  Enumerator.new(self, :recurse_each_child, options)
end

#class_nameObject

retrieves the name of the class to which this window belongs

msdn.microsoft.com/en-us/library/ms633582(VS.85).aspx



576
577
578
579
580
581
# File 'lib/winwindow.rb', line 576

def class_name
  buff_size=256
  buff=" "*buff_size
  len=WinUser.GetClassNameA(hwnd, buff, buff_size)
  @class_name=buff.to_s[0...len]
end

#click!Object

tries to click on this Window (using PostMessage sending BM_CLICK message).

Clicking might not always work! Especially if the window is not focused (frontmost application). The BM_CLICK message might just be ignored, or maybe it will just focus the hwnd but not really click.



910
911
912
# File 'lib/winwindow.rb', line 910

def click!
  WinUser.PostMessageA(hwnd, BM_CLICK, 0, nil)
end

#click_child_button_try_for!(button_text, time, options = {}) ⇒ Object

Give the name of a button, or a Regexp to match it (see #child_button). keeps clicking the button until the button no longer exists, or until the given block is true (ie, not false or nil)

Options:

  • :interval is the length of time in seconds between each attempt (default 0.05)

  • :set_foreground is whether the window should be activated first, since button-clicking is much more likely to fail if the window isn’t focused (default true)

  • :exception is the exception class or instance that will be raised if we can’t click the button (default nil, no exception is raised, the return value indicates success/failure)

Raises ArgumentError if invalid options are given. Raises a WinWindow::NotExistsError if the button doesn’t exist, or if this window doesn’t exist, or a WinWindow::SystemError if a System Error occurs (from #each_child)



1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
# File 'lib/winwindow.rb', line 1194

def click_child_button_try_for!(button_text, time, options={})
  options=handle_options(options, {:set_foreground => true, :exception => nil, :interval => 0.05})
  button=child_button(button_text) || (raise WinWindow::NotExistsError, "Button #{button_text.inspect} not found")
  waiter_options={}
  waiter_options[:condition]=proc{!button.exists? || (block_given? && yield)}
  waiter_options.merge!(options.reject{|k,v| ![:exception, :interval].include?(k)})
  Waiter.try_for(time, waiter_options) do
    if options[:set_foreground]
      show_normal!
      really_set_foreground!
    end
    button.click!
  end
  return waiter_options[:condition].call
end

#client_rectObject

Returns a Rect struct with members left, top, right, and bottom indicating the coordinates of a window’s client area. The client coordinates specify the upper-left and lower-right corners of the client area. Because client coordinates are relative to the upper-left corner of a window’s client area, the coordinates of the upper-left corner are (0,0).

msdn.microsoft.com/en-us/library/ms633503%28VS.85%29.aspx



934
935
936
937
938
939
940
941
942
# File 'lib/winwindow.rb', line 934

def client_rect
  rect=WinUser::Rect.new
  ret=WinUser.GetClientRect(hwnd, rect)
  if ret==WIN_FALSE
    self.class.system_error "GetClientRect"
  else
    rect
  end
end

#close!Object

minimizes this window (but does not destroy it) (why is it called close? I don’t know)

msdn.microsoft.com/en-us/library/ms632678(VS.85).aspx



747
748
749
750
# File 'lib/winwindow.rb', line 747

def close!
  ret=WinUser.CloseWindow(hwnd)
  ret != WIN_FALSE
end

#destroy!Object

destroy! destroys the window. #destroy! sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. #destroy! also destroys the window’s menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).

If the specified window is a parent or owner window, #destroy! automatically destroys the associated child or owned windows when it destroys the parent or owner window. #destroy! first destroys child or owned windows, and then it destroys the parent or owner window. #destroy! also destroys modeless dialog boxes.

msdn.microsoft.com/en-us/library/ms632682(VS.85).aspx



876
877
878
879
# File 'lib/winwindow.rb', line 876

def destroy!
  ret=WinUser.DestroyWindow(hwnd)
  ret != WIN_FALSE
end

#each_childObject

iterates over each child, yielding a WinWindow object.

raises a WinWindow::NotExistsError if the window does not exist, or a WinWindow::SystemError if a System Error errors.

use #children to get an Enumerable object.

msdn.microsoft.com/en-us/library/ms633494(VS.85).aspx

For System Error Codes see msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx



1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
# File 'lib/winwindow.rb', line 1111

def each_child
  raise WinWindow::NotExistsError, "Window does not exist! Cannot enumerate children." unless exists?
  enum_child_windows_callback= WinUser.window_enum_callback do |chwnd, lparam|
    yield WinWindow.new(chwnd)
    WIN_TRUE
  end
  begin
    ret=WinUser.EnumChildWindows(hwnd, enum_child_windows_callback, nil)
  ensure
    WinUser.remove_window_enum_callback(enum_child_windows_callback)
  end
  if ret==0
    self.class.system_error("EnumChildWindows")
    # actually, EnumChildWindows doesn't say anything about return value indicating error encountered.
    # Although EnumWindows does, so it seems sort of safe to assume that would apply here too. 
    # but, maybe not - so, should we raise an error here? 
  end
  nil
end

#enabled_popupObject

The retrieved handle identifies the enabled popup window owned by the specified window (the search uses the first such window found using GW_HWNDNEXT); otherwise, if there are no enabled popup windows, nil is returned.

msdn.microsoft.com/en-us/library/ms633515(VS.85).aspx



478
479
480
481
# File 'lib/winwindow.rb', line 478

def enabled_popup
  popup_hwnd=WinUser.GetWindow(hwnd, GW_ENABLEDPOPUP)
  @enabled_popup= popup_hwnd > 0 && popup_hwnd != self.hwnd ? self.class.new(popup_hwnd) : nil
end

#end_task!(force = false) ⇒ Object

called to forcibly close the window.

the argument force, if true, will force the destruction of the window if an initial attempt fails to gently close the window using WM_CLOSE.

if false, only the close with WM_CLOSE is attempted

msdn.microsoft.com/en-us/library/ms633492(VS.85).aspx



889
890
891
892
# File 'lib/winwindow.rb', line 889

def end_task!(force=false)
  ret=WinUser.EndTask(hwnd, 0, force ? WIN_TRUE : WIN_FALSE)
  ret != WIN_FALSE
end

#eql?(oth) ⇒ Boolean Also known as: ==

true if comparing an object of the same class with the same hwnd (integer)

Returns:

  • (Boolean)


1167
1168
1169
# File 'lib/winwindow.rb', line 1167

def eql?(oth)
  oth.class==self.class && oth.hwnd==self.hwnd
end

#exists?Boolean

determines whether the specified window handle identifies an existing window

msdn.microsoft.com/en-us/library/ms633528(VS.85).aspx

Returns:

  • (Boolean)


612
613
614
615
# File 'lib/winwindow.rb', line 612

def exists?
  ret=WinUser.IsWindow(hwnd)
  ret != WIN_FALSE
end

#force_minimize!Object

Windows 2000/XP: Minimizes the window, even if the thread that owns the window is not responding. This should only be used when minimizing windows from a different thread.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



860
861
862
863
# File 'lib/winwindow.rb', line 860

def force_minimize!
  ret=WinUser.ShowWindow(hwnd, SW_FORCEMINIMIZE)
  ret != WIN_FALSE
end

#foreground?Boolean

returns true if this is the same Window that is returned from WinWindow.foreground_window

Returns:

  • (Boolean)


660
661
662
# File 'lib/winwindow.rb', line 660

def foreground?
  self==self.class.foreground_window
end

#handle_options(*args) ⇒ Object

:nodoc:



21
22
23
# File 'lib/winwindow/ext.rb', line 21

def handle_options(*args) # :nodoc:
  self.class.handle_options(*args)
end

#hashObject

:nodoc:



1172
1173
1174
# File 'lib/winwindow.rb', line 1172

def hash # :nodoc:
  [self.class, self.hwnd].hash
end

#hide!Object

Hides the window and activates another window.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



755
756
757
758
# File 'lib/winwindow.rb', line 755

def hide!
  ret=WinUser.ShowWindow(hwnd, SW_HIDE)
  ret != WIN_FALSE
end

#hung_app?Boolean

determine if Microsoft Windows considers that a specified application is not responding. An application is considered to be not responding if it is not waiting for input, is not in startup processing, and has not called PeekMessage within the internal timeout period of 5 seconds.

msdn.microsoft.com/en-us/library/ms633526.aspx

Returns:

  • (Boolean)


568
569
570
571
# File 'lib/winwindow.rb', line 568

def hung_app?
  hung=WinUser.IsHungAppWindow(hwnd)
  hung != WIN_FALSE
end

#iconic?Boolean Also known as: minimized?

whether the window is minimized (iconic).

msdn.microsoft.com/en-us/library/ms633527(VS.85).aspx

Returns:

  • (Boolean)


628
629
630
631
# File 'lib/winwindow.rb', line 628

def iconic?
  ret=WinUser.IsIconic(hwnd)
  ret != WIN_FALSE
end

#inspectObject



402
403
404
405
406
# File 'lib/winwindow.rb', line 402

def inspect
  retrieve_text
  class_name
  Object.instance_method(:inspect).bind(self).call
end

#last_active_popupObject

determines which pop-up window owned by this window was most recently active

msdn.microsoft.com/en-us/library/ms633507(VS.85).aspx



519
520
521
522
# File 'lib/winwindow.rb', line 519

def last_active_popup
  ret_hwnd=WinUser.GetLastActivePopup(hwnd)
  @last_active_popup= ret_hwnd > 0 ? self.class.new(ret_hwnd) : nil
end

#maximize!Object

Maximizes this window. (note: exact same as show_maximized!)

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



789
790
791
792
# File 'lib/winwindow.rb', line 789

def maximize!
  ret=WinUser.ShowWindow(hwnd, SW_MAXIMIZE)
  ret != WIN_FALSE
end

#minimize!Object

Minimizes this window and activates the next top-level window in the Z order.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



814
815
816
817
# File 'lib/winwindow.rb', line 814

def minimize!
  ret=WinUser.ShowWindow(hwnd, SW_MINIMIZE)
  ret != WIN_FALSE
end

#ownerObject

The retrieved handle identifies the specified window’s owner window, if any.

msdn.microsoft.com/en-us/library/ms633515(VS.85).aspx



486
487
488
489
# File 'lib/winwindow.rb', line 486

def owner
  owner_hwnd=WinUser.GetWindow(hwnd, GW_OWNER)
  @owner= owner_hwnd > 0 ? self.class.new(owner_hwnd) : nil
end

#parentObject

retrieves a handle to this window’s parent or owner

msdn.microsoft.com/en-us/library/ms633510(VS.85).aspx



536
537
538
539
# File 'lib/winwindow.rb', line 536

def parent
  parent_hwnd=WinUser.GetParent(hwnd)
  @parent= parent_hwnd > 0 ? self.class.new(parent_hwnd) : nil
end

#pretty_print(pp) ⇒ Object



408
409
410
411
412
# File 'lib/winwindow.rb', line 408

def pretty_print(pp)
  retrieve_text
  class_name
  pp.pp_object(self)
end

#process_idObject

returns the process identifier that created this window

msdn.microsoft.com/en-us/library/ms633522%28VS.85%29.aspx



603
604
605
606
607
# File 'lib/winwindow.rb', line 603

def process_id
  lpdwProcessId=FFI::MemoryPointer.new(Types[:LPDWORD])
  WinUser.GetWindowThreadProcessId(hwnd, lpdwProcessId)
  lpdwProcessId.get_ulong(0)
end

#real_class_nameObject

retrieves a string that specifies the window type

msdn.microsoft.com/en-us/library/ms633538(VS.85).aspx



586
587
588
589
590
591
# File 'lib/winwindow.rb', line 586

def real_class_name
  buff_size=256
  buff=" "*buff_size
  len=WinUser.RealGetWindowClassA(hwnd, buff, buff_size)
  @real_class_name=buff.to_s[0...len]
end

#really_set_foreground!(options = {}) ⇒ Object

really sets this to be the foreground window.

  • restores the window if it’s iconic.

  • attempts to circumvent a lock disabling calls made by set_foreground!

  • then calls set_foreground!, which should then work with that lock disabled. tries this for a few seconds, checking if it was successful.

if you want it to raise an exception if it can’t set the foreground window, pass :error => true (default is false)



705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
# File 'lib/winwindow.rb', line 705

def really_set_foreground!(options={})
  options=handle_options(options, :error => false)
  try_harder=false
  mapped_vk_menu=WinUser.MapVirtualKeyA(VK_MENU, 0)
  Waiter.try_for(2, :exception => (options[:error] && WinWindow::Error.new("Failed to set foreground window"))) do
    if iconic?
      restore!
    end
    if try_harder
      # Simulate two single ALT keystrokes in order to deactivate lock on SetForeGroundWindow before we call it.
      # See LockSetForegroundWindow, http://msdn.microsoft.com/en-us/library/ms633532(VS.85).aspx
      # also keybd_event, see http://msdn.microsoft.com/en-us/library/ms646304(VS.85).aspx
      #
      # this idea is taken from AutoIt's setforegroundwinex.cpp in SetForegroundWinEx::Activate(HWND hWnd)
      # keybd_event((BYTE)VK_MENU, MapVirtualKey(VK_MENU, 0), 0, 0);
      # keybd_event((BYTE)VK_MENU, MapVirtualKey(VK_MENU, 0), KEYEVENTF_KEYUP, 0);
      2.times do
        ret=WinUser.keybd_event(VK_MENU, mapped_vk_menu, KEYEVENTF_KEYDOWN, nil)
        ret=WinUser.keybd_event(VK_MENU, mapped_vk_menu, KEYEVENTF_KEYUP, nil)
      end
    else
      try_harder=true
    end
    set_foreground!
    foreground?
  end
end

#recurse_each_child(options = {}) ⇒ Object

iterates over each child recursively, yielding a WinWindow object for each child.

raises a WinWindow::NotExistsError if the window does not exist, or a WinWindow::SystemError if a System Error errors.

use #children_recursive to get an Enumerable object.



1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
# File 'lib/winwindow.rb', line 1145

def recurse_each_child(options={})
  options=handle_options(options, :rescue_enum_child_windows => true)
  ycomb do |recurse|
    proc do |win_window|
      yield win_window
      begin
        win_window.each_child do |child_window|
          recurse.call child_window
        end
      rescue SystemError
        raise unless options[:rescue_enum_child_windows] && $!.function=='EnumChildWindows'
      end
    end
  end.call(self)
end

#restore!Object

Activates and displays the window. If the window is minimized or maximized, the system restores it to its original size and position. An application should use this when restoring a minimized window.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



842
843
844
845
# File 'lib/winwindow.rb', line 842

def restore!
  ret=WinUser.ShowWindow(hwnd, SW_RESTORE)
  ret != WIN_FALSE
end

#retrieve_textObject

This is similar to #text that one is GetWindowText(hwnd) this one is SendMessage(hwnd, WM_GETTEXT) differences are documented here: msdn.microsoft.com/en-us/magazine/cc301438.aspx and here: blogs.msdn.com/oldnewthing/archive/2003/08/21/54675.aspx



442
443
444
445
446
447
# File 'lib/winwindow.rb', line 442

def retrieve_text
  buff_size=retrieve_text_length+1
  buff=" "*buff_size
  len= WinUser.SendMessageA(hwnd, WM_GETTEXT, buff_size, buff)
  @text=buff[0...len]
end

#retrieve_text_lengthObject

similar to #text_length; differences between that and this are the same as between #text and #retrieve_text



451
452
453
454
# File 'lib/winwindow.rb', line 451

def retrieve_text_length
  len= WinUser.SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, nil)
  len
end

#send_close!Object

sends notification that the window should close. returns nil (we get no indication of success or failure).

msdn.microsoft.com/en-us/library/ms632617%28VS.85%29.aspx



898
899
900
901
902
903
# File 'lib/winwindow.rb', line 898

def send_close!
  buff_size=0
  buff=""
  len=WinUser.SendMessageA(hwnd, WM_CLOSE, buff_size, buff)
  nil
end

#send_set_text!(text) ⇒ Object

sets text by sending WM_SETTEXT message. this different than #set_text! in the same way that #retrieve_text is different than #text



468
469
470
471
# File 'lib/winwindow.rb', line 468

def send_set_text!(text)
  ret=WinUser.SendMessageA(hwnd, WM_SETTEXT, 0, text.dup)
  nil
end

#set_foreground!Object

puts the thread that created the specified window into the foreground and activates the window. Keyboard input is directed to the window, and various visual cues are changed for the user. The system assigns a slightly higher priority to the thread that created the foreground window than it does to other threads.

If the window was brought to the foreground, the return value is true.

If the window was not brought to the foreground, the return value is false.

msdn.microsoft.com/en-us/library/ms633539(VS.85).aspx



654
655
656
657
# File 'lib/winwindow.rb', line 654

def set_foreground!
  ret= WinUser.SetForegroundWindow(hwnd)
  ret != WIN_FALSE
end

#set_parent!(parent) ⇒ Object

changes the parent window of this child window

msdn.microsoft.com/en-us/library/ms633541(VS.85).aspx



544
545
546
547
548
# File 'lib/winwindow.rb', line 544

def set_parent!(parent)
  parent_hwnd= parent.is_a?(self.class) ? parent.hwnd : parent
  new_parent=WinUser.SetParent(hwnd, parent_hwnd)
  new_parent > 0 ? self.class.new(new_parent) : nil
end

#set_text!(text) ⇒ Object

changes the text of the specified window’s title bar (if it has one). If the specified window is a control, the text of the control is changed. However, #set_text! cannot change the text of a control in another application (see #send_set_text!)

msdn.microsoft.com/en-us/library/ms633546(VS.85).aspx



461
462
463
464
# File 'lib/winwindow.rb', line 461

def set_text!(text)
  set=WinUser.SetWindowTextA(hwnd, text)
  set != WIN_FALSE
end

#show!Object

Activates the window and displays it in its current size and position.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



806
807
808
809
# File 'lib/winwindow.rb', line 806

def show!
  ret=WinUser.ShowWindow(hwnd, SW_SHOW)
  ret != WIN_FALSE
end

#show_default!Object

Sets the show state based on the SW_ value specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



851
852
853
854
# File 'lib/winwindow.rb', line 851

def show_default!
  ret=WinUser.ShowWindow(hwnd, SW_SHOWDEFAULT)
  ret != WIN_FALSE
end

#show_maximized!Object

Activates the window and displays it as a maximized window. (note: exact same as maximize!)

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



781
782
783
784
# File 'lib/winwindow.rb', line 781

def show_maximized!
  ret=WinUser.ShowWindow(hwnd, SW_SHOWMAXIMIZED)
  ret != WIN_FALSE
end

#show_min_no_active!Object

Displays the window as a minimized window. This is similar to show_minimized!, except the window is not activated.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



823
824
825
826
# File 'lib/winwindow.rb', line 823

def show_min_no_active!
  ret=WinUser.ShowWindow(hwnd, SW_SHOWMINNOACTIVE)
  ret != WIN_FALSE
end

#show_minimized!Object

Activates the window and displays it as a minimized window.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



773
774
775
776
# File 'lib/winwindow.rb', line 773

def show_minimized!
  ret=WinUser.ShowWindow(hwnd, SW_SHOWMINIMIZED)
  ret != WIN_FALSE
end

#show_na!Object

Displays the window in its current size and position. This is similar to show!, except the window is not activated.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



832
833
834
835
# File 'lib/winwindow.rb', line 832

def show_na!
  ret=WinUser.ShowWindow(hwnd, SW_SHOWNA)
  ret != WIN_FALSE
end

#show_no_activate!Object

Displays the window in its most recent size and position. This is similar to show_normal!, except the window is not actived.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



798
799
800
801
# File 'lib/winwindow.rb', line 798

def show_no_activate!
  ret=WinUser.ShowWindow(hwnd, SW_SHOWNOACTIVATE)
  ret != WIN_FALSE
end

#show_normal!Object

Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.

msdn.microsoft.com/en-us/library/ms633548(VS.85).aspx



765
766
767
768
# File 'lib/winwindow.rb', line 765

def show_normal!
  ret=WinUser.ShowWindow(hwnd, SW_SHOWNORMAL)
  ret != WIN_FALSE
end

#switch_to!(alt_tab = false) ⇒ Object

switch focus and bring to the foreground

the argument alt_tab, if true, indicates that the window is being switched to using the Alt/Ctl+Tab key sequence. This argument should be false otherwise.

msdn.microsoft.com/en-us/library/ms633553(VS.85).aspx



640
641
642
# File 'lib/winwindow.rb', line 640

def switch_to!(alt_tab=false)
  WinUser.SwitchToThisWindow(hwnd, alt_tab ? WIN_TRUE : WIN_FALSE)
end

#textObject

retrieves the text of this window’s title bar (if it has one). If this is a control, the text of the control is retrieved. However, #text cannot retrieve the text of a control in another application (see #retrieve_text)

msdn.microsoft.com/en-us/library/ms633520(VS.85).aspx



419
420
421
422
423
424
# File 'lib/winwindow.rb', line 419

def text
  buff_size=text_length+1
  buff="\001"*buff_size
  len= WinUser.GetWindowTextA(hwnd, buff, buff_size)
  @text=buff[0...len]
end

#text_lengthObject

length of the window text, see #text

similar to #text, cannot retrieve the text of a control in another application - see #retrieve_text, #retrieve_text_length

msdn.microsoft.com/en-us/library/ms633521(VS.85).aspx



432
433
434
435
# File 'lib/winwindow.rb', line 432

def text_length
  len= WinUser.GetWindowTextLengthA(hwnd)
  len
end

#thread_idObject

returns the identifier of the thread that created the window

msdn.microsoft.com/en-us/library/ms633522%28VS.85%29.aspx



596
597
598
# File 'lib/winwindow.rb', line 596

def thread_id
  WinUser.GetWindowThreadProcessId(hwnd, nil)
end

#top_windowObject

examines the Z order of the child windows associated with self and retrieves a handle to the child window at the top of the Z order

msdn.microsoft.com/en-us/library/ms633514(VS.85).aspx



528
529
530
531
# File 'lib/winwindow.rb', line 528

def top_window
  ret_hwnd= WinUser.GetTopWindow(hwnd)
  @top_window= ret_hwnd > 0 ? self.class.new(ret_hwnd) : nil
end

#visible?Boolean

visibility state of the specified window

msdn.microsoft.com/en-us/library/ms633530(VS.85).aspx

Returns:

  • (Boolean)


620
621
622
623
# File 'lib/winwindow.rb', line 620

def visible?
  ret=WinUser.IsWindowVisible(hwnd)
  ret != WIN_FALSE
end

#window_rectObject

Returns a Rect struct with members left, top, right, and bottom indicating the dimensions of the bounding rectangle of the specified window. The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.

msdn.microsoft.com/en-us/library/ms633519%28VS.85%29.aspx



919
920
921
922
923
924
925
926
927
# File 'lib/winwindow.rb', line 919

def window_rect
  rect=WinUser::Rect.new
  ret=WinUser.GetWindowRect(hwnd, rect)
  if ret==WIN_FALSE
    self.class.system_error "GetWindowRect"
  else
    rect
  end
end