win 0.1.16 → 0.1.18

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.16
1
+ 0.1.18
data/lib/win/error.rb CHANGED
@@ -851,6 +851,13 @@ module Win
851
851
  FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
852
852
  FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF
853
853
 
854
+ # Set/GetErrorMode values:
855
+
856
+ SEM_FAILCRITICALERRORS = 0x0001
857
+ SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
858
+ SEM_NOGPFAULTERRORBOX = 0x0002
859
+ SEM_NOOPENFILEERRORBOX = 0x8000
860
+
854
861
  ##
855
862
  # FormatMessage Function
856
863
  # Formats a message string. The function requires a message definition as input. The message definition
@@ -1011,12 +1018,11 @@ module Win
1011
1018
  function :FormatMessage, [:DWORD, :LPCVOID, :DWORD, :DWORD, :LPTSTR, :DWORD, :varargs], :DWORD,
1012
1019
  &->(api, flags=FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
1013
1020
  source=nil, message_id=0, language_id=0, *args){
1014
- buffer = FFI::MemoryPointer.new :char, 260
1021
+ buffer = FFI::MemoryPointer.new :char, 260
1015
1022
  args = [:int, 0] if args.empty?
1016
1023
  num_chars = api.call(flags, source, message_id, language_id, buffer, buffer.size, *args)
1017
1024
  num_chars == 0 ? nil : buffer.get_bytes(0, num_chars).strip }
1018
1025
 
1019
-
1020
1026
  ##
1021
1027
  # GetLastError Function
1022
1028
  # Retrieves the calling thread's last-error code value. The last-error code is maintained on a
@@ -1062,5 +1068,157 @@ module Win
1062
1068
  &->(api) { error_code = api.call
1063
1069
  flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY
1064
1070
  format_message(flags, nil, error_code)}
1071
+
1072
+ ##
1073
+ # SetLastError Function
1074
+ # Sets the last-error code for the calling thread.
1075
+ #
1076
+ # [*Syntax*] void WINAPI SetLastError( DWORD dwErrCode );
1077
+ #
1078
+ # dwErrCode:: [in] The last-error code for the thread.
1079
+ #
1080
+ # *Returns*:: This function does not return a value.
1081
+ # ---
1082
+ # *Remarks*:
1083
+ # - The last-error code is kept in thread local storage so that multiple threads do not overwrite each
1084
+ # other's values.
1085
+ # - This function is intended primarily for use by dynamic-link libraries (DLL). A DLL can provide the
1086
+ # applications that are using it with additional diagnostic information by calling this function after
1087
+ # an error occurs. Most functions call SetLastError or SetLastErrorEx only when they fail. However, some
1088
+ # system functions call SetLastError or SetLastErrorEx under conditions of success; those cases are
1089
+ # noted in each function's documentation.
1090
+ # - Applications can optionally retrieve the value set by this function by using the GetLastError function
1091
+ # immediately after a function fails.
1092
+ # - Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29 is reserved for
1093
+ # application-defined error codes; no system error code has this bit set. If you are defining an error
1094
+ # code for your application, set this bit to indicate that the error code has been defined by your
1095
+ # application and to ensure that your error code does not conflict with any system-defined error codes.
1096
+ # ---
1097
+ # <b>Enhanced (snake_case) API: </b>
1098
+ #
1099
+ # :call-seq:
1100
+ # set_last_error(err_code)
1101
+ #
1102
+ function :SetLastError, [:DWORD], :void
1103
+
1104
+ ##
1105
+ # SetLastErrorEx Function sets the last-error code.
1106
+ # Currently, this function is identical to the SetLastError function. The second parameter is ignored.
1107
+ #
1108
+ # [*Syntax*] void WINAPI SetLastErrorEx( DWORD dwErrCode, DWORD dwType );
1109
+ #
1110
+ # dwErrCode:: The last-error code for the thread.
1111
+ # dwType:: This parameter is ignored.
1112
+ #
1113
+ # *Returns*:: This function does not return a value.
1114
+ # ---
1115
+ # *Remarks*:
1116
+ # The last-error code is kept in thread local storage so that multiple threads do not overwrite each
1117
+ # other's values.
1118
+ # This function is intended primarily for use by dynamic-link libraries (DLL). A DLL can provide the
1119
+ # applications that are using it with additional diagnostic information by calling this function after
1120
+ # an error occurs. Most functions call SetLastError or SetLastErrorEx only when they fail. However, some
1121
+ # system functions call SetLastError or SetLastErrorEx under conditions of success; those cases are
1122
+ # noted in each function's documentation.
1123
+ # Applications can optionally retrieve the value set by this function by using the GetLastError function
1124
+ # immediately after a function fails.
1125
+ # Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29 is reserved for
1126
+ # application-defined error codes; no system error code has this bit set. If you are defining an error
1127
+ # code for your application, set this bit to indicate that the error code has been defined by the
1128
+ # application and to ensure that your error code does not conflict with any system-defined error codes.
1129
+ #
1130
+ # :call-seq:
1131
+ # set_last_error_ex(err_code, dw_type)
1132
+ #
1133
+ try_function :SetLastErrorEx, [:DWORD, :DWORD], :void
1134
+ # fails silently unless platform is XP++
1135
+
1136
+ ##
1137
+ # GetErrorMode Function
1138
+ # Retrieves the error mode for the current process.
1139
+ #
1140
+ # [*Syntax*] UINT WINAPI GetErrorMode( void );
1141
+ #
1142
+ # This function has no parameters.
1143
+ #
1144
+ # *Returns*:: The process error mode. This function returns one of the following values.
1145
+ # SEM_FAILCRITICALERRORS:: The system does not display the critical-error-handler message box. Instead,
1146
+ # the system sends the error to the calling process.
1147
+ # SEM_NOALIGNMENTFAULTEXCEPT:: The system automatically fixes memory alignment faults and makes them
1148
+ # invisible to the application. It does this for the calling process and any
1149
+ # descendant processes. This feature is only supported by certain processor
1150
+ # architectures. For more information, see the Remarks section.
1151
+ # After this value is set for a process, subsequent attempts to clear the
1152
+ # value are ignored.
1153
+ # SEM_NOGPFAULTERRORBOX:: The system does not display the general-protection-fault message box. This flag
1154
+ # should only be set by debugging applications that handle general protection (GP)
1155
+ # faults themselves with an exception handler.
1156
+ # SEM_NOOPENFILEERRORBOX:: The system does not display a message box when it fails to find a file. Instead,
1157
+ # the error is returned to the calling process.
1158
+ # ---
1159
+ # *Remarks*:
1160
+ # Each process has an associated error mode that indicates to the system how the application is going to
1161
+ # respond to serious errors. A child process inherits the error mode of its parent process.
1162
+ # To change the error mode for the process, use the SetErrorMode function.
1163
+ # ------
1164
+ # <b> Only works in Vista++! </b>
1165
+ # ------
1166
+ # :call-seq:
1167
+ # mode = get_error_mode()
1168
+ #
1169
+ try_function :GetErrorMode, [], :UINT
1170
+ # fails silently unless platform is Vista++
1171
+
1172
+ ##
1173
+ # SetErrorMode Function controls whether the system will handle the specified types of serious errors or whether
1174
+ # the process will handle them.
1175
+ #
1176
+ # [*Syntax*] UINT WINAPI SetErrorMode( UINT uMode );
1177
+ #
1178
+ # uMode:: The process error mode. This parameter can be one or more of the following values.
1179
+ # 0:: Use the system default, which is to display all error dialog boxes.
1180
+ # SEM_FAILCRITICALERRORS:: The system does not display the critical-error-handler message box. Instead,
1181
+ # the system sends the error to the calling process.
1182
+ # SEM_NOALIGNMENTFAULTEXCEPT:: The system automatically fixes memory alignment faults and makes them
1183
+ # invisible to the application. It does this for the calling process and any
1184
+ # descendant processes. This feature is only supported by certain processor
1185
+ # architectures. For more information, see the Remarks section.
1186
+ # After this value is set for a process, subsequent attempts to clear the
1187
+ # value are ignored.
1188
+ # SEM_NOGPFAULTERRORBOX:: The system does not display the general-protection-fault message box. This flag
1189
+ # should only be set by debugging applications that handle general protection (GP)
1190
+ # faults themselves with an exception handler.
1191
+ # SEM_NOOPENFILEERRORBOX:: The system does not display a message box when it fails to find a file. Instead,
1192
+ # the error is returned to the calling process.
1193
+ #
1194
+ # *Returns*:: The return value is the previous state of the error-mode bit flags.
1195
+ # ---
1196
+ # *Remarks*:
1197
+ # Each process has an associated error mode that indicates to the system how the application is going to
1198
+ # respond to serious errors. A child process inherits the error mode of its parent process. To retrieve
1199
+ # the process error mode, use the GetErrorMode function.
1200
+ # Because the error mode is set for the entire process, you must ensure that multi-threaded applications
1201
+ # do not set different error-mode flags. Doing so can lead to inconsistent error handling.
1202
+ # The system does not make alignment faults visible to an application on all processor architectures.
1203
+ # Therefore, specifying SEM_NOALIGNMENTFAULTEXCEPT is not an error on such architectures, but the system
1204
+ # is free to silently ignore the request. This means that code sequences such as the following are not
1205
+ # always valid on x86 computers:
1206
+ #
1207
+ # SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);
1208
+ # fuOldErrorMode = SetErrorMode(0);
1209
+ # ASSERT(fuOldErrorMode == SEM_NOALIGNMENTFAULTEXCEPT);
1210
+ #
1211
+ # Itanium:: An application must explicitly call SetErrorMode with SEM_NOALIGNMENTFAULTEXCEPT to have the
1212
+ # system automatically fix alignment faults. The default setting is for the system to make alignment
1213
+ # faults visible to an application.
1214
+ # Visual Studio 2005:: When declaring a pointer to a structure that may not have aligned data, you can use
1215
+ # __unaligned keyword to indicate that the type must be read one byte at a time. For more
1216
+ # information, see Windows Data Alignment.
1217
+ #
1218
+ # :call-seq:
1219
+ # success = set_error_mode(mode)
1220
+ #
1221
+ function :SetErrorMode, [:UINT], :UINT
1222
+
1065
1223
  end
