win 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY +8 -0
- data/VERSION +1 -1
- data/lib/win/gui/window.rb +127 -7
- data/lib/win/library.rb +9 -9
- data/spec/spec_helper.rb +27 -26
- data/spec/win/error_spec.rb +4 -4
- data/spec/win/extensions_spec.rb +8 -8
- data/spec/win/gui/input_spec.rb +2 -2
- data/spec/win/gui/message_spec.rb +4 -4
- data/spec/win/gui/window_spec.rb +146 -30
- data/spec/win/library_spec.rb +18 -18
- metadata +3 -3
data/HISTORY
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.5
|
data/lib/win/gui/window.rb
CHANGED
@@ -43,6 +43,20 @@ module Win
|
|
43
43
|
# flag when minimizing windows from a different thread.
|
44
44
|
SW_FORCEMINIMIZE = 11
|
45
45
|
|
46
|
+
# GetWindow constants:
|
47
|
+
GW_HWNDFIRST = 0
|
48
|
+
GW_HWNDLAST = 1
|
49
|
+
GW_HWNDNEXT = 2
|
50
|
+
GW_HWNDPREV = 3
|
51
|
+
GW_OWNER = 4
|
52
|
+
GW_CHILD = 5
|
53
|
+
GW_ENABLEDPOPUP = 6
|
54
|
+
|
55
|
+
# GetAncestor constants:
|
56
|
+
GA_PARENT = 1
|
57
|
+
GA_ROOT = 2
|
58
|
+
GA_ROOTOWNER = 3
|
59
|
+
|
46
60
|
class << self
|
47
61
|
# Def_block that calls API function expecting EnumWindowsProc callback (EnumWindows, EnumChildWindows, ...).
|
48
62
|
# Default callback pushes all passed handles into Array that is returned if Enum function call was successful.
|
@@ -227,7 +241,7 @@ module Win
|
|
227
241
|
|
228
242
|
##
|
229
243
|
# The FindWindowEx function retrieves a handle to a window whose class name and window name match the specified
|
230
|
-
# strings. The function searches child windows, beginning with the one following the specified child window.
|
244
|
+
# strings. The function searches only child windows, beginning with the one following the specified child window.
|
231
245
|
# This function does not perform a case-sensitive search.
|
232
246
|
#
|
233
247
|
# [*Syntax*] HWND FindWindowEx( HWND hwndParent, HWND hwndChildAfter, LPCTSTR lpszClass, LPCTSTR lpszWindow );
|
@@ -257,7 +271,11 @@ module Win
|
|
257
271
|
# call GetLastError.
|
258
272
|
# ---
|
259
273
|
# *Remarks*:
|
260
|
-
# -
|
274
|
+
# - Only DIRECT children of given parent window being searched, not ALL its the descendants. This behavior is
|
275
|
+
# different from EnumChildWindows which enumerates also non-direct descendants.
|
276
|
+
# - If the lpszWindow parameter is not nil, FindWindowEx calls the GetWindowText function to retrieve the window
|
277
|
+
# name for comparison. For a description of a potential problem that can arise, see the Remarks section of
|
278
|
+
# GetWindowText.
|
261
279
|
# - An application can call this function in the following way.
|
262
280
|
# find_window_ex( nil, nil, MAKEINTATOM(0x8000), nil )
|
263
281
|
# 0x8000 is the atom for a menu class. When an application calls this function, the function checks whether
|
@@ -470,11 +488,8 @@ module Win
|
|
470
488
|
function :GetWindowRect, [:HWND, :pointer], :int,
|
471
489
|
&->(api, handle) {
|
472
490
|
rect = FFI::MemoryPointer.new(:long, 4)
|
473
|
-
#rect.write_array_of_long([0, 0, 0, 0])
|
474
491
|
res = api.call handle, rect
|
475
492
|
res == 0 ? [nil, nil, nil, nil] : rect.read_array_of_long(4) }
|
476
|
-
# weird lambda literal instead of normal block is needed because current version of RDoc
|
477
|
-
# goes crazy if block is attached to meta-definition
|
478
493
|
|
479
494
|
##
|
480
495
|
# EnumWindowsProc is an application-defined callback function that receives top-level window handles
|
@@ -499,8 +514,8 @@ module Win
|
|
499
514
|
|
500
515
|
##
|
501
516
|
# The EnumWindows function enumerates all top-level windows on the screen by passing the handle to
|
502
|
-
#
|
503
|
-
#
|
517
|
+
# each window, in turn, to an application-defined callback function. EnumWindows continues until
|
518
|
+
# the last top-level window is enumerated or the callback function returns FALSE.
|
504
519
|
#
|
505
520
|
# [*Syntax*] BOOL EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam );
|
506
521
|
#
|
@@ -636,7 +651,112 @@ module Win
|
|
636
651
|
#
|
637
652
|
function :GetActiveWindow, [], :HWND, zeronil: true
|
638
653
|
|
654
|
+
##
|
655
|
+
# The GetWindow function retrieves a handle to a window that has the specified relationship (Z-Order or
|
656
|
+
# owner) to the specified window.
|
657
|
+
#
|
658
|
+
# [*Syntax*] HWND GetWindow( HWND hWnd, UINT uCmd );
|
659
|
+
#
|
660
|
+
# hWnd:: [in] Handle to a window. The window handle retrieved is relative to this window, based on the
|
661
|
+
# value of the uCmd parameter.
|
662
|
+
# uCmd:: [in] Specifies the relationship between the specified window and the window whose handle is to
|
663
|
+
# be retrieved. This parameter can be one of the following values.
|
664
|
+
# GW_CHILD - The retrieved handle identifies the child window at the top of the Z order, if the specified
|
665
|
+
# window is a parent window; otherwise, the retrieved handle is NULL. The function examines
|
666
|
+
# only child windows of the specified window. It does not examine descendant windows.
|
667
|
+
# GW_ENABLEDPOPUP - Windows 2000/XP: The retrieved handle identifies the enabled popup window owned by
|
668
|
+
# the specified window (the search uses the first such window found using GW_HWNDNEXT);
|
669
|
+
# otherwise, if there are no enabled popup windows, the retrieved handle is that of the
|
670
|
+
# specified window.
|
671
|
+
# GW_HWNDFIRST - The retrieved handle identifies the window of the same type that is highest in Z order.
|
672
|
+
# If the specified window is a topmost window, the handle identifies the topmost window
|
673
|
+
# that is highest in the Z order. If the specified window is a top-level window, the handle
|
674
|
+
# identifies the top-level window that is highest in the Z order. If the specified window
|
675
|
+
# is a child window, the handle identifies the sibling window that is highest in Z order.
|
676
|
+
# GW_HWNDLAST - The retrieved handle identifies the window of the same type that is lowest in the Z order.
|
677
|
+
# If the specified window is a topmost window, the handle identifies the topmost window that
|
678
|
+
# is lowest in the Z order. If the specified window is a top-level window, the handle
|
679
|
+
# identifies the top-level window that is lowest in the Z order. If the specified window is
|
680
|
+
# a child window, the handle identifies the sibling window that is lowest in the Z order.
|
681
|
+
# GW_HWNDNEXT - The retrieved handle identifies the window below the specified window in the Z order.
|
682
|
+
# If the specified window is a topmost window, the handle identifies the topmost window
|
683
|
+
# below the specified window. If the specified window is a top-level window, the handle
|
684
|
+
# identifies the top-level window below the specified window. If the specified window is
|
685
|
+
# a child window, the handle identifies the sibling window below the specified window.
|
686
|
+
# GW_HWNDPREV - The retrieved handle identifies the window above the specified window in the Z order.
|
687
|
+
# If the specified window is a topmost window, the handle identifies the topmost window
|
688
|
+
# above the specified window. If the specified window is a top-level window, the handle
|
689
|
+
# identifies the top-level window above the specified window. If the specified window is
|
690
|
+
# a child window, the handle identifies the sibling window above the specified window.
|
691
|
+
# GW_OWNER - The retrieved handle identifies the specified window's owner window, if any. For more
|
692
|
+
# information, see Owned Windows.
|
693
|
+
# *Returns*:: If the function succeeds, the return value is a window handle. If no window exists with
|
694
|
+
# the specified relationship to the specified window, the return value is NULL. To get
|
695
|
+
# extended error information, call GetLastError.
|
696
|
+
# ---
|
697
|
+
# *Remarks*:
|
698
|
+
# The EnumChildWindows function is more reliable than calling GetWindow in a loop. An application that
|
699
|
+
# calls GetWindow to perform this task risks being caught in an infinite loop or referencing a handle to
|
700
|
+
# a window that has been destroyed.
|
701
|
+
# Function Information
|
702
|
+
#
|
703
|
+
# ---
|
704
|
+
# <b>Enhanced (snake_case) API: returns nil instead of 0 in case of failure</b>
|
705
|
+
#
|
706
|
+
# :call-seq:
|
707
|
+
# window_handle = get_window(h_wnd, u_cmd)
|
708
|
+
#
|
709
|
+
function :GetWindow, [:HWND, :UINT], :HWND, zeronil: true
|
710
|
+
|
711
|
+
##
|
712
|
+
# The GetParent function retrieves a handle to the specified window's parent OR OWNER.
|
713
|
+
# To retrieve a handle to a specified ancestor, use the GetAncestor function.
|
714
|
+
#
|
715
|
+
# [*Syntax*] HWND GetParent( HWND hWnd );
|
716
|
+
#
|
717
|
+
# hWnd:: [in] Handle to the window whose parent window handle is to be retrieved.
|
718
|
+
#
|
719
|
+
# *Returns*:: If the window is a child window, the return value is a handle to the parent window. If the
|
720
|
+
# window is a top-level window, the return value is a handle to the owner window. If the
|
721
|
+
# window is a top-level unowned window or if the function fails, the return value is NULL.
|
722
|
+
# To get extended error information, call GetLastError. For example, this would determine,
|
723
|
+
# when the function returns NULL, if the function failed or the window was a top-level window.
|
724
|
+
# ---
|
725
|
+
# *Remarks*:
|
726
|
+
# Note that, despite its name, this function can return an owner window instead of a parent window. To
|
727
|
+
# obtain the parent window and not the owner, use GetAncestor with the GA_PARENT flag.
|
728
|
+
#
|
729
|
+
# ---
|
730
|
+
# <b>Enhanced (snake_case) API: returns nil instead of 0 in case of failure</b>
|
731
|
+
#
|
732
|
+
# :call-seq:
|
733
|
+
# parent = get_parent(h_wnd)
|
734
|
+
#
|
735
|
+
function :GetParent, [:HWND], :HWND, zeronil: true
|
736
|
+
|
737
|
+
##
|
738
|
+
# The GetAncestor function retrieves the handle to the ancestor of the specified window.
|
739
|
+
#
|
740
|
+
# [*Syntax*] HWND GetAncestor( HWND hwnd, UINT gaFlags );
|
741
|
+
#
|
742
|
+
# hwnd:: [in] Handle to the window whose ancestor is to be retrieved. If this parameter is the desktop
|
743
|
+
# window, the function returns NULL.
|
744
|
+
# gaFlags:: [in] Specifies the ancestor to be retrieved. This parameter can be one of the following values:
|
745
|
+
# GA_PARENT - Retrieves parent window. Unlike GetParent function, this does NOT include the owner.
|
746
|
+
# GA_ROOT - Retrieves the root window by walking the chain of parent windows.
|
747
|
+
# GA_ROOTOWNER - Retrieves the owned root window by walking the chain of parent and owner windows
|
748
|
+
# returned by GetParent.
|
749
|
+
#
|
750
|
+
# *Returns*:: The return value is the handle to the ancestor window.
|
751
|
+
# ---
|
752
|
+
# <b>Enhanced (snake_case) API: returns nil instead of 0 in case of failure</b>
|
753
|
+
#
|
754
|
+
# :call-seq:
|
755
|
+
# ancestor = get_ancestor(hwnd, ga_flags)
|
756
|
+
#
|
757
|
+
function :GetAncestor, [:HWND, :UINT], :HWND, zeronil: true
|
639
758
|
|
759
|
+
|
640
760
|
# Convenience wrapper methods:
|
641
761
|
|
642
762
|
##
|
data/lib/win/library.rb
CHANGED
@@ -365,8 +365,8 @@ module Win
|
|
365
365
|
|
366
366
|
define_method snake_name, &method_body # define snake_case instance method
|
367
367
|
|
368
|
-
|
369
|
-
|
368
|
+
eigen_class = class << self; self; end # Extracting eigenclass
|
369
|
+
eigen_class.class_eval do
|
370
370
|
define_method snake_name, &method_body # define snake_case class method
|
371
371
|
end
|
372
372
|
end
|
@@ -446,23 +446,23 @@ module Win
|
|
446
446
|
# Hook executed when Win::Library is included into class or module. It extends host class/module
|
447
447
|
# with both FFI::Library methods and Win::Library macro methods like 'function'.
|
448
448
|
#
|
449
|
-
def self.included(
|
450
|
-
|
449
|
+
def self.included(host_class)
|
450
|
+
host_class.extend FFI::Library
|
451
451
|
|
452
452
|
# Extracting host class's eigenclass
|
453
453
|
# :stopdoc:
|
454
|
-
|
454
|
+
eigen_class = class << host_class; self; end # :nodoc:
|
455
455
|
|
456
|
-
|
457
|
-
define_method(:namespace) {
|
456
|
+
eigen_class.class_eval do
|
457
|
+
define_method(:namespace) {host_class} # Defining new class method for host class pointing to itself
|
458
458
|
alias_method :attach_callback, :callback
|
459
459
|
|
460
460
|
include ClassMethods
|
461
461
|
end
|
462
462
|
# :startdoc:
|
463
463
|
|
464
|
-
|
465
|
-
|
464
|
+
host_class.ffi_lib 'user32', 'kernel32' # Default libraries
|
465
|
+
host_class.ffi_convention :stdcall
|
466
466
|
end
|
467
467
|
end
|
468
468
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,7 +4,7 @@ require 'spec'
|
|
4
4
|
require 'spec/autorun'
|
5
5
|
require 'win/gui'
|
6
6
|
|
7
|
-
$debug =
|
7
|
+
$debug = false
|
8
8
|
|
9
9
|
# Customize RSpec with my own extensions
|
10
10
|
module ClassMacros
|
@@ -13,7 +13,6 @@ module ClassMacros
|
|
13
13
|
# spec { use{ function(arg1 = 4, arg2 = 'string') }}
|
14
14
|
def spec &block
|
15
15
|
it description_from(caller[0]), &block # it description_from(*block.source_location), &block
|
16
|
-
#do lambda(&block).should_not raise_error end
|
17
16
|
end
|
18
17
|
|
19
18
|
# reads description line from source file and drops external brackets like its{}, use{}
|
@@ -46,11 +45,11 @@ Spec::Runner.configure do |config|
|
|
46
45
|
config.extend(ClassMacros)
|
47
46
|
config.include(InstanceMacros)
|
48
47
|
|
49
|
-
class << Spec::ExampleGroup
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
48
|
+
# class << Spec::ExampleGroup
|
49
|
+
## def spoc &block
|
50
|
+
## it description_from(caller[0]), &block
|
51
|
+
## end
|
52
|
+
# end
|
54
53
|
end
|
55
54
|
|
56
55
|
# Global test methods
|
@@ -72,17 +71,19 @@ end
|
|
72
71
|
|
73
72
|
module WinTest
|
74
73
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
74
|
+
KEY_DELAY = 0.001
|
75
|
+
IMPOSSIBLE = 'Impossible'
|
76
|
+
CONVERSION_ERROR = /Can.t convert/
|
77
|
+
SLEEP_DELAY = 0.02
|
78
|
+
APP_PATH = File.join(File.dirname(__FILE__), "test_apps/locknote/LockNote.exe" )
|
79
|
+
APP_START = cygwin? ? "cmd /c start `cygpath -w #{APP_PATH}`" : 'start "" "' + APP_PATH + '"'
|
80
|
+
WIN_TITLE = 'LockNote - Steganos LockNote'
|
81
|
+
WIN_RECT = [710, 400, 1210, 800]
|
82
|
+
WIN_CLASS = 'ATL:00434098'
|
83
|
+
STATUSBAR_CLASS = 'msctls_statusbar32'
|
84
|
+
TEXTAREA_CLASS = 'ATL:00434310'
|
85
|
+
DESKTOP_CLASS = '#32769'
|
86
|
+
MENU_CLASS = '#32768'
|
86
87
|
|
87
88
|
def any_handle
|
88
89
|
find_window(nil, nil)
|
@@ -104,14 +105,14 @@ module WinTestApp
|
|
104
105
|
#include Win::Gui::Convenience
|
105
106
|
|
106
107
|
def launch_test_app
|
107
|
-
system
|
108
|
-
sleep
|
108
|
+
system APP_START
|
109
|
+
sleep SLEEP_DELAY until (handle = find_window(nil, WIN_TITLE))
|
109
110
|
|
110
|
-
textarea = find_window_ex(handle, 0,
|
111
|
+
textarea = find_window_ex(handle, 0, TEXTAREA_CLASS, nil)
|
111
112
|
app = "Locknote" # App identifier
|
112
113
|
|
113
|
-
|
114
|
-
|
114
|
+
eigen_class = class << app; self; end # Extracting app's eigenclass
|
115
|
+
eigen_class.class_eval do # Defining singleton methods on app
|
115
116
|
define_method(:handle) {handle}
|
116
117
|
define_method(:textarea) {textarea}
|
117
118
|
end
|
@@ -120,9 +121,9 @@ module WinTestApp
|
|
120
121
|
end
|
121
122
|
|
122
123
|
def close_test_app(app = @launched_test_app)
|
123
|
-
while app && app.respond_to?( :handle) && find_window(nil,
|
124
|
+
while app && app.respond_to?( :handle) && find_window(nil, WIN_TITLE)
|
124
125
|
shut_window app.handle
|
125
|
-
sleep
|
126
|
+
sleep SLEEP_DELAY
|
126
127
|
end
|
127
128
|
@launched_test_app = nil
|
128
129
|
end
|
@@ -132,7 +133,7 @@ module WinTestApp
|
|
132
133
|
app = launch_test_app
|
133
134
|
|
134
135
|
# def app.textarea #define singleton method retrieving app's text area
|
135
|
-
# Window::Window.new find_window_ex(self.handle, 0,
|
136
|
+
# Window::Window.new find_window_ex(self.handle, 0, TEXTAREA_CLASS, nil)
|
136
137
|
# end
|
137
138
|
|
138
139
|
yield app
|
data/spec/win/error_spec.rb
CHANGED
@@ -21,14 +21,14 @@ module WinErrorTest
|
|
21
21
|
spec{ use{ err_message = get_last_error() }}
|
22
22
|
|
23
23
|
it "original api retrieves the calling thread's last-error code value" do
|
24
|
-
find_window(
|
24
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE)
|
25
25
|
GetLastError().should == ERROR_FILE_NOT_FOUND
|
26
26
|
window_text(0)
|
27
27
|
GetLastError().should == ERROR_INVALID_WINDOW_HANDLE
|
28
28
|
end
|
29
29
|
|
30
30
|
it "enhanced api retrieves the message corresponding to last error code" do
|
31
|
-
find_window(
|
31
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE)
|
32
32
|
get_last_error.should == "The system cannot find the file specified."
|
33
33
|
window_text(0)
|
34
34
|
get_last_error.should == "Invalid window handle."
|
@@ -40,7 +40,7 @@ module WinErrorTest
|
|
40
40
|
spec{ use{ message = format_message(sys_flags, source=nil, message_id=0, language_id=0, :int, 0) }}
|
41
41
|
|
42
42
|
it "original api formats a message string - system message" do
|
43
|
-
find_window(
|
43
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE)
|
44
44
|
message_id = GetLastError()
|
45
45
|
buf = buffer()
|
46
46
|
num_chars = FormatMessage(sys_flags, nil, message_id, dw_language_id=0, buf, buf.size, :int, 0)
|
@@ -48,7 +48,7 @@ module WinErrorTest
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it "snake_case api Formats a message string - system message" do
|
51
|
-
find_window(
|
51
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE)
|
52
52
|
message = format_message(sys_flags, nil, dw_message_id=GetLastError())
|
53
53
|
message.should == "The system cannot find the file specified."
|
54
54
|
end
|
data/spec/win/extensions_spec.rb
CHANGED
@@ -53,20 +53,20 @@ module WinTest
|
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'raises error if char is not implemented punctuation' do
|
56
|
-
('!'..'/').each {|char| lambda {char.to_vkeys}.should raise_error
|
57
|
-
(':'..'@').each {|char| lambda {char.to_vkeys}.should raise_error
|
58
|
-
('['..'`').each {|char| lambda {char.to_vkeys}.should raise_error
|
59
|
-
('{'..'~').each {|char| lambda {char.to_vkeys}.should raise_error
|
56
|
+
('!'..'/').each {|char| lambda {char.to_vkeys}.should raise_error CONVERSION_ERROR }
|
57
|
+
(':'..'@').each {|char| lambda {char.to_vkeys}.should raise_error CONVERSION_ERROR }
|
58
|
+
('['..'`').each {|char| lambda {char.to_vkeys}.should raise_error CONVERSION_ERROR }
|
59
|
+
('{'..'~').each {|char| lambda {char.to_vkeys}.should raise_error CONVERSION_ERROR }
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'raises error if char is non-printable or non-ascii' do
|
63
|
-
lambda {1.chr.to_vkeys}.should raise_error
|
64
|
-
lambda {230.chr.to_vkeys}.should raise_error
|
63
|
+
lambda {1.chr.to_vkeys}.should raise_error CONVERSION_ERROR
|
64
|
+
lambda {230.chr.to_vkeys}.should raise_error CONVERSION_ERROR
|
65
65
|
end
|
66
66
|
|
67
67
|
it 'raises error if string is multi-char' do
|
68
|
-
lambda {'hello'.to_vkeys}.should raise_error
|
69
|
-
lambda {'23'.to_vkeys}.should raise_error
|
68
|
+
lambda {'hello'.to_vkeys}.should raise_error CONVERSION_ERROR
|
69
|
+
lambda {'23'.to_vkeys}.should raise_error CONVERSION_ERROR
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
data/spec/win/gui/input_spec.rb
CHANGED
@@ -17,9 +17,9 @@ module WinWindowTest
|
|
17
17
|
text = '12 34'
|
18
18
|
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
19
19
|
keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
|
20
|
-
sleep
|
20
|
+
sleep KEY_DELAY
|
21
21
|
keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
|
22
|
-
sleep
|
22
|
+
sleep KEY_DELAY
|
23
23
|
end
|
24
24
|
text(app.textarea).should =~ Regexp.new(text)
|
25
25
|
5.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
|
@@ -52,7 +52,7 @@ module WinGuiMessageTest
|
|
52
52
|
it 'places (posts) a message in the message queue associated with the thread that created the specified window' do
|
53
53
|
app = launch_test_app
|
54
54
|
post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil).should == true
|
55
|
-
sleep
|
55
|
+
sleep SLEEP_DELAY
|
56
56
|
window?(app.handle).should == false
|
57
57
|
end
|
58
58
|
|
@@ -80,7 +80,7 @@ module WinGuiMessageTest
|
|
80
80
|
buffer.get_bytes(0, num_chars).should =~ /Welcome to Steganos LockNote/
|
81
81
|
|
82
82
|
send_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil)
|
83
|
-
sleep
|
83
|
+
sleep SLEEP_DELAY # delay to allow window close
|
84
84
|
window?(app.handle).should == false
|
85
85
|
end
|
86
86
|
end # describe '#send_message'
|
@@ -104,7 +104,7 @@ module WinGuiMessageTest
|
|
104
104
|
@data.should == nil
|
105
105
|
@result.should == nil
|
106
106
|
|
107
|
-
sleep
|
107
|
+
sleep SLEEP_DELAY # small delay to allow message delivery
|
108
108
|
peek_message # dispatching sent message (even though there is nothing in queue)
|
109
109
|
|
110
110
|
@handle.should == @app.handle
|
@@ -118,7 +118,7 @@ module WinGuiMessageTest
|
|
118
118
|
sent.should == true
|
119
119
|
@data.should == nil
|
120
120
|
|
121
|
-
sleep
|
121
|
+
sleep SLEEP_DELAY # small delay to allow message delivery
|
122
122
|
peek_message # dispatching sent message (even though there is nothing in queue)
|
123
123
|
|
124
124
|
@data.should == 0
|
data/spec/win/gui/window_spec.rb
CHANGED
@@ -135,16 +135,16 @@ module WinWindowTest
|
|
135
135
|
|
136
136
|
it 'returns either Integer Window handle or nil' do
|
137
137
|
find_window(nil, nil).should be_a_kind_of Integer
|
138
|
-
find_window(
|
138
|
+
find_window(IMPOSSIBLE, nil).should == nil
|
139
139
|
end
|
140
140
|
|
141
141
|
it 'returns nil if Window is not found' do
|
142
|
-
find_window(
|
143
|
-
find_window(nil,
|
144
|
-
find_window(
|
145
|
-
find_window_w(
|
146
|
-
find_window_w(nil,
|
147
|
-
find_window_w(
|
142
|
+
find_window(IMPOSSIBLE, nil).should == nil
|
143
|
+
find_window(nil, IMPOSSIBLE).should == nil
|
144
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE).should == nil
|
145
|
+
find_window_w(IMPOSSIBLE, nil).should == nil
|
146
|
+
find_window_w(nil, IMPOSSIBLE).should == nil
|
147
|
+
find_window_w(IMPOSSIBLE, IMPOSSIBLE).should == nil
|
148
148
|
end
|
149
149
|
|
150
150
|
it 'finds at least one window if both args are nils' do
|
@@ -154,10 +154,10 @@ module WinWindowTest
|
|
154
154
|
|
155
155
|
it 'finds top-level window by window class or title' do
|
156
156
|
test_app do |app|
|
157
|
-
find_window(
|
158
|
-
find_window(nil,
|
159
|
-
find_window_w(
|
160
|
-
find_window_w(nil,
|
157
|
+
find_window(WIN_CLASS, nil).should == app.handle
|
158
|
+
find_window(nil, WIN_TITLE).should == app.handle
|
159
|
+
find_window_w(WIN_CLASS.to_w, nil).should == app.handle
|
160
|
+
find_window_w(nil, WIN_TITLE.to_w).should == app.handle
|
161
161
|
end
|
162
162
|
end
|
163
163
|
end
|
@@ -168,13 +168,13 @@ module WinWindowTest
|
|
168
168
|
|
169
169
|
it 'returns nil if wrong control is given' do
|
170
170
|
parent_handle = any_handle
|
171
|
-
find_window_ex(parent_handle, 0,
|
172
|
-
find_window_ex(parent_handle, 0, nil,
|
171
|
+
find_window_ex(parent_handle, 0, IMPOSSIBLE, nil).should == nil
|
172
|
+
find_window_ex(parent_handle, 0, nil, IMPOSSIBLE).should == nil
|
173
173
|
end
|
174
174
|
|
175
175
|
it 'finds child window/control by class' do
|
176
176
|
test_app do |app|
|
177
|
-
ta_handle = find_window_ex(app.handle, 0,
|
177
|
+
ta_handle = find_window_ex(app.handle, 0, TEXTAREA_CLASS, nil)
|
178
178
|
ta_handle.should_not == nil
|
179
179
|
ta_handle.should == app.textarea
|
180
180
|
end
|
@@ -252,10 +252,10 @@ module WinWindowTest
|
|
252
252
|
|
253
253
|
it 'returns correct window text' do
|
254
254
|
test_app do |app|
|
255
|
-
get_window_text(app.handle).should ==
|
256
|
-
get_window_text_w(app.handle).should ==
|
257
|
-
window_text(app.handle).should ==
|
258
|
-
window_text_w(app.handle).should ==
|
255
|
+
get_window_text(app.handle).should == WIN_TITLE
|
256
|
+
get_window_text_w(app.handle).should == WIN_TITLE
|
257
|
+
window_text(app.handle).should == WIN_TITLE
|
258
|
+
window_text_w(app.handle).should == WIN_TITLE
|
259
259
|
end
|
260
260
|
end
|
261
261
|
end
|
@@ -272,10 +272,10 @@ module WinWindowTest
|
|
272
272
|
|
273
273
|
it 'returns correct window class name' do
|
274
274
|
test_app do |app|
|
275
|
-
get_class_name(app.handle).should ==
|
276
|
-
class_name(app.handle).should ==
|
277
|
-
class_name_w(app.handle).should ==
|
278
|
-
get_class_name_w(app.handle).should ==
|
275
|
+
get_class_name(app.handle).should == WIN_CLASS
|
276
|
+
class_name(app.handle).should == WIN_CLASS
|
277
|
+
class_name_w(app.handle).should == WIN_CLASS #!!!!!!!!!!! nil?
|
278
|
+
get_class_name_w(app.handle).should == WIN_CLASS #!!!!!! nil?
|
279
279
|
end
|
280
280
|
end
|
281
281
|
end
|
@@ -310,7 +310,7 @@ module WinWindowTest
|
|
310
310
|
|
311
311
|
it 'returns window`s border rectangle' do
|
312
312
|
test_app do |app|
|
313
|
-
get_window_rect(app.handle).should ==
|
313
|
+
get_window_rect(app.handle).should == WIN_RECT
|
314
314
|
end
|
315
315
|
end
|
316
316
|
end
|
@@ -399,12 +399,128 @@ module WinWindowTest
|
|
399
399
|
end
|
400
400
|
end # describe 'destroy_window'
|
401
401
|
|
402
|
+
|
402
403
|
end # context 'ensuring test app closes'
|
403
404
|
|
404
405
|
context 'with single test app' do
|
405
406
|
before(:all){@app = launch_test_app}
|
406
407
|
after(:all){close_test_app}
|
407
408
|
|
409
|
+
describe "#get_parent" do
|
410
|
+
spec{ use{ parent = GetParent(any_handle) }}
|
411
|
+
spec{ use{ parent = get_parent(any_handle) }}
|
412
|
+
|
413
|
+
it "retrieves a handle to the specified window's parent or owner." do
|
414
|
+
child = find_window_ex(@app.handle, 0, nil, nil)
|
415
|
+
parent1 = GetParent(child)
|
416
|
+
parent2 = get_parent(child)
|
417
|
+
parent1.should == parent2
|
418
|
+
parent1.should == @app.handle
|
419
|
+
end
|
420
|
+
|
421
|
+
it "returns 0/nil if the specified window has no parent or owner." do
|
422
|
+
GetParent(@app.handle).should == 0
|
423
|
+
get_parent(@app.handle).should == nil
|
424
|
+
end
|
425
|
+
end # describe get_parent
|
426
|
+
|
427
|
+
describe "#get_ancestor" do
|
428
|
+
spec{ use{ ancestor = GetAncestor(any_handle, ga_flags=0) }}
|
429
|
+
spec{ use{ ancestor = get_ancestor(any_handle, ga_flags=0) }}
|
430
|
+
|
431
|
+
context 'GA_PARENT - Retrieves parent window. Unlike GetParent function, this does NOT include the owner.' do
|
432
|
+
it "retrieves a handle to the specified window's parent" do
|
433
|
+
child = find_window_ex(@app.handle, 0, nil, nil)
|
434
|
+
parent1 = GetAncestor(child, GA_PARENT)
|
435
|
+
parent2 = get_ancestor(child, GA_PARENT)
|
436
|
+
parent1.should == parent2
|
437
|
+
parent1.should == @app.handle
|
438
|
+
end
|
439
|
+
|
440
|
+
it "returns desktop handle for top-level window" do
|
441
|
+
parent = get_ancestor(@app.handle, GA_PARENT)
|
442
|
+
class_name(parent).should == DESKTOP_CLASS
|
443
|
+
end
|
444
|
+
|
445
|
+
it "returns 0/nil if the specified window is a desktop (has REALLY no parent)" do
|
446
|
+
desktop = get_ancestor(@app.handle, GA_PARENT)
|
447
|
+
GetAncestor(desktop, GA_PARENT).should == 0
|
448
|
+
get_ancestor(desktop, GA_PARENT).should == nil
|
449
|
+
end
|
450
|
+
end # context GA_PARENT
|
451
|
+
|
452
|
+
# GA_ROOT - Retrieves the root window by walking the chain of parent windows.
|
453
|
+
# GA_ROOTOWNER - Retrieves the owned root window by walking the chain of parent and owner windows
|
454
|
+
# returned by GetParent.
|
455
|
+
it "original api retrieves the handle to the ancestor of the specified window. " do
|
456
|
+
pending
|
457
|
+
success = GetAncestor(hwnd=0, ga_flags=0)
|
458
|
+
end
|
459
|
+
|
460
|
+
it "snake_case api retrieves the handle to the ancestor of the specified window. " do
|
461
|
+
pending
|
462
|
+
success = get_ancestor(hwnd=0, ga_flags=0)
|
463
|
+
end
|
464
|
+
|
465
|
+
end # describe get_ancestor
|
466
|
+
|
467
|
+
describe "#get_window" do
|
468
|
+
spec{ use{ handle = GetWindow(any_handle, command=0) }}
|
469
|
+
spec{ use{ handle = get_window(any_handle, command=0) }}
|
470
|
+
|
471
|
+
context "GW_CHILD retrieves a window handle to a first (top of the Z order) child of given window" do
|
472
|
+
before(:all) do
|
473
|
+
# GW_CHILD - The retrieved handle identifies the child window at the top of the Z order, if the specified
|
474
|
+
@child1 = GetWindow(@app.handle, GW_CHILD)
|
475
|
+
@child2 = get_window(@app.handle, GW_CHILD)
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'returns active window handle' do
|
479
|
+
window?(@child1).should == true
|
480
|
+
end
|
481
|
+
it 'returns the same value for original and snake case API' do
|
482
|
+
@child1.should == @child2
|
483
|
+
end
|
484
|
+
it 'returns first direct child of a given window' do
|
485
|
+
@child1.should == find_window_ex(@app.handle, 0, nil, nil)
|
486
|
+
end
|
487
|
+
it 'returns nil/0 if no children for a given window' do
|
488
|
+
GetWindow(@child1, GW_CHILD).should == 0
|
489
|
+
get_window(@child1, GW_CHILD).should == nil
|
490
|
+
end
|
491
|
+
end # context GW_CHILD
|
492
|
+
|
493
|
+
context "GW_OWNER - retrieves a handle to an owner of a given Window" do
|
494
|
+
# GW_OWNER - The retrieved handle identifies the specified window's owner window, if any. For more
|
495
|
+
|
496
|
+
it 'returns owner (but NOT parent!) of a given window' do
|
497
|
+
pending
|
498
|
+
|
499
|
+
child = find_window_ex(@app.handle, 0, nil, nil)
|
500
|
+
p owner1 = GetWindow(child, GW_OWNER)
|
501
|
+
p owner2 = get_window(child, GW_OWNER)
|
502
|
+
owner1.should == owner2
|
503
|
+
owner1.should == @app.handle
|
504
|
+
end
|
505
|
+
|
506
|
+
it 'returns nil/0 if no owner for a given window' do
|
507
|
+
GetWindow(@app.handle, GW_OWNER).should == 0
|
508
|
+
get_window(@app.handle, GW_OWNER).should == nil
|
509
|
+
end
|
510
|
+
|
511
|
+
end
|
512
|
+
|
513
|
+
it "GW_OWNER - retrieves a handle to a window that has the specified relationship to given Window" do
|
514
|
+
pending
|
515
|
+
# GW_ENABLEDPOPUP - Windows 2000/XP: The retrieved handle identifies the enabled popup window owned by
|
516
|
+
# GW_HWNDFIRST - The retrieved handle identifies the window of the same type that is highest in Z order.
|
517
|
+
# GW_HWNDLAST - The retrieved handle identifies the window of the same type that is lowest in the Z order.
|
518
|
+
# GW_HWNDNEXT - The retrieved handle identifies the window below the specified window in the Z order.
|
519
|
+
# GW_HWNDPREV - The retrieved handle identifies the window above the specified window in the Z order.
|
520
|
+
# GW_OWNER - The retrieved handle identifies the specified window's owner window, if any. For more
|
521
|
+
end
|
522
|
+
end # describe get_window
|
523
|
+
|
408
524
|
describe '#enum_windows' do
|
409
525
|
# before(:each){@app = launch_test_app}
|
410
526
|
# after(:each){close_test_app}
|
@@ -460,8 +576,8 @@ module WinWindowTest
|
|
460
576
|
enum = enum_child_windows(@app.handle, 13)
|
461
577
|
enum.should be_a_kind_of Array
|
462
578
|
enum.should have(2).elements
|
463
|
-
class_name(enum.first).should ==
|
464
|
-
class_name(enum.last).should ==
|
579
|
+
class_name(enum.first).should == STATUSBAR_CLASS
|
580
|
+
class_name(enum.last).should == TEXTAREA_CLASS
|
465
581
|
end
|
466
582
|
|
467
583
|
it 'loops through all children of given window, passing each found window handle and a message to a given block' do
|
@@ -471,8 +587,8 @@ module WinWindowTest
|
|
471
587
|
message.should == 13
|
472
588
|
end
|
473
589
|
enum.should have(2).elements
|
474
|
-
class_name(enum.first).should ==
|
475
|
-
class_name(enum.last).should ==
|
590
|
+
class_name(enum.first).should == STATUSBAR_CLASS
|
591
|
+
class_name(enum.last).should == TEXTAREA_CLASS
|
476
592
|
end
|
477
593
|
|
478
594
|
it 'breaks loop if given block returns false' do
|
@@ -482,7 +598,7 @@ module WinWindowTest
|
|
482
598
|
false
|
483
599
|
end
|
484
600
|
enum.should have(1).element
|
485
|
-
class_name(enum.first).should ==
|
601
|
+
class_name(enum.first).should == STATUSBAR_CLASS
|
486
602
|
end
|
487
603
|
|
488
604
|
it 'defaults message to 0 if it is omitted from method call' do
|
@@ -528,7 +644,7 @@ module WinWindowTest
|
|
528
644
|
app = launch_test_app
|
529
645
|
|
530
646
|
shut_window(app.handle).should == true
|
531
|
-
sleep
|
647
|
+
sleep SLEEP_DELAY
|
532
648
|
|
533
649
|
window?(app.handle).should == false
|
534
650
|
end
|
@@ -540,7 +656,7 @@ module WinWindowTest
|
|
540
656
|
it 'returns text associated with window by sending WM_GETTEXT message to it' do
|
541
657
|
test_app do |app|
|
542
658
|
|
543
|
-
text(app.handle).should ==
|
659
|
+
text(app.handle).should == WIN_TITLE
|
544
660
|
text(app.textarea).should =~ /Welcome to Steganos LockNote/
|
545
661
|
end
|
546
662
|
end
|
data/spec/win/library_spec.rb
CHANGED
@@ -92,12 +92,12 @@ module WinLibraryTest
|
|
92
92
|
|
93
93
|
it 'constructs argument prototype from uppercase string, enforces the args count' do
|
94
94
|
expect { MyLib.function :FindWindow, 'PP', 'L' }.to_not raise_error
|
95
|
-
should_count_args :find_window, :FindWindow, [nil, nil], [nil,
|
95
|
+
should_count_args :find_window, :FindWindow, [nil, nil], [nil, IMPOSSIBLE, 'cmd']
|
96
96
|
end
|
97
97
|
|
98
98
|
it 'constructs argument prototype from (mixed) array, enforces the args count' do
|
99
99
|
expect { MyLib.function :FindWindow, [:pointer, 'P'], 'L' }.to_not raise_error
|
100
|
-
should_count_args :find_window, :FindWindow, [nil, nil], [nil,
|
100
|
+
should_count_args :find_window, :FindWindow, [nil, nil], [nil, IMPOSSIBLE, 'cmd']
|
101
101
|
end
|
102
102
|
|
103
103
|
it 'with :rename option, overrides snake_case name for defined method but leaves CamelCase intact' do
|
@@ -110,17 +110,17 @@ module WinLibraryTest
|
|
110
110
|
it 'defined snake_case method returns expected value when called' do
|
111
111
|
MyLib.function :FindWindow, 'PP', 'L'
|
112
112
|
find_window(nil, nil).should_not == 0
|
113
|
-
find_window(nil,
|
114
|
-
find_window(
|
115
|
-
find_window(
|
113
|
+
find_window(nil, IMPOSSIBLE).should == 0
|
114
|
+
find_window(IMPOSSIBLE, nil).should == 0
|
115
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE).should == 0
|
116
116
|
end
|
117
117
|
|
118
118
|
it 'defined CamelCase method returns expected value when called' do
|
119
119
|
MyLib.function :FindWindow, 'PP', 'L'
|
120
120
|
FindWindow(nil, nil).should_not == 0
|
121
|
-
FindWindow(nil,
|
122
|
-
FindWindow(
|
123
|
-
FindWindow(
|
121
|
+
FindWindow(nil, IMPOSSIBLE).should == 0
|
122
|
+
FindWindow(IMPOSSIBLE, nil).should == 0
|
123
|
+
FindWindow(IMPOSSIBLE, IMPOSSIBLE).should == 0
|
124
124
|
end
|
125
125
|
|
126
126
|
# it 'returns underlying Win32::API object if defined method is called with (:api) argument ' do
|
@@ -172,17 +172,17 @@ module WinLibraryTest
|
|
172
172
|
|
173
173
|
it 'defined snake_case method returns false/true instead of zero/non-zero' do
|
174
174
|
find_window(nil, nil).should == true
|
175
|
-
find_window(nil,
|
175
|
+
find_window(nil, IMPOSSIBLE).should == false
|
176
176
|
end
|
177
177
|
|
178
178
|
it 'defined CamelCase method still returns zero/non-zero' do
|
179
179
|
FindWindow(nil, nil).should_not == true
|
180
180
|
FindWindow(nil, nil).should_not == 0
|
181
|
-
FindWindow(nil,
|
181
|
+
FindWindow(nil, IMPOSSIBLE).should == 0
|
182
182
|
end
|
183
183
|
|
184
184
|
it 'defined methods enforce the argument count' do
|
185
|
-
should_count_args :find_window, :FindWindow, [nil, nil], [nil,
|
185
|
+
should_count_args :find_window, :FindWindow, [nil, nil], [nil, IMPOSSIBLE, 'cmd']
|
186
186
|
end
|
187
187
|
end
|
188
188
|
|
@@ -197,12 +197,12 @@ module WinLibraryTest
|
|
197
197
|
it 'defined CamelCase method still returns zero/non-zero' do
|
198
198
|
FindWindow(nil, nil).should_not == true
|
199
199
|
FindWindow(nil, nil).should_not == 0
|
200
|
-
FindWindow(nil,
|
200
|
+
FindWindow(nil, IMPOSSIBLE).should == 0
|
201
201
|
end
|
202
202
|
|
203
203
|
it 'defined method returns nil (but NOT false) instead of zero' do
|
204
|
-
find_window(nil,
|
205
|
-
find_window(nil,
|
204
|
+
find_window(nil, IMPOSSIBLE).should_not == false
|
205
|
+
find_window(nil, IMPOSSIBLE).should == nil
|
206
206
|
end
|
207
207
|
|
208
208
|
it 'defined method does not return true when result is non-zero' do
|
@@ -211,7 +211,7 @@ module WinLibraryTest
|
|
211
211
|
end
|
212
212
|
|
213
213
|
it 'defined methods enforce the argument count' do
|
214
|
-
should_count_args :find_window, :FindWindow, [nil, nil], [nil,
|
214
|
+
should_count_args :find_window, :FindWindow, [nil, nil], [nil, IMPOSSIBLE, 'cmd']
|
215
215
|
end
|
216
216
|
end
|
217
217
|
|
@@ -292,18 +292,18 @@ module WinLibraryTest
|
|
292
292
|
context 'calling defined methods with attached block to preprocess the API function results' do
|
293
293
|
it 'defined method yields raw result to block attached to its invocation' do
|
294
294
|
MyLib.function :FindWindow, 'PP', 'L', zeronil: true
|
295
|
-
find_window(nil,
|
295
|
+
find_window(nil, IMPOSSIBLE) {|result| result.should == 0 }
|
296
296
|
end
|
297
297
|
|
298
298
|
it 'defined method returns result of block attached to its invocation' do
|
299
299
|
MyLib.function :FindWindow, 'PP', 'L', zeronil: true
|
300
|
-
return_value = find_window(nil,
|
300
|
+
return_value = find_window(nil, IMPOSSIBLE) {|result| 'Value'}
|
301
301
|
return_value.should == 'Value'
|
302
302
|
end
|
303
303
|
|
304
304
|
it 'defined method transforms result of block before returning it' do
|
305
305
|
MyLib.function :FindWindow, 'PP', 'L', zeronil: true
|
306
|
-
return_value = find_window(nil,
|
306
|
+
return_value = find_window(nil, IMPOSSIBLE) {|result| 0 }
|
307
307
|
return_value.should_not == 0
|
308
308
|
return_value.should == nil
|
309
309
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 3
|
8
|
-
-
|
9
|
-
version: 0.3.
|
8
|
+
- 5
|
9
|
+
version: 0.3.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- arvicco
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-05-28 00:00:00 +04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|