win 0.1.16 → 0.1.18
Sign up to get free protection for your applications and to get access to all the features.
- 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