1066
1224
  end
data/lib/win/gui.rb CHANGED
@@ -2,7 +2,6 @@ require 'win/gui/window'
2
2
  require 'win/gui/input'
3
3
  require 'win/gui/message'
4
4
  require 'win/gui/dialog'
5
- require 'win/gui/window/window'
6
5
 
7
6
  module Win
8
7
 
@@ -33,15 +33,15 @@ module Win
33
33
  # Convenience methods:
34
34
 
35
35
  # finds top-level dialog window by title and yields found dialog window to block if given
36
- def dialog(title, seconds=3)
37
- d = begin
38
- win = Window::Window.top_level(title, seconds)
39
- yield(win) ? win : nil
40
- rescue TimeoutError
41
- end
42
- d.wait_for_close if d
43
- return d
44
- end
36
+ # def dialog(title, seconds=3)
37
+ # d = begin
38
+ # win = Window::Window.top_level(title, seconds)
39
+ # yield(win) ? win : nil
40
+ # rescue TimeoutError
41
+ # end
42
+ # d.wait_for_close if d
43
+ # return d
44
+ # end
45
45
  end
46
46
  end
47
47
  end
data/lib/win/gui/input.rb CHANGED
@@ -288,6 +288,38 @@ module Win
288
288
  #
289
289
  function :SetCursorPos, [:int, :int], :int, boolean: true
290
290
 
291
+ ##
292
+ # GetCursorPos Function retrieves the cursor's position, in screen coordinates.
293
+ #
294
+ # [*Syntax*] BOOL GetCursorPos( LPPOINT lpPoint );
295
+ #
296
+ # lpPoint:: [out] Pointer to a POINT structure that receives the screen coordinates of the cursor.
297
+ #
298
+ # *Returns*:: Returns nonzero if successful or zero otherwise. To get extended error information, call
299
+ # GetLastError.
300
+ # ---
301
+ # *Remarks*:
302
+ # The cursor position is always specified in screen coordinates and is not affected by the mapping mode
303
+ # of the window that contains the cursor.
304
+ # The calling process must have WINSTA_READATTRIBUTES access to the window station.
305
+ # The input desktop must be the current desktop when you call GetCursorPos. Call OpenInputDesktop to
306
+ # determine whether the current desktop is the input desktop. If it is not, call SetThreadDesktop with
307
+ # the HDESK returned by OpenInputDesktop to switch to that desktop.
308
+ # ---
309
+ # <b>Enhanced (snake_case) API: accepts no args, returns a pair (x, y) of cursor coordinates</b>
310
+ #
311
+ # :call-seq:
312
+ # x, y = get_cursor_pos()
313
+ #
314
+ function :GetCursorPos, [:pointer], :int8,
315
+ &->(api) {
316
+ point = FFI::MemoryPointer.new(:long, 2)
317
+ res = api.call point
318
+ res == 0 ? [nil, nil] : point.read_array_of_long(2) }
319
+ # weird lambda literal instead of normal block is needed because current version of RDoc
320
+ # goes crazy if block is attached to meta-definition
321
+
322
+
291
323
  # Convenience methods
292
324
 
293
325
  ##
@@ -416,7 +416,7 @@ module Win
416
416
  #:call-seq:
417
417
  # success = post_message(handle, msg, w_param, l_param)
418
418
  #
419
- function :PostMessage, [:ulong, :uint, :long, :uint], :int, boolean: true
419
+ function :PostMessage, [:ulong, :uint, :long, :pointer], :int, boolean: true
420
420
 
421
421
  ##
422
422
  # The SendMessage function sends the specified message to a window or windows. It calls the window procedure for
@@ -530,7 +530,7 @@ module Win
530
530
  # :call-seq:
531
531
  # handles = enum_windows( [value=0] ) {|handle, value| your callback procedure }
532
532
  #
533
- function :EnumWindows, [:EnumWindowsProc, :long], :bool, &return_enum
533
+ function :EnumWindows, [:EnumWindowsProc, :long], :int8, &return_enum
534
534
 
535
535
  ##
536
536
  # EnumDesktopWindows Function enumerates all top-level windows associated with the specified desktop.
@@ -568,7 +568,7 @@ module Win
568
568
  # :call-seq:
