win32-api 1.1.0-x86-mswin32-60 → 1.2.0-x86-mswin32-60
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/CHANGES +9 -0
- data/README +11 -6
- data/ext/win32/api.c +67 -28
- data/lib/win32/api.so +0 -0
- data/test/test_win32_api.rb +35 -3
- metadata +10 -10
- data/ext/extconf.rb +0 -11
data/CHANGES
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
= 1.2.0 - 22-Jul-2008
|
2
|
+
* Added support for the 'S' (string) prototype and return type. It can be
|
3
|
+
used instead of 'P' (pointer) for const char*.
|
4
|
+
* Some internal refactoring. The attempts to load ANSI and/or Wide character
|
5
|
+
versions of functions are skipped for MSVCRT functions, since they do not
|
6
|
+
exist. This eliminates some unnecessary LoadLibrary() calls.
|
7
|
+
* Added a couple of gem building Rake tasks.
|
8
|
+
* Added a few more tests.
|
9
|
+
|
1
10
|
= 1.1.0 - 12-Jun-2008
|
2
11
|
* Added the Windows::API::Function class. This is a subclass of Win32::API
|
3
12
|
meant only for use with raw function pointers.
|
data/README
CHANGED
@@ -39,10 +39,12 @@
|
|
39
39
|
= Differences between win32-api and Win32API
|
40
40
|
* This library has callback support
|
41
41
|
* This library supports raw function pointers.
|
42
|
+
* This library supports a separate string type for const char* (S).
|
42
43
|
* Argument order change. The DLL name is now last, not first.
|
43
|
-
* Removed the 'N' and 'n'. Always use 'L' for longs now.
|
44
|
+
* Removed the 'N' and 'n' prototypes. Always use 'L' for longs now.
|
44
45
|
* Sensible default arguments for the prototype, return type and DLL name.
|
45
|
-
* Reader methods for the function name,
|
46
|
+
* Reader methods for the function name, effective function name, prototype,
|
47
|
+
return type and DLL.
|
46
48
|
* Removed the support for lower case prototype and return types. Always
|
47
49
|
use capital letters.
|
48
50
|
* Resorts to wide character functions (where possible) when $KCODE is set
|
@@ -82,9 +84,12 @@
|
|
82
84
|
implied warranties, including, without limitation, the implied
|
83
85
|
warranties of merchantability and fitness for a particular purpose.
|
84
86
|
|
85
|
-
= Known
|
86
|
-
|
87
|
-
|
87
|
+
= Known Issues
|
88
|
+
Possible callback issues when dealing with multi-threaded applications.
|
89
|
+
We are working on this for the next 1.2.x release.
|
90
|
+
|
91
|
+
Please submit any bug reports to the project page at
|
92
|
+
http://www.rubyforge.org/projects/win32utils.
|
88
93
|
|
89
94
|
= Copyright
|
90
95
|
(C) 2003-2008 Daniel J. Berger
|
@@ -95,4 +100,4 @@
|
|
95
100
|
|
96
101
|
= Authors
|
97
102
|
Daniel J. Berger
|
98
|
-
Park Heesob
|
103
|
+
Park Heesob
|
data/ext/win32/api.c
CHANGED
@@ -2,13 +2,14 @@
|
|
2
2
|
#include <windows.h>
|
3
3
|
|
4
4
|
#define MAX_BUF 1024
|
5
|
-
#define WINDOWS_API_VERSION "1.
|
5
|
+
#define WINDOWS_API_VERSION "1.2.0"
|
6
6
|
|
7
7
|
#define _T_VOID 0
|
8
8
|
#define _T_LONG 1
|
9
9
|
#define _T_POINTER 2
|
10
10
|
#define _T_INTEGER 3
|
11
11
|
#define _T_CALLBACK 4
|
12
|
+
#define _T_STRING 5
|
12
13
|
|
13
14
|
VALUE cAPIError, cCallbackError;
|
14
15
|
|
@@ -80,8 +81,8 @@ char* StringError(DWORD dwError){
|
|
80
81
|
*
|
81
82
|
* The +prototype+ is the function prototype for the callback function. This
|
82
83
|
* is a string. The possible valid characters are 'I' (integer), 'L' (long),
|
83
|
-
* 'V' (void),
|
84
|
-
* do not have a default prototype.
|
84
|
+
* 'V' (void), 'P' (pointer) or 'S' (string). Unlike API objects, API::Callback
|
85
|
+
* objects do not have a default prototype.
|
85
86
|
*
|
86
87
|
* The +return+ argument is the return type for the callback function. The
|
87
88
|
* valid characters are the same as for the +prototype+. The default is
|
@@ -93,6 +94,7 @@ char* StringError(DWORD dwError){
|
|
93
94
|
*
|
94
95
|
* EnumWindows = API.new('EnumWindows', 'KP', 'L', 'user32')
|
95
96
|
* GetWindowText = API.new('GetWindowText', 'LPI', 'I', 'user32')
|
97
|
+
*
|
96
98
|
* EnumWindowsProc = API::Callback.new('LP', 'I'){ |handle, param|
|
97
99
|
* buf = "\0" * 200
|
98
100
|
* GetWindowText.call(handle, buf, 200);
|
@@ -112,7 +114,7 @@ static VALUE callback_init(int argc, VALUE* argv, VALUE self)
|
|
112
114
|
/* Validate prototype characters */
|
113
115
|
for(i = 0; i < RSTRING(v_proto)->len; i++){
|
114
116
|
switch(RSTRING(v_proto)->ptr[i]){
|
115
|
-
case 'I': case 'L': case 'P': case 'V':
|
117
|
+
case 'I': case 'L': case 'P': case 'V': case 'S':
|
116
118
|
break;
|
117
119
|
default:
|
118
120
|
rb_raise(cCallbackError, "Illegal prototype '%c'",
|
@@ -139,8 +141,13 @@ static VALUE callback_init(int argc, VALUE* argv, VALUE self)
|
|
139
141
|
*
|
140
142
|
* The +prototype+ is the function prototype for +function+. This can be a
|
141
143
|
* string or an array of characters. The possible valid characters are 'I'
|
142
|
-
* (integer), 'L' (long), 'V' (void), 'P' (pointer),
|
144
|
+
* (integer), 'L' (long), 'V' (void), 'P' (pointer), 'K' (callback) or 'S'
|
145
|
+
* (string).
|
146
|
+
*
|
143
147
|
* The default is void ('V').
|
148
|
+
*
|
149
|
+
* Constant (const char*) strings should use 'S'. Pass by reference string
|
150
|
+
* buffers should use 'P'. The former is faster, but cannot be modified.
|
144
151
|
*
|
145
152
|
* The +return+ argument is the return type for the function. The valid
|
146
153
|
* characters are the same as for the +prototype+. The default is 'L' (long).
|
@@ -227,33 +234,44 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
227
234
|
second = "A";
|
228
235
|
}
|
229
236
|
|
237
|
+
// Skip the ANSI and Wide function checks for MSVCRT functions.
|
230
238
|
if(!fProc){
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
+
if(!strcmp(RSTRING(v_dll)->ptr, "msvcrt")){
|
240
|
+
rb_raise(
|
241
|
+
cAPIError,
|
242
|
+
"GetProcAddress() failed for '%s': %s",
|
243
|
+
RSTRING(v_proc)->ptr,
|
244
|
+
StringError(GetLastError())
|
245
|
+
);
|
246
|
+
}
|
247
|
+
else{
|
248
|
+
VALUE v_ascii = rb_str_new3(v_proc);
|
249
|
+
v_ascii = rb_str_cat(v_ascii, first, 1);
|
250
|
+
fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_ascii)->ptr));
|
239
251
|
|
240
252
|
if(!fProc){
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
253
|
+
VALUE v_unicode = rb_str_new3(v_proc);
|
254
|
+
v_unicode = rb_str_cat(v_unicode, second, 1);
|
255
|
+
fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_unicode)->ptr));
|
256
|
+
|
257
|
+
if(!fProc){
|
258
|
+
rb_raise(
|
259
|
+
cAPIError,
|
260
|
+
"GetProcAddress() failed for '%s', '%s' and '%s': %s",
|
261
|
+
RSTRING(v_proc)->ptr,
|
262
|
+
RSTRING(v_ascii)->ptr,
|
263
|
+
RSTRING(v_unicode)->ptr,
|
264
|
+
StringError(GetLastError())
|
265
|
+
);
|
266
|
+
}
|
267
|
+
else{
|
268
|
+
rb_iv_set(self, "@effective_function_name", v_unicode);
|
269
|
+
}
|
249
270
|
}
|
250
271
|
else{
|
251
|
-
rb_iv_set(self, "@effective_function_name",
|
272
|
+
rb_iv_set(self, "@effective_function_name", v_ascii);
|
252
273
|
}
|
253
274
|
}
|
254
|
-
else{
|
255
|
-
rb_iv_set(self, "@effective_function_name", v_ascii);
|
256
|
-
}
|
257
275
|
}
|
258
276
|
else{
|
259
277
|
rb_iv_set(self, "@effective_function_name", v_proc);
|
@@ -281,6 +299,9 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
281
299
|
case 'K':
|
282
300
|
ptr->prototype[i] = _T_CALLBACK;
|
283
301
|
break;
|
302
|
+
case 'S':
|
303
|
+
ptr->prototype[i] = _T_STRING;
|
304
|
+
break;
|
284
305
|
default:
|
285
306
|
rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
|
286
307
|
}
|
@@ -308,6 +329,9 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
308
329
|
case 'V':
|
309
330
|
ptr->return_type = _T_VOID;
|
310
331
|
break;
|
332
|
+
case 'S':
|
333
|
+
ptr->return_type = _T_STRING;
|
334
|
+
break;
|
311
335
|
default:
|
312
336
|
rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
|
313
337
|
}
|
@@ -397,6 +421,9 @@ static VALUE func_init(int argc, VALUE* argv, VALUE self){
|
|
397
421
|
case 'K':
|
398
422
|
ptr->prototype[i] = _T_CALLBACK;
|
399
423
|
break;
|
424
|
+
case 'S':
|
425
|
+
ptr->prototype[i] = _T_STRING;
|
426
|
+
break;
|
400
427
|
default:
|
401
428
|
rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
|
402
429
|
}
|
@@ -424,6 +451,9 @@ static VALUE func_init(int argc, VALUE* argv, VALUE self){
|
|
424
451
|
case 'V':
|
425
452
|
ptr->return_type = _T_VOID;
|
426
453
|
break;
|
454
|
+
case 'S':
|
455
|
+
ptr->return_type = _T_STRING;
|
456
|
+
break;
|
427
457
|
default:
|
428
458
|
rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
|
429
459
|
}
|
@@ -495,6 +525,9 @@ DWORD CallbackFunction(PARAM param)
|
|
495
525
|
case 'L':
|
496
526
|
return NUM2ULONG(v_retval);
|
497
527
|
break;
|
528
|
+
case 'S':
|
529
|
+
return (unsigned long)RSTRING(v_retval)->ptr;
|
530
|
+
break;
|
498
531
|
case 'P':
|
499
532
|
if(NIL_P(v_retval)){
|
500
533
|
return 0;
|
@@ -588,6 +621,9 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
588
621
|
ActiveCallback = v_arg;
|
589
622
|
param.params[i] = (LPARAM)CallbackFunction;
|
590
623
|
break;
|
624
|
+
case _T_STRING:
|
625
|
+
param.params[i] = (unsigned long)RSTRING(v_arg)->ptr;
|
626
|
+
break;
|
591
627
|
default:
|
592
628
|
param.params[i] = NUM2ULONG(v_arg);
|
593
629
|
}
|
@@ -615,6 +651,9 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
615
651
|
else
|
616
652
|
v_return = rb_str_new2((TCHAR*)return_value);
|
617
653
|
break;
|
654
|
+
case _T_STRING:
|
655
|
+
v_return = rb_str_new2((TCHAR*)return_value);
|
656
|
+
break;
|
618
657
|
default:
|
619
658
|
v_return = INT2NUM(0);
|
620
659
|
}
|
@@ -676,7 +715,7 @@ void Init_api(){
|
|
676
715
|
/* The prototype, returned as an array of characters */
|
677
716
|
rb_define_attr(cAPI, "prototype", 1, 0);
|
678
717
|
|
679
|
-
/* The return type, returned as a single character, P, L, I, V or B */
|
718
|
+
/* The return type, returned as a single character, S, P, L, I, V or B */
|
680
719
|
rb_define_attr(cAPI, "return_type", 1, 0);
|
681
720
|
|
682
721
|
/* Win32::API::Callback Instance Methods */
|
@@ -684,7 +723,7 @@ void Init_api(){
|
|
684
723
|
/* The prototype, returned as an array of characters */
|
685
724
|
rb_define_attr(cCallback, "prototype", 1, 0);
|
686
725
|
|
687
|
-
/* The return type, returned as a single character, P, L, I, V or B */
|
726
|
+
/* The return type, returned as a single character, S, P, L, I, V or B */
|
688
727
|
rb_define_attr(cCallback, "return_type", 1, 0);
|
689
728
|
|
690
729
|
/* The numeric address of the function pointer */
|
@@ -692,6 +731,6 @@ void Init_api(){
|
|
692
731
|
|
693
732
|
/* Constants */
|
694
733
|
|
695
|
-
/* 1.
|
734
|
+
/* 1.2.0: The version of this library, returned as a String */
|
696
735
|
rb_define_const(cAPI, "VERSION", rb_str_new2(WINDOWS_API_VERSION));
|
697
736
|
}
|
data/lib/win32/api.so
CHANGED
Binary file
|
data/test/test_win32_api.rb
CHANGED
@@ -13,10 +13,18 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
13
13
|
@buf = 0.chr * 260
|
14
14
|
@api = API.new('GetCurrentDirectory', 'LP')
|
15
15
|
@gle = API.new('GetLastError', 'V', 'L')
|
16
|
+
@str = API.new('strstr', 'PP', 'P', 'msvcrt')
|
16
17
|
end
|
17
18
|
|
18
19
|
def test_version
|
19
|
-
assert_equal('1.
|
20
|
+
assert_equal('1.2.0', API::VERSION)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_constructor_basic
|
24
|
+
assert_nothing_raised{ API.new('GetCurrentDirectory') }
|
25
|
+
assert_nothing_raised{ API.new('GetCurrentDirectory', 'LP') }
|
26
|
+
assert_nothing_raised{ API.new('GetCurrentDirectory', 'LP', 'L') }
|
27
|
+
assert_nothing_raised{ API.new('GetCurrentDirectory', 'LP', 'L', 'kernel32') }
|
20
28
|
end
|
21
29
|
|
22
30
|
def test_call
|
@@ -38,11 +46,13 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
38
46
|
def test_function_name
|
39
47
|
assert_respond_to(@api, :function_name)
|
40
48
|
assert_equal('GetCurrentDirectory', @api.function_name)
|
49
|
+
assert_equal('strstr', @str.function_name)
|
41
50
|
end
|
42
51
|
|
43
52
|
def test_effective_function_name
|
44
53
|
assert_respond_to(@api, :effective_function_name)
|
45
54
|
assert_equal('GetCurrentDirectoryA', @api.effective_function_name)
|
55
|
+
assert_equal('strstr', @str.effective_function_name)
|
46
56
|
|
47
57
|
@api = API.new('GetCurrentDirectoryA', 'LP')
|
48
58
|
assert_equal('GetCurrentDirectoryA', @api.effective_function_name)
|
@@ -68,9 +78,30 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
68
78
|
end
|
69
79
|
|
70
80
|
def test_constructor_expected_failures
|
81
|
+
assert_raise(ArgumentError){ API.new }
|
71
82
|
assert_raise(API::Error){ API.new('GetUserName', 'PL', 'I', 'foo') }
|
72
|
-
assert_raise(API::Error){ API.new('GetUserName', 'X', 'I', '
|
73
|
-
assert_raise(API::Error){ API.new('GetUserName', 'PL', 'X', '
|
83
|
+
assert_raise(API::Error){ API.new('GetUserName', 'X', 'I', 'kernel32') }
|
84
|
+
assert_raise(API::Error){ API.new('GetUserName', 'PL', 'X', 'kernel32') }
|
85
|
+
end
|
86
|
+
|
87
|
+
# Compare MSVCRT error messages vs regular error messages. This validates
|
88
|
+
# that we're skipping the 'A' and 'W' lookups for MSVCRT functions.
|
89
|
+
def test_constructor_expected_failure_messages
|
90
|
+
begin
|
91
|
+
API.new('GetBlah')
|
92
|
+
rescue API::Error => err
|
93
|
+
expected = "GetProcAddress() failed for 'GetBlah', 'GetBlahA' and "
|
94
|
+
expected += "'GetBlahW': The specified procedure could not be found."
|
95
|
+
assert_equal(expected, err.to_s)
|
96
|
+
end
|
97
|
+
|
98
|
+
begin
|
99
|
+
API.new('strxxx', 'P', 'P', 'msvcrt')
|
100
|
+
rescue API::Error => err
|
101
|
+
expected = "GetProcAddress() failed for 'strxxx': The specified "
|
102
|
+
expected += "procedure could not be found."
|
103
|
+
assert_equal(expected, err.to_s)
|
104
|
+
end
|
74
105
|
end
|
75
106
|
|
76
107
|
def test_call_expected_failures
|
@@ -81,5 +112,6 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
81
112
|
@buf = nil
|
82
113
|
@api = nil
|
83
114
|
@gle = nil
|
115
|
+
@str = nil
|
84
116
|
end
|
85
117
|
end
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: x86-mswin32-60
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
8
|
+
- Park Heesob
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date: 2008-
|
13
|
+
date: 2008-07-22 00:00:00 -06:00
|
13
14
|
default_executable:
|
14
15
|
dependencies: []
|
15
16
|
|
@@ -25,17 +26,14 @@ extra_rdoc_files:
|
|
25
26
|
- MANIFEST
|
26
27
|
- ext/win32/api.c
|
27
28
|
files:
|
28
|
-
-
|
29
|
-
- ext/win32
|
30
|
-
- ext/win32/api.c
|
29
|
+
- lib/win32/api.so
|
31
30
|
- test/test_win32_api.rb
|
32
31
|
- test/test_win32_api_callback.rb
|
33
32
|
- test/test_win32_api_function.rb
|
34
|
-
- lib/win32
|
35
|
-
- lib/win32/api.so
|
36
33
|
- README
|
37
34
|
- CHANGES
|
38
35
|
- MANIFEST
|
36
|
+
- ext/win32/api.c
|
39
37
|
has_rdoc: true
|
40
38
|
homepage: http://www.rubyforge.org/projects/win32utils
|
41
39
|
post_install_message:
|
@@ -58,9 +56,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
56
|
requirements: []
|
59
57
|
|
60
58
|
rubyforge_project: win32utils
|
61
|
-
rubygems_version: 1.
|
59
|
+
rubygems_version: 1.2.0
|
62
60
|
signing_key:
|
63
61
|
specification_version: 2
|
64
62
|
summary: A superior replacement for Win32API
|
65
|
-
test_files:
|
66
|
-
|
63
|
+
test_files:
|
64
|
+
- test/test_win32_api.rb
|
65
|
+
- test/test_win32_api_callback.rb
|
66
|
+
- test/test_win32_api_function.rb
|
data/ext/extconf.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
##########################################################################
|
2
|
-
# extconf.rb
|
3
|
-
#
|
4
|
-
# The Windows::API binary should be built using the Rake task, i.e.
|
5
|
-
# 'rake build' or 'rake install'.
|
6
|
-
##########################################################################
|
7
|
-
require 'mkmf'
|
8
|
-
|
9
|
-
have_func('strncpy_s')
|
10
|
-
|
11
|
-
create_makefile('win32/api', 'win32')
|