win32-api 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +35 -0
- data/MANIFEST +9 -9
- data/README +1 -1
- data/ext/win32/api.c +266 -125
- data/test/test_win32_api.rb +62 -44
- data/test/test_win32_api_callback.rb +17 -1
- data/test/test_win32_api_function.rb +19 -1
- metadata +3 -3
data/CHANGES
CHANGED
@@ -1,3 +1,38 @@
|
|
1
|
+
= 1.3.0 - 1-Jan-2009
|
2
|
+
* Fixed RubyForge bug #23395, which was caused by inadvertently modifying
|
3
|
+
a variable within a loop. This caused callbacks to fail in certain
|
4
|
+
situations.
|
5
|
+
* Added the Win32::API::LoadLibraryError and Win32::API::PrototypeError classes
|
6
|
+
to provide more fine grained handling of possible error conditions in the
|
7
|
+
constructor. These are both subclasses of Win32::API::Error.
|
8
|
+
* Removed the Win32::API::CallbackError class.
|
9
|
+
* Changed the upper limit on prototypes from 16 to 20. It turns out that
|
10
|
+
there are actually Windows functions with more than 16 prototypes.
|
11
|
+
* Refactored a high iteration test so that it counts as only one test
|
12
|
+
instead of 1000.
|
13
|
+
|
14
|
+
= 1.2.2 - 27-Nov-2008
|
15
|
+
* Fixed bug in the error message for illegal prototypes and illegal return
|
16
|
+
types where the character in question would come out as empty or garbage.
|
17
|
+
* Passing a bad return type to Win32::API::Callback now raises an error.
|
18
|
+
* Updated the error message for illegal return types to say, "Illegal return
|
19
|
+
type" instead of "Illegal prototype" as it did previously.
|
20
|
+
* The error message for a bad function name passed to Win32::API.new now
|
21
|
+
matches JRuby's FFI error message.
|
22
|
+
* Improved the handling of msvcrt functions with regards to skipping 'A'
|
23
|
+
and 'W' checks. Previously it was checking against the literal string
|
24
|
+
'msvcrt'. Now it checks against any string that starts with 'msvcr'.
|
25
|
+
* Added test-unit 2.x as a prerequisite.
|
26
|
+
* Added tests for the Win32::API::Callback#address method.
|
27
|
+
* Added tests to all Win32::API classes that explicitly check error messages.
|
28
|
+
|
29
|
+
= 1.2.1 - 14-Nov-2008
|
30
|
+
* Fixed and updated callback handling.
|
31
|
+
* Fixed wide string return handling for pointers and strings.
|
32
|
+
* Added the Win32::API::Callback#address instance method.
|
33
|
+
* All errors are now in English instead of your native language, because
|
34
|
+
that's what Ruby itself does.
|
35
|
+
|
1
36
|
= 1.2.0 - 22-Jul-2008
|
2
37
|
* Added support for the 'S' (string) prototype and return type. It can be
|
3
38
|
used instead of 'P' (pointer) for const char*.
|
data/MANIFEST
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
* CHANGES
|
2
|
-
* MANIFEST
|
3
|
-
* README
|
4
|
-
* Rakefile
|
5
|
-
* win32-api.gemspec
|
6
|
-
* ext/extconf.rb
|
7
|
-
* ext/win32/api.c
|
8
|
-
* test/test_win32_api.rb
|
9
|
-
* test/test_win32_api_callback.rb
|
1
|
+
* CHANGES
|
2
|
+
* MANIFEST
|
3
|
+
* README
|
4
|
+
* Rakefile
|
5
|
+
* win32-api.gemspec
|
6
|
+
* ext/extconf.rb
|
7
|
+
* ext/win32/api.c
|
8
|
+
* test/test_win32_api.rb
|
9
|
+
* test/test_win32_api_callback.rb
|
10
10
|
* test/test_win32_api_function.rb
|
data/README
CHANGED
@@ -70,7 +70,7 @@
|
|
70
70
|
instance variable names with proper accessors, removing support for lower
|
71
71
|
case prototype and return value characters that no one used in practice,
|
72
72
|
better naming conventions, the addition of RDoc ready comments and,
|
73
|
-
especially, callback support.
|
73
|
+
especially, callback and raw function pointer support.
|
74
74
|
|
75
75
|
Most importantly, we can now add, modify and fix any features that we feel
|
76
76
|
best benefit our end users.
|
data/ext/win32/api.c
CHANGED
@@ -2,7 +2,7 @@
|
|
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.3.0"
|
6
6
|
|
7
7
|
#define _T_VOID 0
|
8
8
|
#define _T_LONG 1
|
@@ -11,13 +11,14 @@
|
|
11
11
|
#define _T_CALLBACK 4
|
12
12
|
#define _T_STRING 5
|
13
13
|
|
14
|
-
VALUE cAPIError,
|
14
|
+
VALUE cAPIError, cAPIProtoError, cAPILoadError;
|
15
|
+
static VALUE ActiveCallback = Qnil;
|
15
16
|
|
16
17
|
typedef struct {
|
17
18
|
HANDLE library;
|
18
19
|
FARPROC function;
|
19
20
|
int return_type;
|
20
|
-
int prototype[
|
21
|
+
int prototype[20];
|
21
22
|
} Win32API;
|
22
23
|
|
23
24
|
static void api_free(Win32API* ptr){
|
@@ -34,7 +35,10 @@ static VALUE api_allocate(VALUE klass){
|
|
34
35
|
}
|
35
36
|
|
36
37
|
/* Helper function that converts the error number returned by GetLastError()
|
37
|
-
* into a human readable string.
|
38
|
+
* into a human readable string. Note that we always use English for error
|
39
|
+
* output because that's what Ruby itself does.
|
40
|
+
*
|
41
|
+
* Internal use only.
|
38
42
|
*/
|
39
43
|
char* StringError(DWORD dwError){
|
40
44
|
LPVOID lpMsgBuf;
|
@@ -48,7 +52,7 @@ char* StringError(DWORD dwError){
|
|
48
52
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
49
53
|
NULL,
|
50
54
|
dwError,
|
51
|
-
MAKELANGID(
|
55
|
+
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
52
56
|
(LPSTR)&lpMsgBuf,
|
53
57
|
0,
|
54
58
|
NULL
|
@@ -74,71 +78,86 @@ char* StringError(DWORD dwError){
|
|
74
78
|
/*
|
75
79
|
* call-seq:
|
76
80
|
* Win32::API::Callback.new(prototype, return='L'){ |proto| ... }
|
77
|
-
*
|
81
|
+
*
|
78
82
|
* Creates and returns a new Win32::API::Callback object. The prototype
|
79
83
|
* arguments are yielded back to the block in the same order they were
|
80
84
|
* declared.
|
81
|
-
*
|
85
|
+
*
|
82
86
|
* The +prototype+ is the function prototype for the callback function. This
|
83
87
|
* is a string. The possible valid characters are 'I' (integer), 'L' (long),
|
84
88
|
* 'V' (void), 'P' (pointer) or 'S' (string). Unlike API objects, API::Callback
|
85
89
|
* objects do not have a default prototype.
|
86
|
-
*
|
90
|
+
*
|
87
91
|
* The +return+ argument is the return type for the callback function. The
|
88
92
|
* valid characters are the same as for the +prototype+. The default is
|
89
93
|
* 'L' (long).
|
90
|
-
*
|
94
|
+
*
|
91
95
|
* Example:
|
92
96
|
* require 'win32/api'
|
93
97
|
* include Win32
|
94
|
-
*
|
98
|
+
*
|
95
99
|
* EnumWindows = API.new('EnumWindows', 'KP', 'L', 'user32')
|
96
100
|
* GetWindowText = API.new('GetWindowText', 'LPI', 'I', 'user32')
|
97
|
-
*
|
101
|
+
*
|
98
102
|
* EnumWindowsProc = API::Callback.new('LP', 'I'){ |handle, param|
|
99
103
|
* buf = "\0" * 200
|
100
104
|
* GetWindowText.call(handle, buf, 200);
|
101
105
|
* puts buf.strip unless buf.strip.empty?
|
102
106
|
* buf.index(param).nil? ? true : false
|
103
107
|
* }
|
104
|
-
*
|
108
|
+
*
|
105
109
|
* EnumWindows.call(EnumWindowsProc, 'UEDIT32')
|
106
110
|
*/
|
107
111
|
static VALUE callback_init(int argc, VALUE* argv, VALUE self)
|
108
112
|
{
|
113
|
+
extern void *CallbackTable[];
|
109
114
|
VALUE v_proto, v_return, v_proc;
|
110
115
|
int i;
|
111
|
-
|
116
|
+
|
112
117
|
rb_scan_args(argc, argv, "11&", &v_proto, &v_return, &v_proc);
|
113
|
-
|
118
|
+
|
114
119
|
/* Validate prototype characters */
|
115
120
|
for(i = 0; i < RSTRING(v_proto)->len; i++){
|
116
121
|
switch(RSTRING(v_proto)->ptr[i]){
|
117
122
|
case 'I': case 'L': case 'P': case 'V': case 'S':
|
118
123
|
break;
|
119
124
|
default:
|
120
|
-
rb_raise(
|
121
|
-
RSTRING(v_proto)->ptr[i]
|
125
|
+
rb_raise(cAPIProtoError, "Illegal prototype '%c'",
|
126
|
+
RSTRING(v_proto)->ptr[i]
|
127
|
+
);
|
122
128
|
}
|
123
129
|
}
|
124
130
|
|
125
|
-
if(NIL_P(v_return) || RARRAY(v_return)->len == 0)
|
131
|
+
if(NIL_P(v_return) || RARRAY(v_return)->len == 0){
|
126
132
|
v_return = rb_str_new2("L");
|
133
|
+
}
|
134
|
+
else{
|
135
|
+
switch(*(char*)RSTRING(v_return)->ptr){
|
136
|
+
case 'I': case 'L': case 'P': case 'V': case 'S':
|
137
|
+
break;
|
138
|
+
default:
|
139
|
+
rb_raise(cAPIProtoError, "Illegal return type '%s'",
|
140
|
+
RSTRING(v_return)->ptr
|
141
|
+
);
|
142
|
+
}
|
143
|
+
}
|
127
144
|
|
128
145
|
rb_iv_set(self, "@function", v_proc);
|
129
146
|
rb_iv_set(self, "@prototype", v_proto);
|
130
147
|
rb_iv_set(self, "@return_type", v_return);
|
131
|
-
|
148
|
+
rb_iv_set(self, "@address", ULONG2NUM((LPARAM)CallbackTable[RSTRING(v_proto)->len]));
|
149
|
+
ActiveCallback = self;
|
150
|
+
|
132
151
|
return self;
|
133
152
|
}
|
134
153
|
|
135
154
|
/*
|
136
155
|
* call-seq:
|
137
156
|
* Win32::API.new(function, prototype='V', return='L', dll='kernel32')
|
138
|
-
*
|
157
|
+
*
|
139
158
|
* Creates and returns a new Win32::API object. The +function+ is the name
|
140
159
|
* of the Windows function.
|
141
|
-
*
|
160
|
+
*
|
142
161
|
* The +prototype+ is the function prototype for +function+. This can be a
|
143
162
|
* string or an array of characters. The possible valid characters are 'I'
|
144
163
|
* (integer), 'L' (long), 'V' (void), 'P' (pointer), 'K' (callback) or 'S'
|
@@ -148,27 +167,27 @@ static VALUE callback_init(int argc, VALUE* argv, VALUE self)
|
|
148
167
|
*
|
149
168
|
* Constant (const char*) strings should use 'S'. Pass by reference string
|
150
169
|
* buffers should use 'P'. The former is faster, but cannot be modified.
|
151
|
-
*
|
170
|
+
*
|
152
171
|
* The +return+ argument is the return type for the function. The valid
|
153
172
|
* characters are the same as for the +prototype+. The default is 'L' (long).
|
154
|
-
*
|
173
|
+
*
|
155
174
|
* The +dll+ is the name of the DLL file that the function is exported from.
|
156
175
|
* The default is 'kernel32'.
|
157
|
-
*
|
176
|
+
*
|
158
177
|
* If the function cannot be found then an API::Error is raised (a subclass
|
159
178
|
* of RuntimeError).
|
160
|
-
*
|
179
|
+
*
|
161
180
|
* Example:
|
162
|
-
*
|
181
|
+
*
|
163
182
|
* require 'win32/api'
|
164
183
|
* include Win32
|
165
|
-
*
|
184
|
+
*
|
166
185
|
* buf = 0.chr * 260
|
167
186
|
* len = [buf.length].pack('L')
|
168
|
-
*
|
187
|
+
*
|
169
188
|
* GetUserName = API.new('GetUserName', 'PP', 'I', 'advapi32')
|
170
189
|
* GetUserName.call(buf, len)
|
171
|
-
*
|
190
|
+
*
|
172
191
|
* puts buf.strip
|
173
192
|
*/
|
174
193
|
static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
@@ -180,9 +199,9 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
180
199
|
char* first = "A";
|
181
200
|
char* second = "W";
|
182
201
|
VALUE v_proc, v_proto, v_return, v_dll;
|
183
|
-
|
202
|
+
|
184
203
|
rb_scan_args(argc, argv, "13", &v_proc, &v_proto, &v_return, &v_dll);
|
185
|
-
|
204
|
+
|
186
205
|
Data_Get_Struct(self, Win32API, ptr);
|
187
206
|
|
188
207
|
// Convert a string prototype to an array of characters
|
@@ -195,17 +214,17 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
195
214
|
rb_ary_push(v_proto, rb_str_new2("V"));
|
196
215
|
}
|
197
216
|
|
198
|
-
// Set an arbitrary limit of
|
199
|
-
if(
|
217
|
+
// Set an arbitrary limit of 20 parameters
|
218
|
+
if(20 < RARRAY(v_proto)->len)
|
200
219
|
rb_raise(rb_eArgError, "too many parameters: %d\n", RARRAY(v_proto)->len);
|
201
|
-
|
220
|
+
|
202
221
|
// Set the default dll to 'kernel32'
|
203
222
|
if(NIL_P(v_dll))
|
204
|
-
|
205
|
-
|
223
|
+
v_dll = rb_str_new2("kernel32");
|
224
|
+
|
206
225
|
// Set the default return type to 'L' (DWORD)
|
207
226
|
if(NIL_P(v_return))
|
208
|
-
|
227
|
+
v_return = rb_str_new2("L");
|
209
228
|
|
210
229
|
SafeStringValue(v_dll);
|
211
230
|
SafeStringValue(v_proc);
|
@@ -214,7 +233,7 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
214
233
|
|
215
234
|
// The most likely cause of failure is a bad DLL load path
|
216
235
|
if(!hLibrary){
|
217
|
-
rb_raise(
|
236
|
+
rb_raise(cAPILoadError, "LoadLibrary() function failed for '%s': %s",
|
218
237
|
RSTRING(v_dll)->ptr,
|
219
238
|
StringError(GetLastError())
|
220
239
|
);
|
@@ -236,10 +255,10 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
236
255
|
|
237
256
|
// Skip the ANSI and Wide function checks for MSVCRT functions.
|
238
257
|
if(!fProc){
|
239
|
-
if(
|
258
|
+
if(strstr(RSTRING(v_dll)->ptr, "msvcr")){
|
240
259
|
rb_raise(
|
241
|
-
|
242
|
-
"
|
260
|
+
cAPILoadError,
|
261
|
+
"Unable to load function '%s'",
|
243
262
|
RSTRING(v_proc)->ptr,
|
244
263
|
StringError(GetLastError())
|
245
264
|
);
|
@@ -256,12 +275,11 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
256
275
|
|
257
276
|
if(!fProc){
|
258
277
|
rb_raise(
|
259
|
-
|
260
|
-
"
|
278
|
+
cAPILoadError,
|
279
|
+
"Unable to load function '%s', '%s', or '%s'",
|
261
280
|
RSTRING(v_proc)->ptr,
|
262
281
|
RSTRING(v_ascii)->ptr,
|
263
|
-
RSTRING(v_unicode)->ptr
|
264
|
-
StringError(GetLastError())
|
282
|
+
RSTRING(v_unicode)->ptr
|
265
283
|
);
|
266
284
|
}
|
267
285
|
else{
|
@@ -303,7 +321,9 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
303
321
|
ptr->prototype[i] = _T_STRING;
|
304
322
|
break;
|
305
323
|
default:
|
306
|
-
rb_raise(
|
324
|
+
rb_raise(cAPIProtoError, "Illegal prototype '%s'",
|
325
|
+
StringValuePtr(RARRAY(v_proto)->ptr[i])
|
326
|
+
);
|
307
327
|
}
|
308
328
|
}
|
309
329
|
|
@@ -333,7 +353,9 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
|
333
353
|
ptr->return_type = _T_STRING;
|
334
354
|
break;
|
335
355
|
default:
|
336
|
-
rb_raise(
|
356
|
+
rb_raise(cAPIProtoError, "Illegal return type '%s'",
|
357
|
+
RSTRING(v_return)->ptr
|
358
|
+
);
|
337
359
|
}
|
338
360
|
}
|
339
361
|
|
@@ -391,13 +413,13 @@ static VALUE func_init(int argc, VALUE* argv, VALUE self){
|
|
391
413
|
rb_ary_push(v_proto, rb_str_new2("V"));
|
392
414
|
}
|
393
415
|
|
394
|
-
// Set an arbitrary limit of
|
395
|
-
if(
|
416
|
+
// Set an arbitrary limit of 20 parameters
|
417
|
+
if(20 < RARRAY(v_proto)->len)
|
396
418
|
rb_raise(rb_eArgError, "too many parameters: %d\n", RARRAY(v_proto)->len);
|
397
419
|
|
398
420
|
// Set the default return type to 'L' (DWORD)
|
399
421
|
if(NIL_P(v_return))
|
400
|
-
|
422
|
+
v_return = rb_str_new2("L");
|
401
423
|
|
402
424
|
ptr->function = (FARPROC)NUM2LONG(v_address);
|
403
425
|
|
@@ -425,7 +447,9 @@ static VALUE func_init(int argc, VALUE* argv, VALUE self){
|
|
425
447
|
ptr->prototype[i] = _T_STRING;
|
426
448
|
break;
|
427
449
|
default:
|
428
|
-
rb_raise(
|
450
|
+
rb_raise(cAPIProtoError, "Illegal prototype '%s'",
|
451
|
+
StringValuePtr(RARRAY(v_proto)->ptr[i])
|
452
|
+
);
|
429
453
|
}
|
430
454
|
}
|
431
455
|
|
@@ -455,7 +479,9 @@ static VALUE func_init(int argc, VALUE* argv, VALUE self){
|
|
455
479
|
ptr->return_type = _T_STRING;
|
456
480
|
break;
|
457
481
|
default:
|
458
|
-
rb_raise(
|
482
|
+
rb_raise(cAPIProtoError, "Illegal return type '%s'",
|
483
|
+
RSTRING(v_return)->ptr
|
484
|
+
);
|
459
485
|
}
|
460
486
|
}
|
461
487
|
|
@@ -467,95 +493,176 @@ static VALUE func_init(int argc, VALUE* argv, VALUE self){
|
|
467
493
|
}
|
468
494
|
|
469
495
|
typedef struct {
|
470
|
-
DWORD params[
|
471
|
-
}
|
496
|
+
DWORD params[20];
|
497
|
+
} CALLPARAM;
|
472
498
|
|
473
|
-
static VALUE ActiveCallback;
|
474
499
|
|
475
|
-
DWORD CallbackFunction(
|
500
|
+
DWORD CallbackFunction(CALLPARAM param)
|
476
501
|
{
|
477
502
|
VALUE v_proto, v_return, v_proc, v_retval;
|
478
|
-
VALUE argv[
|
503
|
+
VALUE argv[20];
|
479
504
|
int i, argc;
|
480
505
|
char *a_proto;
|
481
506
|
char *a_return;
|
482
|
-
|
507
|
+
|
483
508
|
if(!NIL_P(ActiveCallback)){
|
484
509
|
v_proto = rb_iv_get(ActiveCallback, "@prototype");
|
485
510
|
a_proto = RSTRING(v_proto)->ptr;
|
486
|
-
|
511
|
+
|
487
512
|
v_return = rb_iv_get(ActiveCallback, "@return_type");
|
488
513
|
a_return = RSTRING(v_return)->ptr;
|
489
|
-
|
514
|
+
|
490
515
|
v_proc = rb_iv_get(ActiveCallback, "@function");
|
491
516
|
argc = RSTRING(v_proto)->len;
|
492
|
-
|
517
|
+
|
493
518
|
for(i=0; i < RSTRING(v_proto)->len; i++){
|
494
519
|
argv[i] = Qnil;
|
495
520
|
switch(a_proto[i]){
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
521
|
+
case 'L':
|
522
|
+
argv[i] = ULONG2NUM(param.params[i]);
|
523
|
+
break;
|
524
|
+
case 'P':
|
525
|
+
if(param.params[i])
|
526
|
+
argv[i] = rb_str_new2((char *)param.params[i]);
|
527
|
+
break;
|
528
|
+
case 'I':
|
529
|
+
argv[i] = INT2NUM(param.params[i]);
|
530
|
+
break;
|
531
|
+
default:
|
532
|
+
rb_raise(cAPIProtoError, "Illegal prototype '%s'",
|
533
|
+
RSTRING(a_proto[i])->ptr
|
534
|
+
);
|
508
535
|
}
|
509
536
|
}
|
510
|
-
|
537
|
+
|
511
538
|
v_retval = rb_funcall2(v_proc, rb_intern("call"), argc, argv);
|
512
|
-
|
539
|
+
|
513
540
|
/* Handle true and false explicitly, as some CALLBACK functions
|
514
541
|
* require TRUE or FALSE to break out of loops, etc.
|
515
542
|
*/
|
516
|
-
if(v_retval == Qtrue)
|
543
|
+
if(v_retval == Qtrue)
|
517
544
|
return TRUE;
|
518
|
-
else if(v_retval == Qfalse)
|
545
|
+
else if(v_retval == Qfalse)
|
519
546
|
return FALSE;
|
520
|
-
|
547
|
+
|
521
548
|
switch (*a_return) {
|
522
549
|
case 'I':
|
523
550
|
return NUM2INT(v_retval);
|
524
551
|
break;
|
525
552
|
case 'L':
|
526
|
-
return NUM2ULONG(v_retval);
|
553
|
+
return NUM2ULONG(v_retval);
|
527
554
|
break;
|
528
555
|
case 'S':
|
529
556
|
return (unsigned long)RSTRING(v_retval)->ptr;
|
530
557
|
break;
|
531
558
|
case 'P':
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
}
|
559
|
+
if(NIL_P(v_retval)){
|
560
|
+
return 0;
|
561
|
+
}
|
562
|
+
else if(FIXNUM_P(v_retval)){
|
563
|
+
return NUM2ULONG(v_retval);
|
564
|
+
}
|
565
|
+
else{
|
566
|
+
StringValue(v_retval);
|
567
|
+
rb_str_modify(v_retval);
|
568
|
+
return (unsigned long)StringValuePtr(v_retval);
|
569
|
+
}
|
570
|
+
break;
|
571
|
+
}
|
545
572
|
}
|
546
|
-
|
573
|
+
|
547
574
|
return 0;
|
548
575
|
}
|
549
576
|
|
577
|
+
DWORD CALLBACK CallbackFunction0() {
|
578
|
+
CALLPARAM param = {0};
|
579
|
+
param.params[0] = 0;
|
580
|
+
return CallbackFunction(param);
|
581
|
+
}
|
582
|
+
|
583
|
+
DWORD CALLBACK CallbackFunction1(DWORD p1) {
|
584
|
+
CALLPARAM param = {p1};
|
585
|
+
return CallbackFunction(param);
|
586
|
+
}
|
587
|
+
|
588
|
+
DWORD CALLBACK CallbackFunction2(DWORD p1, DWORD p2){
|
589
|
+
CALLPARAM param = {p1,p2};
|
590
|
+
return CallbackFunction(param);
|
591
|
+
}
|
592
|
+
|
593
|
+
DWORD CALLBACK CallbackFunction3(DWORD p1, DWORD p2, DWORD p3){
|
594
|
+
CALLPARAM param = {p1,p2,p3};
|
595
|
+
return CallbackFunction(param);
|
596
|
+
}
|
597
|
+
|
598
|
+
DWORD CALLBACK CallbackFunction4(DWORD p1, DWORD p2, DWORD p3, DWORD p4){
|
599
|
+
CALLPARAM param = {p1,p2,p3,p4};
|
600
|
+
return CallbackFunction(param);
|
601
|
+
}
|
602
|
+
|
603
|
+
DWORD CALLBACK CallbackFunction5(
|
604
|
+
DWORD p1, DWORD p2, DWORD p3, DWORD p4, DWORD p5
|
605
|
+
)
|
606
|
+
{
|
607
|
+
CALLPARAM param = {p1,p2,p3,p4,p5};
|
608
|
+
return CallbackFunction(param);
|
609
|
+
}
|
610
|
+
|
611
|
+
DWORD CALLBACK CallbackFunction6(
|
612
|
+
DWORD p1, DWORD p2, DWORD p3, DWORD p4, DWORD p5, DWORD p6
|
613
|
+
)
|
614
|
+
{
|
615
|
+
CALLPARAM param = {p1,p2,p3,p4,p5,p6};
|
616
|
+
return CallbackFunction(param);
|
617
|
+
}
|
618
|
+
|
619
|
+
DWORD CALLBACK CallbackFunction7(
|
620
|
+
DWORD p1, DWORD p2, DWORD p3, DWORD p4, DWORD p5, DWORD p6, DWORD p7)
|
621
|
+
{
|
622
|
+
CALLPARAM param = {p1,p2,p3,p4,p5,p6,p7};
|
623
|
+
return CallbackFunction(param);
|
624
|
+
}
|
625
|
+
|
626
|
+
DWORD CALLBACK CallbackFunction8(
|
627
|
+
DWORD p1, DWORD p2, DWORD p3, DWORD p4,
|
628
|
+
DWORD p5, DWORD p6, DWORD p7, DWORD p8
|
629
|
+
)
|
630
|
+
{
|
631
|
+
CALLPARAM param = {p1,p2,p3,p4,p5,p6,p7,p8};
|
632
|
+
return CallbackFunction(param);
|
633
|
+
}
|
634
|
+
|
635
|
+
DWORD CALLBACK CallbackFunction9(
|
636
|
+
DWORD p1, DWORD p2, DWORD p3, DWORD p4, DWORD p5,
|
637
|
+
DWORD p6, DWORD p7, DWORD p8, DWORD p9
|
638
|
+
)
|
639
|
+
{
|
640
|
+
CALLPARAM param = {p1,p2,p3,p4,p5,p6,p7,p8,p9};
|
641
|
+
return CallbackFunction(param);
|
642
|
+
}
|
643
|
+
|
644
|
+
void *CallbackTable[] = {
|
645
|
+
CallbackFunction0,
|
646
|
+
CallbackFunction1,
|
647
|
+
CallbackFunction2,
|
648
|
+
CallbackFunction3,
|
649
|
+
CallbackFunction4,
|
650
|
+
CallbackFunction5,
|
651
|
+
CallbackFunction6,
|
652
|
+
CallbackFunction7,
|
653
|
+
CallbackFunction8,
|
654
|
+
CallbackFunction9
|
655
|
+
};
|
656
|
+
|
550
657
|
/*
|
551
658
|
* call-seq:
|
552
659
|
* Win32::API#call(arg1, arg2, ...)
|
553
|
-
*
|
660
|
+
*
|
554
661
|
* Calls the function pointer with the given arguments (if any). Note that,
|
555
662
|
* while this method will catch some prototype mismatches (raising a TypeError
|
556
663
|
* in the process), it is not fulproof. It is ultimately your job to make
|
557
664
|
* sure the arguments match the +prototype+ specified in the constructor.
|
558
|
-
*
|
665
|
+
*
|
559
666
|
* For convenience, nil is converted to NULL, true is converted to TRUE (1)
|
560
667
|
* and false is converted to FALSE (0).
|
561
668
|
*/
|
@@ -564,9 +671,10 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
564
671
|
Win32API* ptr;
|
565
672
|
unsigned long return_value;
|
566
673
|
int i = 0;
|
674
|
+
int len;
|
567
675
|
|
568
676
|
struct{
|
569
|
-
unsigned long params[
|
677
|
+
unsigned long params[20];
|
570
678
|
} param;
|
571
679
|
|
572
680
|
Data_Get_Struct(self, Win32API, ptr);
|
@@ -575,7 +683,7 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
575
683
|
|
576
684
|
v_proto = rb_iv_get(self, "@prototype");
|
577
685
|
|
578
|
-
|
686
|
+
// For void prototypes, allow either no args or an explicit nil
|
579
687
|
if(RARRAY(v_proto)->len != RARRAY(v_args)->len){
|
580
688
|
char* c = StringValuePtr(RARRAY(v_proto)->ptr[0]);
|
581
689
|
if(!strcmp(c, "V")){
|
@@ -589,10 +697,12 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
589
697
|
}
|
590
698
|
}
|
591
699
|
|
592
|
-
|
700
|
+
len = RARRAY(v_proto)->len;
|
701
|
+
|
702
|
+
for(i = 0; i < len; i++){
|
593
703
|
v_arg = RARRAY(v_args)->ptr[i];
|
594
704
|
|
595
|
-
|
705
|
+
// Convert nil to NULL. Otherwise convert as appropriate.
|
596
706
|
if(NIL_P(v_arg))
|
597
707
|
param.params[i] = (unsigned long)NULL;
|
598
708
|
else if(v_arg == Qtrue)
|
@@ -619,7 +729,8 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
619
729
|
break;
|
620
730
|
case _T_CALLBACK:
|
621
731
|
ActiveCallback = v_arg;
|
622
|
-
|
732
|
+
v_proto = rb_iv_get(ActiveCallback, "@prototype");
|
733
|
+
param.params[i] = (LPARAM)CallbackTable[RSTRING(v_proto)->len];
|
623
734
|
break;
|
624
735
|
case _T_STRING:
|
625
736
|
param.params[i] = (unsigned long)RSTRING(v_arg)->ptr;
|
@@ -632,6 +743,7 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
632
743
|
/* Call the function, get the return value */
|
633
744
|
return_value = ptr->function(param);
|
634
745
|
|
746
|
+
|
635
747
|
/* Return the appropriate type based on the return type specified
|
636
748
|
* in the constructor.
|
637
749
|
*/
|
@@ -646,13 +758,38 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
646
758
|
v_return = Qnil;
|
647
759
|
break;
|
648
760
|
case _T_POINTER:
|
649
|
-
if(!return_value)
|
761
|
+
if(!return_value){
|
650
762
|
v_return = Qnil;
|
651
|
-
|
652
|
-
|
763
|
+
}
|
764
|
+
else{
|
765
|
+
VALUE v_efunc = rb_iv_get(self, "@effective_function_name");
|
766
|
+
char* efunc = RSTRING(v_efunc)->ptr;
|
767
|
+
if(efunc[strlen(efunc)-1] == 'W'){
|
768
|
+
v_return = rb_str_new(
|
769
|
+
(TCHAR*)return_value,
|
770
|
+
wcslen((wchar_t*)return_value)*2
|
771
|
+
);
|
772
|
+
}
|
773
|
+
else{
|
774
|
+
v_return = rb_str_new2((TCHAR*)return_value);
|
775
|
+
}
|
776
|
+
}
|
653
777
|
break;
|
654
778
|
case _T_STRING:
|
655
|
-
|
779
|
+
{
|
780
|
+
VALUE v_efunc = rb_iv_get(self, "@effective_function_name");
|
781
|
+
char* efunc = RSTRING(v_efunc)->ptr;
|
782
|
+
|
783
|
+
if(efunc[strlen(efunc)-1] == 'W'){
|
784
|
+
v_return = rb_str_new(
|
785
|
+
(TCHAR*)return_value,
|
786
|
+
wcslen((wchar_t*)return_value)*2
|
787
|
+
);
|
788
|
+
}
|
789
|
+
else{
|
790
|
+
v_return = rb_str_new2((TCHAR*)return_value);
|
791
|
+
}
|
792
|
+
}
|
656
793
|
break;
|
657
794
|
default:
|
658
795
|
v_return = INT2NUM(0);
|
@@ -661,35 +798,38 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
|
661
798
|
return v_return;
|
662
799
|
}
|
663
800
|
|
664
|
-
/*
|
801
|
+
/*
|
665
802
|
* Wraps the Windows API functions in a Ruby interface.
|
666
803
|
*/
|
667
804
|
void Init_api(){
|
668
805
|
VALUE mWin32, cAPI, cCallback, cFunction;
|
669
|
-
|
806
|
+
|
670
807
|
/* Modules and Classes */
|
671
|
-
|
808
|
+
|
672
809
|
/* The Win32 module serves as a namespace only */
|
673
810
|
mWin32 = rb_define_module("Win32");
|
674
|
-
|
811
|
+
|
675
812
|
/* The API class encapsulates a function pointer to Windows API function */
|
676
813
|
cAPI = rb_define_class_under(mWin32, "API", rb_cObject);
|
677
|
-
|
678
|
-
/* The API::Callback class encapsulates a Windows CALLBACK function */
|
814
|
+
|
815
|
+
/* The API::Callback class encapsulates a Windows CALLBACK function */
|
679
816
|
cCallback = rb_define_class_under(cAPI, "Callback", rb_cObject);
|
680
817
|
|
681
818
|
/* The API::Function class encapsulates a raw function pointer */
|
682
819
|
cFunction = rb_define_class_under(cAPI, "Function", cAPI);
|
683
|
-
|
684
|
-
/* The API::Error class
|
820
|
+
|
821
|
+
/* The API::Error class serves as a base class for other errors */
|
685
822
|
cAPIError = rb_define_class_under(cAPI, "Error", rb_eRuntimeError);
|
686
823
|
|
687
|
-
/* The
|
688
|
-
|
824
|
+
/* The LoadError class is raised if a function cannot be found or loaded */
|
825
|
+
cAPILoadError = rb_define_class_under(cAPI, "LoadLibraryError", cAPIError);
|
826
|
+
|
827
|
+
/* The PrototypeError class is raised if an invalid prototype is passed */
|
828
|
+
cAPIProtoError = rb_define_class_under(cAPI, "PrototypeError", cAPIError);
|
689
829
|
|
690
830
|
/* Miscellaneous */
|
691
831
|
rb_define_alloc_func(cAPI, api_allocate);
|
692
|
-
|
832
|
+
|
693
833
|
/* Win32::API Instance Methods */
|
694
834
|
rb_define_method(cAPI, "initialize", api_init, -1);
|
695
835
|
rb_define_method(cAPI, "call", api_call, -1);
|
@@ -699,38 +839,39 @@ void Init_api(){
|
|
699
839
|
|
700
840
|
/* Win32::API::Function Instance Methods */
|
701
841
|
rb_define_method(cFunction, "initialize", func_init, -1);
|
702
|
-
|
842
|
+
|
703
843
|
/* The name of the DLL that exports the API function */
|
704
844
|
rb_define_attr(cAPI, "dll_name", 1, 0);
|
705
|
-
|
845
|
+
|
706
846
|
/* The name of the function passed to the constructor */
|
707
847
|
rb_define_attr(cAPI, "function_name", 1, 0);
|
708
|
-
|
848
|
+
|
709
849
|
/* The name of the actual function that is returned by the constructor.
|
710
850
|
* For example, if you passed 'GetUserName' to the constructor, then the
|
711
851
|
* effective function name would be either 'GetUserNameA' or 'GetUserNameW'.
|
712
852
|
*/
|
713
853
|
rb_define_attr(cAPI, "effective_function_name", 1, 0);
|
714
|
-
|
854
|
+
|
715
855
|
/* The prototype, returned as an array of characters */
|
716
856
|
rb_define_attr(cAPI, "prototype", 1, 0);
|
717
|
-
|
857
|
+
|
718
858
|
/* The return type, returned as a single character, S, P, L, I, V or B */
|
719
859
|
rb_define_attr(cAPI, "return_type", 1, 0);
|
720
|
-
|
860
|
+
|
721
861
|
/* Win32::API::Callback Instance Methods */
|
722
|
-
|
862
|
+
|
723
863
|
/* The prototype, returned as an array of characters */
|
724
864
|
rb_define_attr(cCallback, "prototype", 1, 0);
|
725
|
-
|
865
|
+
|
726
866
|
/* The return type, returned as a single character, S, P, L, I, V or B */
|
727
867
|
rb_define_attr(cCallback, "return_type", 1, 0);
|
728
868
|
|
729
869
|
/* The numeric address of the function pointer */
|
870
|
+
rb_define_attr(cCallback, "address", 1, 0);
|
730
871
|
rb_define_attr(cFunction, "address", 1, 0);
|
731
|
-
|
872
|
+
|
732
873
|
/* Constants */
|
733
|
-
|
734
|
-
/* 1.2.
|
874
|
+
|
875
|
+
/* 1.2.2: The version of this library, returned as a String */
|
735
876
|
rb_define_const(cAPI, "VERSION", rb_str_new2(WINDOWS_API_VERSION));
|
736
877
|
}
|
data/test/test_win32_api.rb
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
# Test case for the Win32::API class. You should run this as Rake task,
|
5
5
|
# i.e. 'rake test', instead of running it directly.
|
6
6
|
############################################################################
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'test-unit'
|
9
|
+
|
7
10
|
require 'win32/api'
|
8
11
|
require 'test/unit'
|
9
12
|
include Win32
|
@@ -11,13 +14,13 @@ include Win32
|
|
11
14
|
class TC_Win32_API < Test::Unit::TestCase
|
12
15
|
def setup
|
13
16
|
@buf = 0.chr * 260
|
14
|
-
@
|
17
|
+
@gcd = API.new('GetCurrentDirectory', 'LP')
|
15
18
|
@gle = API.new('GetLastError', 'V', 'L')
|
16
19
|
@str = API.new('strstr', 'PP', 'P', 'msvcrt')
|
17
20
|
end
|
18
21
|
|
19
22
|
def test_version
|
20
|
-
assert_equal('1.
|
23
|
+
assert_equal('1.3.0', API::VERSION)
|
21
24
|
end
|
22
25
|
|
23
26
|
def test_constructor_basic
|
@@ -28,8 +31,8 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
28
31
|
end
|
29
32
|
|
30
33
|
def test_call
|
31
|
-
assert_respond_to(@
|
32
|
-
assert_nothing_raised{ @
|
34
|
+
assert_respond_to(@gcd, :call)
|
35
|
+
assert_nothing_raised{ @gcd.call(@buf.length, @buf) }
|
33
36
|
assert_equal(Dir.pwd.tr('/', "\\"), @buf.strip)
|
34
37
|
end
|
35
38
|
|
@@ -39,78 +42,93 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
39
42
|
end
|
40
43
|
|
41
44
|
def test_dll_name
|
42
|
-
assert_respond_to(@
|
43
|
-
assert_equal('kernel32', @
|
45
|
+
assert_respond_to(@gcd, :dll_name)
|
46
|
+
assert_equal('kernel32', @gcd.dll_name)
|
44
47
|
end
|
45
48
|
|
46
49
|
def test_function_name
|
47
|
-
assert_respond_to(@
|
48
|
-
assert_equal('GetCurrentDirectory', @
|
50
|
+
assert_respond_to(@gcd, :function_name)
|
51
|
+
assert_equal('GetCurrentDirectory', @gcd.function_name)
|
49
52
|
assert_equal('strstr', @str.function_name)
|
50
53
|
end
|
51
54
|
|
52
|
-
def
|
53
|
-
assert_respond_to(@
|
54
|
-
assert_equal('GetCurrentDirectoryA', @
|
55
|
+
def test_effective_function_name_default
|
56
|
+
assert_respond_to(@gcd, :effective_function_name)
|
57
|
+
assert_equal('GetCurrentDirectoryA', @gcd.effective_function_name)
|
55
58
|
assert_equal('strstr', @str.effective_function_name)
|
59
|
+
end
|
56
60
|
|
57
|
-
|
58
|
-
|
61
|
+
def test_effective_function_name_default_explicit_ansi
|
62
|
+
@gcd = API.new('GetCurrentDirectoryA', 'LP')
|
63
|
+
assert_equal('GetCurrentDirectoryA', @gcd.effective_function_name)
|
64
|
+
end
|
59
65
|
|
60
|
-
|
61
|
-
|
66
|
+
def test_effective_function_name_default_explicit_wide
|
67
|
+
@gcd = API.new('GetCurrentDirectoryW', 'LP')
|
68
|
+
assert_equal('GetCurrentDirectoryW', @gcd.effective_function_name)
|
62
69
|
end
|
63
70
|
|
64
71
|
def test_prototype
|
65
|
-
assert_respond_to(@
|
66
|
-
assert_equal(['L', 'P'], @
|
72
|
+
assert_respond_to(@gcd, :prototype)
|
73
|
+
assert_equal(['L', 'P'], @gcd.prototype)
|
67
74
|
end
|
68
75
|
|
69
76
|
def test_return_type
|
70
|
-
assert_respond_to(@
|
71
|
-
assert_equal('L', @
|
77
|
+
assert_respond_to(@gcd, :return_type)
|
78
|
+
assert_equal('L', @gcd.return_type)
|
72
79
|
end
|
73
80
|
|
74
81
|
def test_constructor_high_iteration
|
75
|
-
|
76
|
-
|
82
|
+
assert_nothing_raised{
|
83
|
+
1000.times{ API.new('GetUserName', 'P', 'P', 'advapi32') }
|
77
84
|
}
|
78
85
|
end
|
79
86
|
|
80
87
|
def test_constructor_expected_failures
|
81
88
|
assert_raise(ArgumentError){ API.new }
|
82
|
-
assert_raise(
|
83
|
-
assert_raise(API::
|
84
|
-
assert_raise(API::
|
89
|
+
assert_raise(ArgumentError){ API.new('GetUserName', ('L' * 21), 'X') }
|
90
|
+
assert_raise(API::LoadLibraryError){ API.new('GetUserName', 'PL', 'I', 'foo') }
|
91
|
+
assert_raise(API::PrototypeError){ API.new('GetUserName', 'X', 'I', 'advapi32') }
|
92
|
+
assert_raise(API::PrototypeError){ API.new('GetUserName', 'PL', 'X', 'advapi32') }
|
85
93
|
end
|
86
94
|
|
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
95
|
def test_constructor_expected_failure_messages
|
90
|
-
|
91
|
-
API.new('
|
92
|
-
|
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
|
96
|
+
assert_raise_message("Unable to load function 'Zap', 'ZapA', or 'ZapW'"){
|
97
|
+
API.new('Zap')
|
98
|
+
}
|
97
99
|
|
98
|
-
|
99
|
-
API.new('strxxx', 'P', '
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
100
|
+
assert_raise_message("Unable to load function 'strxxx'"){
|
101
|
+
API.new('strxxx', 'P', 'L', 'msvcrt')
|
102
|
+
}
|
103
|
+
|
104
|
+
assert_raise_message("Illegal prototype 'X'"){
|
105
|
+
API.new('GetUserName', 'X', 'I', 'advapi32')
|
106
|
+
}
|
107
|
+
|
108
|
+
assert_raise_message("Illegal return type 'Y'"){
|
109
|
+
API.new('GetUserName', 'PL', 'Y', 'advapi32')
|
110
|
+
}
|
105
111
|
end
|
106
|
-
|
112
|
+
|
107
113
|
def test_call_expected_failures
|
108
|
-
assert_raise(TypeError){ @
|
114
|
+
assert_raise(TypeError){ @gcd.call('test', @buf) }
|
109
115
|
end
|
110
|
-
|
116
|
+
|
117
|
+
def test_error_classes
|
118
|
+
assert_not_nil(Win32::API::Error)
|
119
|
+
assert_not_nil(Win32::API::LoadLibraryError)
|
120
|
+
assert_not_nil(Win32::API::PrototypeError)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_error_class_relationships
|
124
|
+
assert_kind_of(RuntimeError, Win32::API::Error.new)
|
125
|
+
assert_kind_of(Win32::API::Error, Win32::API::LoadLibraryError.new)
|
126
|
+
assert_kind_of(Win32::API::Error, Win32::API::PrototypeError.new)
|
127
|
+
end
|
128
|
+
|
111
129
|
def teardown
|
112
130
|
@buf = nil
|
113
|
-
@
|
131
|
+
@gcd = nil
|
114
132
|
@gle = nil
|
115
133
|
@str = nil
|
116
134
|
end
|
@@ -4,6 +4,9 @@
|
|
4
4
|
# Test case for the Win32::API::Callback class. You should run this as Rake
|
5
5
|
# task, i.e. 'rake test', instead of running it directly.
|
6
6
|
############################################################################
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'test-unit'
|
9
|
+
|
7
10
|
require 'win32/api'
|
8
11
|
require 'test/unit'
|
9
12
|
include Win32
|
@@ -33,6 +36,13 @@ class TC_Win32_API_Callback < Test::Unit::TestCase
|
|
33
36
|
assert_respond_to(@callback, :return_type)
|
34
37
|
assert_equal('I', @callback.return_type)
|
35
38
|
end
|
39
|
+
|
40
|
+
def test_address
|
41
|
+
assert_nothing_raised{ @callback = API::Callback.new('LP', 'I') }
|
42
|
+
assert_respond_to(@callback, :address)
|
43
|
+
assert_kind_of(Fixnum, @callback.address)
|
44
|
+
assert_equal(true, @callback.address > 0)
|
45
|
+
end
|
36
46
|
|
37
47
|
def test_callback
|
38
48
|
assert_nothing_raised{
|
@@ -46,7 +56,13 @@ class TC_Win32_API_Callback < Test::Unit::TestCase
|
|
46
56
|
end
|
47
57
|
|
48
58
|
def test_constructor_expected_errors
|
49
|
-
assert_raise(API::
|
59
|
+
assert_raise(API::PrototypeError){ API::Callback.new('X') }
|
60
|
+
assert_raise(API::PrototypeError){ API::Callback.new('L', 'Y') }
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_constructor_expected_error_messages
|
64
|
+
assert_raise_message("Illegal prototype 'X'"){ API::Callback.new('X') }
|
65
|
+
assert_raise_message("Illegal return type 'Y'"){ API::Callback.new('L', 'Y') }
|
50
66
|
end
|
51
67
|
|
52
68
|
def teardown
|
@@ -4,8 +4,12 @@
|
|
4
4
|
# Test case for the Win32::API::Function class. You should run these
|
5
5
|
# tests via the 'rake test' task.
|
6
6
|
########################################################################
|
7
|
+
require 'rubygems'
|
8
|
+
gem 'test-unit'
|
9
|
+
|
7
10
|
require 'test/unit'
|
8
11
|
require 'win32/api'
|
12
|
+
include Win32
|
9
13
|
|
10
14
|
class TC_Win32_API_Function < Test::Unit::TestCase
|
11
15
|
def setup
|
@@ -38,8 +42,22 @@ class TC_Win32_API_Function < Test::Unit::TestCase
|
|
38
42
|
assert_equal('L', @func.return_type)
|
39
43
|
end
|
40
44
|
|
41
|
-
def
|
45
|
+
def test_expected_errors_from_arguments
|
42
46
|
assert_raise(ArgumentError){ Win32::API::Function.new }
|
47
|
+
assert_raise(TypeError){ Win32::API::Function.new('L') }
|
48
|
+
assert_raise(Win32::API::PrototypeError){ Win32::API::Function.new(1, 'X') }
|
49
|
+
assert_raise(Win32::API::PrototypeError){ Win32::API::Function.new(1, 'X', 'Y') }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_expected_error_messages
|
53
|
+
assert_raise_message("Illegal prototype 'X'"){ API::Function.new(1, 'X') }
|
54
|
+
assert_raise_message("Illegal return type 'Y'"){ API::Function.new(1, 'L', 'Y') }
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_expected_errors_from_call
|
58
|
+
assert_raise(ArgumentError){ @func.call }
|
59
|
+
assert_raise(ArgumentError){ @func.call(1) }
|
60
|
+
assert_raise(ArgumentError){ @func.call(1, 'a', 2) }
|
43
61
|
end
|
44
62
|
|
45
63
|
def teardown
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2009-01-04 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -55,7 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
55
|
requirements: []
|
56
56
|
|
57
57
|
rubyforge_project: win32utils
|
58
|
-
rubygems_version: 1.
|
58
|
+
rubygems_version: 1.3.1
|
59
59
|
signing_key:
|
60
60
|
specification_version: 2
|
61
61
|
summary: A superior replacement for Win32API
|