569
569
  # handles = enum_desktop_windows( desktop_handle, [value=0] ) {|handle, value| your callback procedure }
570
570
  #
571
- function :EnumDesktopWindows, [:ulong, :EnumWindowsProc, :long], :bool, &return_enum
571
+ function :EnumDesktopWindows, [:ulong, :EnumWindowsProc, :long], :int8, &return_enum
572
572
 
573
573
  ##
574
574
  # The EnumChildWindows function enumerates the child windows that belong to the specified parent window by
@@ -602,7 +602,7 @@ module Win
602
602
  #:call-seq:
603
603
  # handles = enum_child_windows( parent_handle, [value=0] ) {|handle, value| your callback procedure }
604
604
  #
605
- function :EnumChildWindows, [:HWND, :EnumWindowsProc, :long], :bool, &return_enum
605
+ function :EnumChildWindows, [:HWND, :EnumWindowsProc, :long], :int8, &return_enum
606
606
 
607
607
  ##
608
608
  # GetForegroundWindow function returns a handle to the foreground window (the window with which the user
@@ -660,7 +660,7 @@ module Win
660
660
  # I have not find so far how to REALLY destroy window in different thread without it asking user anything.
661
661
  #
662
662
  def shut_window( win_handle)
663
- post_message(win_handle, Win::GUI::Message::WM_SYSCOMMAND, Win::GUI::Message::SC_CLOSE, 0)
663
+ post_message(win_handle, Win::GUI::Message::WM_SYSCOMMAND, Win::GUI::Message::SC_CLOSE, nil)
664
664
  end
665
665
 
666
666
  ##
data/lib/win/library.rb CHANGED
@@ -374,7 +374,16 @@ module Win
374
374
  api #return api object from function declaration
375
375
  end
376
376
 
377
- ##
377
+ # Try to define platform-specific function, rescue error, return message
378
+ #
379
+ def try_function(name, params, returns, options={}, &def_block)
380
+ begin
381
+ function name, params, returns, options={}, &def_block
382
+ rescue Win::Errors::NotFoundError
383
+ "This platform does not support function #{name}"
384
+ end
385
+ end
386
+
378
387
  # Generates possible effective names for function in Win32 dll (name+A/W),
379
388
  # Rubyesque name and aliases for method(s) defined based on function name,
380
389
  #
data/spec/spec_helper.rb CHANGED
@@ -9,6 +9,18 @@ $debug = true
9
9
  # Customize RSpec with my own extensions
10
10
  module ClassMacros
11
11
 
12
+ def os
13
+ `ver`
14
+ end
15
+
16
+ def vista?
17
+ os =~ /Version 6/
18
+ end
19
+
20
+ def xp?
21
+ os =~ /XP/
22
+ end
23
+
12
24
  # wrapper for it method that extracts description from example source code, such as:
13
25
  # spec { use{ function(arg1 = 4, arg2 = 'string') }}
14
26
  def spec &block
@@ -8,7 +8,11 @@ module WinErrorTest
8
8
  include Win::GUI::Window
9
9
 
10
10
  def buffer
11
- FFI::MemoryPointer.new(:char, 1024)
11
+ FFI::MemoryPointer.new(:char, 260)
12
+ end
13
+
14
+ def sys_flags
15
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY
12
16
  end
13
17
 
14
18
  describe Win::Error, ' contains a set of pre-defined Windows API functions' do
@@ -29,25 +33,80 @@ module WinErrorTest
29
33
  window_text(0)
30
34
  get_last_error.should == "Invalid window handle."
31
35
  end
32
-
33
36
  end # describe "#get_last_error"
34
37
 
35
38
  describe "#format_message" do
36
- spec{ use{ num_chars = FormatMessage(dw_flags=0, lp_source=nil, dw_message_id=0, dw_language_id=0, buffer, buffer.size, :int, 0) }}
37
- spec{ use{ message = format_message(dw_flags=0, lp_source=nil, dw_message_id=0, dw_language_id=0, :int, 0) }}
39
+ spec{ use{ num_chars = FormatMessage(sys_flags, source=nil, message_id=0, language_id=0, buffer, buffer.size, :int, 0) }}
40
+ spec{ use{ message = format_message(sys_flags, source=nil, message_id=0, language_id=0, :int, 0) }}
38
41
 
39
- it "original api Formats a message string. The function requires a message definition as input. The message definition " do
40
- pending
41
- num_chars = FormatMessage(dw_flags=0, nil, dw_message_id=0, dw_language_id=0, buffer, buffer.size, :int, 0)
42
+ it "original api formats a message string - system message" do
43
+ find_window(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE)
44
+ message_id = GetLastError()
45
+ buf = buffer()
46
+ num_chars = FormatMessage(sys_flags, nil, message_id, dw_language_id=0, buf, buf.size, :int, 0)
47
+ buf.get_bytes(0, num_chars).strip.should == "The system cannot find the file specified."
42
48
  end
43
49
 
44
- it "snake_case api Formats a message string. The function requires a message definition as input. The message definition " do
45
- pending
46
- message = format_message(dw_flags=0, nil, dw_message_id=0, dw_language_id=0, lp_buffer=0, n_size=0,:int, 0)
50
+ it "snake_case api Formats a message string - system message" do
51
+ find_window(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE)
52
+ message = format_message(sys_flags, nil, dw_message_id=GetLastError())
53
+ message.should == "The system cannot find the file specified."
47
54
  end
48
-
49
55
  end # describe format_message
50
56
 
57
+ describe "#set_last_error" do
58
+ spec{ use{ SetLastError(err_code=0) }}
59
+ spec{ use{ set_last_error(err_code=0) }}
60
+
61
+ it "original api sets the last-error code for the calling thread." do
62
+ SetLastError(dw_err_code=0xF000)
63
+ GetLastError().should == ERROR_USER_DEFINED_BASE
64
+ end
65
+
66
+ it "snake_case api also sets the last-error code for the calling thread." do
67
+ set_last_error(3000)
68
+ get_last_error.should == "The specified print monitor is unknown."
69
+ end
70
+ end # describe set_last_error
71
+
72
+ if xp? || vista? # This function works only on XP++
73
+ describe "#set_last_error_ex" do
74
+ spec{ use{ SetLastErrorEx(dw_err_code=0, dw_type=0) }}
75
+ spec{ use{ set_last_error_ex(dw_err_code=0, dw_type=0) }}
76
+
77
+ it "original api sets the last-error code for the calling thread." do
78
+ SetLastErrorEx(dw_err_code=0xF000, dw_type=0)
79
+ GetLastError().should == ERROR_USER_DEFINED_BASE
80
+ end
81
+
82
+ it "snake_case api also sets the last-error code for the calling thread." do
83
+ set_last_error_ex(3000,0)
84
+ get_last_error.should == "The specified print monitor is unknown."
85
+ end
86
+ end # describe set_last_error_ex
87
+ end
88
+
89
+ if vista? # This function works only on Vista++
90
+ describe "#get_error_mode" do
91
+ spec{ use{ mode = GetErrorMode() }}
92
+ spec{ use{ mode = get_error_mode() }}
93
+
94
+ it "original api retrieves the error mode for the current process." do
95
+ p mode = GetErrorMode()
96
+ end
97
+
98
+ it "snake_case api also retrieves the error mode for the current process." do
99
+ p mode = get_error_mode()
100
+ end
101
+ end # describe get_error_mode
102
+ end
103
+
104
+ describe "#set_error_mode" do
105
+ spec{ use{ success = SetErrorMode(u_mode=0) }}
106
+ spec{ use{ success = set_error_mode(u_mode=0) }}
107
+
108
+ it "controls whether the system OR process will handle the specified types of serious errors"
109
+ end # describe set_error_mode
51
110
 
