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 +1 -1
- data/lib/win/error.rb +160 -2
- data/lib/win/gui.rb +0 -1
- data/lib/win/gui/dialog.rb +9 -9
- data/lib/win/gui/input.rb +32 -0
- data/lib/win/gui/message.rb +1 -1
- data/lib/win/gui/window.rb +4 -4
- data/lib/win/library.rb +10 -1
- data/spec/spec_helper.rb +12 -0
- data/spec/win/error_spec.rb +70 -11
- data/spec/win/gui/dialog_spec.rb +20 -34
- data/spec/win/gui/input_spec.rb +41 -9
- data/spec/win/gui/message_spec.rb +29 -18
- data/spec/win/gui/window_spec.rb +1 -1
- data/spec/win/library_spec.rb +206 -205
- data/win.gemspec +1 -1
- metadata +1 -1
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
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
|
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
data/lib/win/gui/dialog.rb
CHANGED
@@ -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
|
##
|
data/lib/win/gui/message.rb
CHANGED
@@ -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, :
|
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
|
data/lib/win/gui/window.rb
CHANGED
@@ -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], :
|
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], :
|
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], :
|
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,
|
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
|
data/spec/win/error_spec.rb
CHANGED
@@ -8,7 +8,11 @@ module WinErrorTest
|
|
8
8
|
include Win::GUI::Window
|
9
9
|
|
10
10
|
def buffer
|
11
|
-
FFI::MemoryPointer.new(:char,
|
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(
|
37
|
-
spec{ use{ message = format_message(
|
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
|
40
|
-
|
41
|
-
|
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
|
45
|
-
|
46
|
-
message = format_message(
|
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
|
data/spec/win/gui/dialog_spec.rb
CHANGED
@@ -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
|
data/spec/win/gui/input_spec.rb
CHANGED
@@ -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
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
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 =
|
14
|
-
spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param =
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
|
data/spec/win/gui/window_spec.rb
CHANGED
@@ -31,7 +31,7 @@ module WinWindowTest
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
describe Win::GUI::Window, ' defines a set
|
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
|
|
data/spec/win/library_spec.rb
CHANGED
@@ -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 ==
|
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
|
-
|
33
|
-
|
34
|
-
|
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
|
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
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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
|
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
|
-
|
133
|
-
|
134
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
166
|
-
|
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
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
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
|
-
|
185
|
-
|
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
|
-
|
190
|
-
|
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
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
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
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
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
|
-
|
214
|
-
|
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
|
-
|
219
|
-
|
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
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
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
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
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
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
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
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
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
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
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
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
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
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
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
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
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
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
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
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
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
|
-
|
318
|
+
end
|
318
319
|
|
319
|
-
context '
|
320
|
-
it '#callback
|
321
|
-
|
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
|
327
|
-
|
328
|
-
|
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
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
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