win32-api 1.2.0 → 1.3.0
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 +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
|