52
111
  end # describe Win::Error
53
112
  end
@@ -14,43 +14,29 @@ module WinWindowTest
14
14
 
15
15
  it 'returns handle to correctly specified control'
16
16
 
17
- it 'does something else' do
18
- pending
19
- test_app do |app|
20
- text = '123 456'
21
- text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
22
- keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
23
- sleep TEST_KEY_DELAY
24
- keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
25
- sleep TEST_KEY_DELAY
26
- end
27
- app.textarea.text.should =~ Regexp.new(text)
28
- 7.times {keystroke(VK_CONTROL, 'Z'.ord)} # dirty hack!
29
- end
30
- end
31
17
  end
32
18
 
33
19
  describe Win::GUI::Dialog, ' defines convenience/service methods on top of Windows API' do
34
- describe 'dialog' do
35
- spec{ use{ dialog( title ='Dialog Title', timeout_sec = 0.001, &any_block) }}
36
-
37
- it 'finds top-level dialog window by title' do
38
- pending 'Some problems (?with timeouts?) leave window open ~half of the runs'
39
- test_app do |app|
40
- keystroke(VK_ALT, 'F'.ord, 'A'.ord)
41
- @found = false
42
- dialog('Save As', 0.5) do |dialog_window|
43
- @found = true
44
- keystroke(VK_ESCAPE)
45
- dialog_window
46
- end
47
- @found.should == true
48
- end
49
- end
50
-
51
- it 'yields found dialog window to a given block'
52
-
53
- end
20
+ # describe 'dialog' do
21
+ # spec{ use{ dialog( title ='Dialog Title', timeout_sec = 0.001, &any_block) }}
22
+ #
23
+ # it 'finds top-level dialog window by title' do
24
+ # pending 'Some problems (?with timeouts?) leave window open ~half of the runs'
25
+ # test_app do |app|
26
+ # keystroke(VK_ALT, 'F'.ord, 'A'.ord)
27
+ # @found = false
28
+ # dialog('Save As', 0.5) do |dialog_window|
29
+ # @found = true
30
+ # keystroke(VK_ESCAPE)
31
+ # dialog_window
32
+ # end
33
+ # @found.should == true
34
+ # end
35
+ # end
36
+ #
37
+ # it 'yields found dialog window to a given block'
38
+ #
39
+ # end
54
40
  end
55
41
  end
56
42
  end
@@ -7,7 +7,7 @@ module WinWindowTest
7
7
  include WinTestApp
8
8
  include Win::GUI::Input
9
9
 
10
- describe Win::GUI::Input do
10
+ describe Win::GUI::Input, ' defines a set of API functions related to user input' do
11
11
 
12
12
  describe '#keydb_event' do
13
13
  spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }}
@@ -25,18 +25,49 @@ module WinWindowTest
25
25
  5.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
26
26
  end
27
27
  end
28
- end
28
+ end # describe '#keydb_event'
29
29
 
30
30
  describe '#mouse_event' do
31
31
  spec { use {mouse_event( flags = MOUSEEVENTF_ABSOLUTE , dx = 0, dy = 0, data=0, extra_info=0 )}}
32
32
  it 'Emulates Mouse clicks'
33
- end
33
+ end # describe '#mouse_event'
34
+
35
+ describe "#get_cursor_pos" do
36
+ spec{ use{ success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2)) }}
37
+ spec{ use{ x, y = get_cursor_pos() }}
38
+
39
+ it "original api returns success code and puts cursor's screen coordinates into supplied buffer" do
40
+ success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2))
41
+ success.should_not == 0
42
+ x, y = lp_point.read_array_of_long(2)
43
+ x.should be_an Integer
44
+ x.should be >= 0
45
+ y.should be_an Integer
46
+ y.should be >= 0
47
+ end
48
+
49
+ it "snake_case api returns the cursor's position, in screen coordinates" do
50
+ x, y = get_cursor_pos()
51
+ x.should be_an Integer
52
+ x.should be >= 0
53
+ y.should be_an Integer
54
+ y.should be >= 0
55
+ end
56
+ end # describe get_cursor_pos
34
57
 
35
58
  describe '#set_cursor_pos' do
59
+ spec { use {success = SetCursorPos(x=0, y=0)}}
36
60
  spec { use {success = set_cursor_pos(x=0, y=0)}}
37
- it 'how to test set_cursor_pos?'
38
- end
39
- end
61
+
62
+ it 'sets cursor`s position, in screen coordinates' do
63
+ SetCursorPos(x=600, y=600).should be_true
64
+ get_cursor_pos().should == [600,600]
65
+ set_cursor_pos(x=0, y=0).should be_true
66
+ get_cursor_pos().should == [0,0]
67
+ end
68
+ end # describe '#set_cursor_pos'
69
+
70
+ end # Win::GUI::Input, ' defines a set of API functions related to user input'
40
71
 
41
72
  describe Win::GUI::Input, ' defines convenience/service methods on top of Windows API' do
42
73
  describe '#keystroke' do
@@ -50,7 +81,7 @@ module WinWindowTest
50
81
  2.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
51
82
  end
52
83
  end
53
- end
84
+ end # describe '#keystroke'
54
85
 
55
86
  describe '#type_in' do
56
87
  spec{ use{ type_in(message = '') }}
@@ -63,7 +94,8 @@ module WinWindowTest
63
94
  5.times {keystroke(VK_CONTROL, 'Z'.ord)} # rolling back changes to allow window closing without dialog!
64
95
  end
65
96
  end
66
- end
67
- end
97
+ end # describe '#type_in'
98
+
99
+ end # Win::GUI::Input, ' defines convenience/service methods on top of Windows API'
68
100
  end
69
101
 
@@ -6,33 +6,44 @@ module WinGUIMessageTest
6
6
 
7
7
  include WinTestApp
8
8
  include Win::GUI::Message
9
+ include Win::GUI::Window
9
10
 
10
- describe Win::GUI::Message do
11
+ describe Win::GUI::Message, ' defines a set of API functions related to Window messaging' do
12
+ after(:each){close_test_app if @launched_test_app}
11
13
 
12
14
  describe '#post_message' do
