win32-api 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +9 -0
- data/README +11 -6
- data/ext/win32/api.c +67 -28
- data/test/test_win32_api.rb +35 -3
- metadata +8 -7
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/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: ruby
|
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,8 +26,6 @@ extra_rdoc_files:
|
|
25
26
|
- MANIFEST
|
26
27
|
- ext/win32/api.c
|
27
28
|
files:
|
28
|
-
- ext/extconf.rb
|
29
|
-
- ext/win32
|
30
29
|
- ext/win32/api.c
|
31
30
|
- test/test_win32_api.rb
|
32
31
|
- test/test_win32_api_callback.rb
|
@@ -56,9 +55,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
55
|
requirements: []
|
57
56
|
|
58
57
|
rubyforge_project: win32utils
|
59
|
-
rubygems_version: 1.
|
58
|
+
rubygems_version: 1.2.0
|
60
59
|
signing_key:
|
61
60
|
specification_version: 2
|
62
61
|
summary: A superior replacement for Win32API
|
63
|
-
test_files:
|
64
|
-
|
62
|
+
test_files:
|
63
|
+
- test/test_win32_api.rb
|
64
|
+
- test/test_win32_api_callback.rb
|
65
|
+
- test/test_win32_api_function.rb
|