13
- spec{ use{ success = PostMessage(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
14
- spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = 0) }}
15
+ spec{ use{ success = PostMessage(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
16
+ spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
17
+
18
+ it 'places (posts) a message in the message queue associated with the thread that created the specified window' do
19
+ app = launch_test_app
20
+ post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil)
21
+ sleep TEST_SLEEP_DELAY
22
+ window?(app.handle).should == false
23
+ end
15
24
 
16
- it 'places (posts) a message in the message queue associated with the thread that created the specified window'
17
25
  it 'returns without waiting for the thread to process the message'
18
- end
26
+ end # describe '#post_message'
19
27
 
20
28
  describe '#send_message' do
21
29
  spec{ use{ success = SendMessage(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
22
30
  spec{ use{ success = send_message(handle = 0, msg = 0, w_param = 1024, l_param = "\x0"*1024) }}
23
- # handle (L) - Handle to the window whose window procedure is to receive the message. The following values have special meanings.
24
- # HWND_BROADCAST - The message is posted to all top-level windows in the system, including disabled or invisible unowned windows,
25
- # overlapped windows, and pop-up windows. The message is not posted to child windows.
26
- # NULL - The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread.
27
- # msg (L) - Specifies the message to be posted.
28
- # w_param (L) - Specifies additional message-specific information.
29
- # l_param (L) - Specifies additional message-specific information.
30
- # return (L) - Nonzero if success, zero if function failed. To get extended error information, call GetLastError.
31
-
32
- it 'sends the specified message to a window or windows'
33
- it 'calls the window procedure and does not return until the window procedure has processed the message'
34
- end
35
- end
31
+
32
+ it 'sends the specified message to a window or windows' do
33
+ app = launch_test_app
34
+ buffer = FFI::MemoryPointer.new :char, 1024
35
+ num_chars = send_message app.handle, WM_GETTEXT, buffer.size, buffer
36
+ buffer.get_bytes(0, num_chars).should == "LockNote - Steganos LockNote"
37
+
38
+ num_chars = send_message app.textarea, WM_GETTEXT, buffer.size, buffer
39
+ buffer.get_bytes(0, num_chars).should =~ /Welcome to Steganos LockNote/
40
+
41
+ send_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil)
42
+ sleep TEST_SLEEP_DELAY
43
+ window?(app.handle).should == false
44
+ end
45
+ end # describe '#send_message'
46
+ end # Win::GUI::Message, ' defines a set of API functions related to Window messaging'
36
47
  end
37
48
 
38
49
 
@@ -31,7 +31,7 @@ module WinWindowTest
31
31
  end
32
32
  end
33
33
 
34
- describe Win::GUI::Window, ' defines a set user32 API functions related to Window manipulation' do
34
+ describe Win::GUI::Window, ' defines a set of API functions related to Window manipulation' do
35
35
  context 'ensuring test app closes' do
36
36
  after(:each){close_test_app if @launched_test_app}
37
37
 
@@ -15,7 +15,7 @@ module WinLibraryTest
15
15
  when :find_window
16
16
  #api.dll_name.should == 'user32' # The name of the DLL that exports the API function
17
17
  api.effective_function_name.should == 'FindWindowA' # Actual function returned by the constructor: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW'
18
- api.function_name.should == 'FindWindow' # The name of the function passed to the constructor
18
+ api.function_name.should == :FindWindow # The name of the function passed to the constructor
19
19
  api.prototype.should == [:pointer, :pointer] # The prototype, returned as an array of characters
20
20
  api.return_type.should == :ulong # The prototype, returned as an array of characters
21
21
  end
@@ -29,16 +29,16 @@ module WinLibraryTest
29
29
  if n == rights.size
30
30
  expect {send method, *rights}.to_not raise_error
31
31
  else
32
- args = (1..n).map {wrongs[rand(wrongs.size)]}
33
- expect {send method, *args}.
34
- to raise_error "wrong number of arguments (#{args.size} for #{rights.size})"
32
+ args = (1..n).map {wrongs[rand(wrongs.size)]}
33
+ expect {send method, *args}.
34
+ to raise_error "wrong number of arguments (#{args.size} for #{rights.size})"
35
35
  end
36
36
  end
37
37
  end
38
38
  end
39
39
 
40
40
  def any_handle
41
- MyLib.function 'FindWindow', 'PP', 'L' unless respond_to? :find_window
41
+ MyLib.function :FindWindow, 'PP', 'L' unless respond_to? :find_window
42
42
  find_window(nil, nil)
43
43
  end
44
44
 
@@ -80,262 +80,263 @@ module WinLibraryTest
80
80
 
81
81
  before(:each) { hide_method *redefined_methods } # hide original methods if defined
82
82
  after(:each) { restore_method *redefined_methods } # restore original methods if hidden
83
+ context '::function' do
84
+ context 'defining enhanced API function method' do
85
+ spec{ use{ MyLib.function(:FindWindow, 'PP', 'l', rename: nil, aliases: nil, boolean: nil, zeronil: nil, &any_block) }}
86
+
87
+ it 'defines new instance methods with appropriate names' do
88
+ MyLib.function :FindWindow, 'PP', 'L'
89
+ respond_to?(:FindWindow).should be_true
90
+ respond_to?(:find_window).should be_true
91
+ end
83
92
 
84
- context 'defining enhanced API function method' do
85
- spec{ use{ MyLib.function('FindWindow', 'PP', 'l', rename: nil, aliases: nil, boolean: nil, zeronil: nil, &any_block) }}
86
-
87
- it 'defines new instance methods with appropriate names' do
88
- MyLib.function 'FindWindow', 'PP', 'L'
89
- respond_to?(:FindWindow).should be_true
90
- respond_to?(:find_window).should be_true
91
- end
92
-
93
- it 'constructs argument prototype from uppercase string, enforces the args count' do
94
- expect { MyLib.function 'FindWindow', 'PP', 'L' }.to_not raise_error
95
- should_count_args :find_window, :FindWindow, [nil, nil], [nil, TEST_IMPOSSIBLE, 'cmd']
96
- end
93
+ it 'constructs argument prototype from uppercase string, enforces the args count' do
94
+ expect { MyLib.function :FindWindow, 'PP', 'L' }.to_not raise_error
95
+ should_count_args :find_window, :FindWindow, [nil, nil], [nil, TEST_IMPOSSIBLE, 'cmd']
96
+ end
97
97
 
98
- it 'constructs argument prototype from (mixed) array, enforces the args count' do
99
- expect { MyLib.function 'FindWindow', [:pointer, 'P'], 'L' }.to_not raise_error
100
- should_count_args :find_window, :FindWindow, [nil, nil], [nil, TEST_IMPOSSIBLE, 'cmd']
101
- end
98
+ it 'constructs argument prototype from (mixed) array, enforces the args count' do
99
+ expect { MyLib.function :FindWindow, [:pointer, 'P'], 'L' }.to_not raise_error
100
+ should_count_args :find_window, :FindWindow, [nil, nil], [nil, TEST_IMPOSSIBLE, 'cmd']
101
+ end
102
102
 
103
- it 'with :rename option, overrides snake_case name for defined method but leaves CamelCase intact' do
104
- MyLib.function 'FindWindow', 'PP', 'L', :rename=> 'my_own_find'
105
- expect {find_window(nil, nil)}.to raise_error NoMethodError
106
- expect {FindWindow(nil, nil)}.to_not raise_error
107
- expect {my_own_find(nil, nil)}.to_not raise_error
108
- end
103
+ it 'with :rename option, overrides snake_case name for defined method but leaves CamelCase intact' do
104
+ MyLib.function :FindWindow, 'PP', 'L', :rename=> 'my_own_find'
105
+ expect {find_window(nil, nil)}.to raise_error NoMethodError
106
+ expect {FindWindow(nil, nil)}.to_not raise_error
107
+ expect {my_own_find(nil, nil)}.to_not raise_error
108
+ end
109
109
 
110
- it 'defined snake_case method returns expected value when called' do
111
- MyLib.function 'FindWindow', 'PP', 'L'
112
- find_window(nil, nil).should_not == 0
113
- find_window(nil, TEST_IMPOSSIBLE).should == 0
114
- find_window(TEST_IMPOSSIBLE, nil).should == 0
115
- find_window(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == 0
116
- end
110
+ it 'defined snake_case method returns expected value when called' do
111
+ MyLib.function :FindWindow, 'PP', 'L'
112
+ find_window(nil, nil).should_not == 0
113
+ find_window(nil, TEST_IMPOSSIBLE).should == 0
114
+ find_window(TEST_IMPOSSIBLE, nil).should == 0
115
+ find_window(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == 0
116
+ end
117
117
 
118
- it 'defined CamelCase method returns expected value when called' do
119
- MyLib.function 'FindWindow', 'PP', 'L'
120
- FindWindow(nil, nil).should_not == 0
121
- FindWindow(nil, TEST_IMPOSSIBLE).should == 0
122
- FindWindow(TEST_IMPOSSIBLE, nil).should == 0
123
- FindWindow(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == 0
124
- end
118
+ it 'defined CamelCase method returns expected value when called' do
119
+ MyLib.function :FindWindow, 'PP', 'L'
120
+ FindWindow(nil, nil).should_not == 0
121
+ FindWindow(nil, TEST_IMPOSSIBLE).should == 0
122
+ FindWindow(TEST_IMPOSSIBLE, nil).should == 0
123
+ FindWindow(TEST_IMPOSSIBLE, TEST_IMPOSSIBLE).should == 0
124
+ end
125
125
 
126
126
  # it 'returns underlying Win32::API object if defined method is called with (:api) argument ' do
127
- # MyLib.function 'FindWindow', 'PP', 'L'
127
+ # MyLib.function :FindWindow, 'PP', 'L'
128
128
  # expect {find_window(:api)}.to_not raise_error
129
129
  # should_be :find_window, find_window(:api)
130
130
  # end
131
131
 
132
- it 'returns underlying Win32::API object' do
133
- FWAPI = MyLib.function 'FindWindow', 'PP', 'L'
134
- should_be :find_window, FWAPI
132
+ it 'returns underlying Win32::API object' do
133
+ FWAPI = MyLib.function :FindWindow, 'PP', 'L'
134
+ should_be :find_window, FWAPI
135
+ end
135
136
  end
136
- end
137
137
 
138
- context 'defining aliases' do
139
- it 'adds alias for defined method with :alias option' do
140
- MyLib.function( 'FindWindow', 'PP', 'L', :alias => 'my_own_find')
141
- expect {find_window(nil, nil)}.to_not raise_error
142
- expect {my_own_find(nil, nil)}.to_not raise_error
143
- end
138
+ context 'defining aliases' do
139
+ it 'adds alias for defined method with :alias option' do
140
+ MyLib.function( :FindWindow, 'PP', 'L', :alias => 'my_own_find')
141
+ expect {find_window(nil, nil)}.to_not raise_error
142
+ expect {my_own_find(nil, nil)}.to_not raise_error
143
+ end
144
144
 
145
- it 'adds aliases for defined method with :aliases option' do
146
- MyLib.function 'FindWindow', 'PP', 'L', :aliases => ['my_own_find', 'my_own_find1']
147
- expect {find_window(nil, nil)}.to_not raise_error
148
- expect {my_own_find(nil, nil)}.to_not raise_error
149
- expect {my_own_find1(nil, nil)}.to_not raise_error
150
- end
145
+ it 'adds aliases for defined method with :aliases option' do
146
+ MyLib.function :FindWindow, 'PP', 'L', :aliases => ['my_own_find', 'my_own_find1']
147
+ expect {find_window(nil, nil)}.to_not raise_error
148
+ expect {my_own_find(nil, nil)}.to_not raise_error
149
+ expect {my_own_find1(nil, nil)}.to_not raise_error
150
+ end
151
151
 
152
- it 'adds Rubyesque alias to IsXxx API test function' do
153
- MyLib.function 'IsWindow', 'L', 'B'
154
- respond_to?(:window?).should be_true
155
- respond_to?(:is_window).should be_true
156
- end
152
+ it 'adds Rubyesque alias to IsXxx API test function' do
153
+ MyLib.function 'IsWindow', 'L', 'B'
154
+ respond_to?(:window?).should be_true
155
+ respond_to?(:is_window).should be_true
156
+ end
157
157
 
158
- it 'adds Rubyesque alias to GetXxx API getter function' do
159
- MyLib.function 'GetComputerName', 'PP', 'I', :dll=> 'kernel32'
160
- respond_to?(:get_computer_name).should be_true
161
- respond_to?(:computer_name).should be_true
158
+ it 'adds Rubyesque alias to GetXxx API getter function' do
159
+ MyLib.function 'GetComputerName', 'PP', 'I', :dll=> 'kernel32'
160
+ respond_to?(:get_computer_name).should be_true
161
+ respond_to?(:computer_name).should be_true
162
+ end
162
163
  end
163
- end
164
164
 
165
- context 'defining API with :boolean option converts result to boolean' do
166
- before(:each) { MyLib.function 'FindWindow', 'PP', 'L', :boolean => true }
165
+ context 'defining API with :boolean option converts result to boolean' do
166
+ before(:each) { MyLib.function :FindWindow, 'PP', 'L', :boolean => true }
167
167
 
168
- it 'defines new instance method' do
169
- respond_to?(:find_window).should be_true
170
- respond_to?(:FindWindow).should be_true
171
- end
168
+ it 'defines new instance method' do
169
+ respond_to?(:find_window).should be_true
170
+ respond_to?(:FindWindow).should be_true
171
+ end
172
172
 
173
- it 'defined snake_case method returns false/true instead of zero/non-zero' do
174
- find_window(nil, nil).should == true
175
- find_window(nil, TEST_IMPOSSIBLE).should == false
176
- end
173
+ it 'defined snake_case method returns false/true instead of zero/non-zero' do
174
+ find_window(nil, nil).should == true
175
+ find_window(nil, TEST_IMPOSSIBLE).should == false
176
+ end
177
177
 
178
- it 'defined CamelCase method still returns zero/non-zero' do
179
- FindWindow(nil, nil).should_not == true
180
- FindWindow(nil, nil).should_not == 0
181
- FindWindow(nil, TEST_IMPOSSIBLE).should == 0
182
- end
178
+ it 'defined CamelCase method still returns zero/non-zero' do
179
+ FindWindow(nil, nil).should_not == true
180
+ FindWindow(nil, nil).should_not == 0
181
+ FindWindow(nil, TEST_IMPOSSIBLE).should == 0
182
+ end
183
183
 
184
- it 'defined methods enforce the argument count' do
185
- should_count_args :find_window, :FindWindow, [nil, nil], [nil, TEST_IMPOSSIBLE, 'cmd']
184
+ it 'defined methods enforce the argument count' do
185
+ should_count_args :find_window, :FindWindow, [nil, nil], [nil, TEST_IMPOSSIBLE, 'cmd']
186
+ end
186
187
  end
187
- end
188
188
 
189
- context 'defining API with :zeronil option converts zero result to nil' do
190
- before(:each) {MyLib.function 'FindWindow', 'PP', 'L', :zeronil => true}
189
+ context 'defining API with :zeronil option converts zero result to nil' do
190
+ before(:each) {MyLib.function :FindWindow, 'PP', 'L', :zeronil => true}
191
191
 
192
- it 'defines new instance method' do
193
- respond_to?(:find_window).should be_true
194
- respond_to?(:FindWindow).should be_true
195
- end
192
+ it 'defines new instance method' do
193
+ respond_to?(:find_window).should be_true
194
+ respond_to?(:FindWindow).should be_true
195
+ end
196
196
 
197
- it 'defined CamelCase method still returns zero/non-zero' do
198
- FindWindow(nil, nil).should_not == true
199
- FindWindow(nil, nil).should_not == 0
200
- FindWindow(nil, TEST_IMPOSSIBLE).should == 0
201
- end
197
+ it 'defined CamelCase method still returns zero/non-zero' do
198
+ FindWindow(nil, nil).should_not == true
199
+ FindWindow(nil, nil).should_not == 0
200
+ FindWindow(nil, TEST_IMPOSSIBLE).should == 0
201
+ end
202
202
 
203
- it 'defined method returns nil (but NOT false) instead of zero' do
204
- find_window(nil, TEST_IMPOSSIBLE).should_not == false
205
- find_window(nil, TEST_IMPOSSIBLE).should == nil
206
- end
203
+ it 'defined method returns nil (but NOT false) instead of zero' do
204
+ find_window(nil, TEST_IMPOSSIBLE).should_not == false
205
+ find_window(nil, TEST_IMPOSSIBLE).should == nil
206
+ end
207
207
 
208
- it 'defined method does not return true when result is non-zero' do
209
- find_window(nil, nil).should_not == true
210
- find_window(nil, nil).should_not == 0
211
- end
208
+ it 'defined method does not return true when result is non-zero' do
209
+ find_window(nil, nil).should_not == true
210
+ find_window(nil, nil).should_not == 0
211
+ end
212
212
 
213
- it 'defined methods enforce the argument count' do
214
- should_count_args :find_window, :FindWindow, [nil, nil], [nil, TEST_IMPOSSIBLE, 'cmd']
213
+ it 'defined methods enforce the argument count' do
214
+ should_count_args :find_window, :FindWindow, [nil, nil], [nil, TEST_IMPOSSIBLE, 'cmd']
215
+ end
215
216
  end
216
- end
217
217
 
218
- context 'using DLL other than default user32 with :dll option' do
219
- before(:each) {MyLib.function 'GetComputerName', 'PP', 'I', :dll=> 'kernel32'}
218
+ context 'using DLL other than default user32 with :dll option' do
219
+ before(:each) {MyLib.function 'GetComputerName', 'PP', 'I', :dll=> 'kernel32'}
220
220
 
221
- it 'defines new instance method with appropriate name' do
222
- respond_to?(:GetComputerName).should be_true
223
- respond_to?(:get_computer_name).should be_true
224
- respond_to?(:computer_name).should be_true
225
- end
221
+ it 'defines new instance method with appropriate name' do
222
+ respond_to?(:GetComputerName).should be_true
223
+ respond_to?(:get_computer_name).should be_true
224
+ respond_to?(:computer_name).should be_true
225
+ end
226
226
 
227
- it 'returns expected result' do
228
- MyLib.function 'GetComputerName', ['P', 'P'], 'I', :dll=> 'kernel32'
229
- hostname = `hostname`.strip.upcase
230
- name = " " * 128
231
- get_computer_name(name, "128")
232
- name.unpack("A*").first.should == hostname
227
+ it 'returns expected result' do
228
+ MyLib.function 'GetComputerName', ['P', 'P'], 'I', :dll=> 'kernel32'
229
+ hostname = `hostname`.strip.upcase
230
+ name = " " * 128
231
+ get_computer_name(name, "128")
232
+ name.unpack("A*").first.should == hostname
233
+ end
233
234
  end
234
- end
235
235
 
236
- context 'trying to define an invalid API function' do
237
- it 'raises error when trying to define function with a wrong function name' do
238
- expect { MyLib.function 'FindWindowImpossible', 'PP', 'L' }.
239
- to raise_error( /Function 'FindWindowImpossible' not found/ )
236
+ context 'trying to define an invalid API function' do
237
+ it 'raises error when trying to define function with a wrong function name' do
238
+ expect { MyLib.function 'FindWindowImpossible', 'PP', 'L' }.
239
+ to raise_error( /Function 'FindWindowImpossible' not found/ )
240
+ end
240
241
  end
241
- end
242
242
 
243
- context 'defining API function using definition block' do
244
- it 'defines new instance method' do
245
- MyLib.function( 'FindWindow', 'PP', 'L' ){|api, *args|}
246
- respond_to?(:find_window).should be_true
247
- respond_to?(:FindWindow).should be_true
248
- end
243
+ context 'defining API function using definition block' do
244
+ it 'defines new instance method' do
245
+ MyLib.function( :FindWindow, 'PP', 'L' ){|api, *args|}
246
+ respond_to?(:find_window).should be_true
247
+ respond_to?(:FindWindow).should be_true
248
+ end
249
249
 
250
- it 'does not enforce argument count outside of block' do
251
- MyLib.function( 'FindWindow', 'PP', 'L' ){|api, *args|}
252
- expect { find_window }.to_not raise_error
253
- expect { find_window(nil) }.to_not raise_error
254
- expect { find_window(nil, 'Str', 1) }.to_not raise_error
255
- end
250
+ it 'does not enforce argument count outside of block' do
251
+ MyLib.function( :FindWindow, 'PP', 'L' ){|api, *args|}
252
+ expect { find_window }.to_not raise_error
253
+ expect { find_window(nil) }.to_not raise_error
254
+ expect { find_window(nil, 'Str', 1) }.to_not raise_error
255
+ end
256
256
 
257
- it 'returns block return value when defined method is called' do
258
- MyLib.function( 'FindWindow', 'PP', 'L' ){|api, *args| 'Value'}
259
- find_window(nil).should == 'Value'
260
- end
257
+ it 'returns block return value when defined method is called' do
258
+ MyLib.function( :FindWindow, 'PP', 'L' ){|api, *args| 'Value'}
259
+ find_window(nil).should == 'Value'
260
+ end
261
261
 
262
- it 'passes arguments and underlying Win32::API object to the block' do
263
- MyLib.function( 'FindWindow', 'PP', 'L' ) do |api, *args|
264
- @api = api
265
- @args = args
262
+ it 'passes arguments and underlying Win32::API object to the block' do
263
+ MyLib.function( :FindWindow, 'PP', 'L' ) do |api, *args|
264
+ @api = api
265
+ @args = args
266
+ end
267
+ expect {find_window(1, 2, 3) }.to_not raise_error
268
+ @args.should == [1, 2, 3]
269
+ should_be :find_window, @api
266
270
  end
267
- expect {find_window(1, 2, 3) }.to_not raise_error
268
- @args.should == [1, 2, 3]
269
- should_be :find_window, @api
270
- end
271
271
 
272
- it ':rename option overrides standard name for defined method' do
273
- MyLib.function( 'FindWindow', 'PP', 'L', :rename => 'my_own_find' ){|api, *args|}
274
- expect {find_window(nil, nil, nil)}.to raise_error
275
- expect {my_own_find(nil, nil)}.to_not raise_error
276
- end
272
+ it ':rename option overrides standard name for defined method' do
273
+ MyLib.function( :FindWindow, 'PP', 'L', :rename => 'my_own_find' ){|api, *args|}
274
+ expect {find_window(nil, nil, nil)}.to raise_error
275
+ expect {my_own_find(nil, nil)}.to_not raise_error
276
+ end
277
277
 
278
- it 'adds alias for defined method with :alias option' do
279
- MyLib.function( 'FindWindow', 'PP', 'L', :alias => 'my_own_find' ){|api, *args|}
280
- expect {find_window(nil, nil)}.to_not raise_error
281
- expect {my_own_find(nil, nil)}.to_not raise_error
282
- end
278
+ it 'adds alias for defined method with :alias option' do
279
+ MyLib.function( :FindWindow, 'PP', 'L', :alias => 'my_own_find' ){|api, *args|}
280
+ expect {find_window(nil, nil)}.to_not raise_error
281
+ expect {my_own_find(nil, nil)}.to_not raise_error
282
+ end
283
283
 
284
- it 'adds aliases for defined method with :aliases option' do
285
- MyLib.function( 'FindWindow', 'PP', 'L', :aliases => ['my_own_find', 'my_own_find1'] ) {|api, *args|}
286
- expect {find_window(nil, nil)}.to_not raise_error
287
- expect {my_own_find(nil, nil)}.to_not raise_error
288
- expect {my_own_find1(nil, nil)}.to_not raise_error
284
+ it 'adds aliases for defined method with :aliases option' do
285
+ MyLib.function( :FindWindow, 'PP', 'L', :aliases => ['my_own_find', 'my_own_find1'] ) {|api, *args|}
286
+ expect {find_window(nil, nil)}.to_not raise_error
287
+ expect {my_own_find(nil, nil)}.to_not raise_error
288
+ expect {my_own_find1(nil, nil)}.to_not raise_error
289
+ end
289
290
  end
290
- end
291
291
 
292
- context 'calling defined methods with attached block to preprocess the API function results' do
293
- it 'defined method yields raw result to block attached to its invocation' do
294
- MyLib.function 'FindWindow', 'PP', 'L', zeronil: true
295
- find_window(nil, TEST_IMPOSSIBLE) {|result| result.should == 0 }
296
- end
292
+ context 'calling defined methods with attached block to preprocess the API function results' do
293
+ it 'defined method yields raw result to block attached to its invocation' do
294
+ MyLib.function :FindWindow, 'PP', 'L', zeronil: true
295
+ find_window(nil, TEST_IMPOSSIBLE) {|result| result.should == 0 }
296
+ end
297
297
 
298
- it 'defined method returns result of block attached to its invocation' do
299
- MyLib.function 'FindWindow', 'PP', 'L', zeronil: true
300
- return_value = find_window(nil, TEST_IMPOSSIBLE) {|result| 'Value'}
301
- return_value.should == 'Value'
302
- end
298
+ it 'defined method returns result of block attached to its invocation' do
299
+ MyLib.function :FindWindow, 'PP', 'L', zeronil: true
300
+ return_value = find_window(nil, TEST_IMPOSSIBLE) {|result| 'Value'}
301
+ return_value.should == 'Value'
302
+ end
303
303
 
304
- it 'defined method transforms result of block before returning it' do
305
- MyLib.function 'FindWindow', 'PP', 'L', zeronil: true
306
- return_value = find_window(nil, TEST_IMPOSSIBLE) {|result| 0 }
307
- return_value.should_not == 0
308
- return_value.should == nil
304
+ it 'defined method transforms result of block before returning it' do
305
+ MyLib.function :FindWindow, 'PP', 'L', zeronil: true
306
+ return_value = find_window(nil, TEST_IMPOSSIBLE) {|result| 0 }
307
+ return_value.should_not == 0
308
+ return_value.should == nil
309
+ end
309
310
  end
310
- end
311
311
 
312
- context 'defining API function without arguments - f(VOID)' do
313
- it 'should enforce argument count to 0, NOT 1' do
314
- MyLib.function 'GetForegroundWindow', [], 'L', zeronil: true
315
- should_count_args :GetForegroundWindow, :get_foreground_window, :foreground_window, [], [nil, 0, 123]
312
+ context 'defining API function without arguments - f(VOID)' do
313
+ it 'should enforce argument count to 0, NOT 1' do
314
+ MyLib.function :GetForegroundWindow, [], 'L', zeronil: true
315
+ should_count_args :GetForegroundWindow, :get_foreground_window, :foreground_window, [], [nil, 0, 123]
316
+ end
316
317
  end
317
- end
318
+ end
318
319
 
319
- context 'working with API function callbacks' do
320
- it '#callback method creates a valid callback object' do
321
- pending 'What about callbacks?'
322
- expect { @callback = WinGui.callback('LP', 'I') {|handle, message| true} }.to_not raise_error
323
- @callback.should be_a_kind_of(Win32::API::Callback)
320
+ context '::callback defining API callback TYPES' do
321
+ it '#callback macro creates a valid callback definition' do
322
+ expect { MyLib.callback :MyEnumWindowsProc, [:HWND, :long], :bool}.to_not raise_error
324
323
  end
325
324
 
326
- it 'created callback object can be used as a valid arg of API function expecting callback' do
327
- pending 'What about callbacks?'
328
- MyLib.function 'EnumWindows', 'KP', 'L'
329
- @callback = WinGui.callback('LP', 'I'){|handle, message| true }
330
- expect { enum_windows(@callback, 'Message') }.to_not raise_error
325
+ it 'created callback definition can be used to define API function expecting callback' do
326
+ expect {MyLib.function :EnumWindows, [:MyEnumWindowsProc, :long], :long}.to_not raise_error
327
+ expect { enum_windows(lambda{|handle, message| true }, 0) }.to_not raise_error
331
328
  end
329
+ end
332
330
 
333
- it 'defined API functions expecting callback convert given block into callback' do
334
- pending 'What about callbacks?'
335
- pending ' What about prototype!? API is not exactly clear atm (.with_callback method?)'
336
- MyLib.function 'EnumWindows', 'KP', 'L'
337
- expect { enum_windows('Message'){|handle, message| true } }.to_not raise_error
331
+ context '::try_function to define API function that are platform-specific' do
332
+ if xp?
333
+ it 'should silently fail to define function not present on current platform' do
334
+ expect {MyLib.function :GetErrorMode, [], :UINT}.to raise_error /Function 'GetErrorMode' not found/
335
+ expect {MyLib.try_function :GetErrorMode, [], :UINT}.to_not raise_error
336
+ expect { GetErrorMode() }.to raise_error /undefined method `GetErrorMode'/
337
+ expect { get_error_mode() }.to raise_error /undefined method `get_error_mode'/
338
+ end
338
339
  end
339
340
  end
340
341
  end
341
- end
342
+ end
data/win.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{win}
8
- s.version = "0.1.16"
8
+ s.version = "0.1.18"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["arvicco"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: win
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.16
4
+ version: 0.1.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - arvicco