win32-api 1.0.0-mswin32 → 1.0.1-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +6 -0
- data/lib/win32/api.so +0 -0
- data/test/tc_win32_api.rb +8 -1
- data/test/tc_win32_api_callback.rb +57 -57
- metadata +3 -4
- data/ext/win32/api.c +0 -496
data/CHANGES
CHANGED
@@ -1,2 +1,8 @@
|
|
1
|
+
= 1.0.1 - 27-Sep-2007
|
2
|
+
* Functions declared with a void prototype no longer require an explicit nil
|
3
|
+
argument to fulfill the arity requirement. You can still call them with an
|
4
|
+
explicit nil if you wish, however.
|
5
|
+
* Fixed the gemspec for the native build.
|
6
|
+
|
1
7
|
= 1.0.0 - 14-Sep-2007
|
2
8
|
* Initial release
|
data/lib/win32/api.so
CHANGED
Binary file
|
data/test/tc_win32_api.rb
CHANGED
@@ -12,10 +12,11 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
12
12
|
def setup
|
13
13
|
@buf = 0.chr * 260
|
14
14
|
@api = API.new('GetCurrentDirectory', 'LP')
|
15
|
+
@gle = API.new('GetLastError', 'V', 'L')
|
15
16
|
end
|
16
17
|
|
17
18
|
def test_version
|
18
|
-
assert_equal('1.0.
|
19
|
+
assert_equal('1.0.1', API::VERSION)
|
19
20
|
end
|
20
21
|
|
21
22
|
def test_call
|
@@ -24,6 +25,11 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
24
25
|
assert_equal(Dir.pwd.tr('/', "\\"), @buf.strip)
|
25
26
|
end
|
26
27
|
|
28
|
+
def test_call_with_void
|
29
|
+
assert_nothing_raised{ @gle.call }
|
30
|
+
assert_nothing_raised{ @gle.call(nil) }
|
31
|
+
end
|
32
|
+
|
27
33
|
def test_dll_name
|
28
34
|
assert_respond_to(@api, :dll_name)
|
29
35
|
assert_equal('kernel32', @api.dll_name)
|
@@ -57,5 +63,6 @@ class TC_Win32_API < Test::Unit::TestCase
|
|
57
63
|
def teardown
|
58
64
|
@buf = nil
|
59
65
|
@api = nil
|
66
|
+
@gle = nil
|
60
67
|
end
|
61
68
|
end
|
@@ -1,58 +1,58 @@
|
|
1
|
-
############################################################################
|
2
|
-
# tc_win32_api_callback.rb
|
3
|
-
#
|
4
|
-
# Test case for the Win32::API::Callback class. You should run this as Rake
|
5
|
-
# task, i.e. 'rake test', instead of running it directly.
|
6
|
-
############################################################################
|
7
|
-
require 'win32/api'
|
8
|
-
require 'test/unit'
|
9
|
-
include Win32
|
10
|
-
|
11
|
-
class TC_Win32_API_Callback < Test::Unit::TestCase
|
12
|
-
def setup
|
13
|
-
@buffer = 0.chr * 260
|
14
|
-
@api_ew = API.new('EnumWindows', 'KP', 'L', 'user32')
|
15
|
-
@api_gwt = API.new('GetWindowText', 'LPI', 'I', 'user32')
|
16
|
-
@callback = nil
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_constructor
|
20
|
-
assert_respond_to(API::Callback, :new)
|
21
|
-
assert_nothing_raised{ API::Callback.new('LP', 'I') }
|
22
|
-
assert_nothing_raised{ API::Callback.new('LP', 'I'){} }
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_prototype
|
26
|
-
assert_nothing_raised{ @callback = API::Callback.new('LP', 'I') }
|
27
|
-
assert_respond_to(@callback, :prototype)
|
28
|
-
assert_equal('LP', @callback.prototype)
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_return_value
|
32
|
-
assert_nothing_raised{ @callback = API::Callback.new('LP', 'I') }
|
33
|
-
assert_respond_to(@callback, :return_type)
|
34
|
-
assert_equal('I', @callback.return_type)
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_callback
|
38
|
-
assert_nothing_raised{
|
39
|
-
@callback = API::Callback.new('LP', 'I'){ |handle, param|
|
40
|
-
buf = "\0" * 200
|
41
|
-
@api_gwt.call(handle, buf, 200);
|
42
|
-
buf.index(param).nil? ? true : false
|
43
|
-
}
|
44
|
-
}
|
45
|
-
assert_nothing_raised{ @api_ew.call(@callback, 'UEDIT32') }
|
46
|
-
end
|
47
|
-
|
48
|
-
def test_constructor_expected_errors
|
49
|
-
assert_raise(API::Callback::Error){ API::Callback.new('X') }
|
50
|
-
end
|
51
|
-
|
52
|
-
def teardown
|
53
|
-
@buffer = nil
|
54
|
-
@api_ew = nil
|
55
|
-
@api_gwt = nil
|
56
|
-
@callback = nil
|
57
|
-
end
|
1
|
+
############################################################################
|
2
|
+
# tc_win32_api_callback.rb
|
3
|
+
#
|
4
|
+
# Test case for the Win32::API::Callback class. You should run this as Rake
|
5
|
+
# task, i.e. 'rake test', instead of running it directly.
|
6
|
+
############################################################################
|
7
|
+
require 'win32/api'
|
8
|
+
require 'test/unit'
|
9
|
+
include Win32
|
10
|
+
|
11
|
+
class TC_Win32_API_Callback < Test::Unit::TestCase
|
12
|
+
def setup
|
13
|
+
@buffer = 0.chr * 260
|
14
|
+
@api_ew = API.new('EnumWindows', 'KP', 'L', 'user32')
|
15
|
+
@api_gwt = API.new('GetWindowText', 'LPI', 'I', 'user32')
|
16
|
+
@callback = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_constructor
|
20
|
+
assert_respond_to(API::Callback, :new)
|
21
|
+
assert_nothing_raised{ API::Callback.new('LP', 'I') }
|
22
|
+
assert_nothing_raised{ API::Callback.new('LP', 'I'){} }
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_prototype
|
26
|
+
assert_nothing_raised{ @callback = API::Callback.new('LP', 'I') }
|
27
|
+
assert_respond_to(@callback, :prototype)
|
28
|
+
assert_equal('LP', @callback.prototype)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_return_value
|
32
|
+
assert_nothing_raised{ @callback = API::Callback.new('LP', 'I') }
|
33
|
+
assert_respond_to(@callback, :return_type)
|
34
|
+
assert_equal('I', @callback.return_type)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_callback
|
38
|
+
assert_nothing_raised{
|
39
|
+
@callback = API::Callback.new('LP', 'I'){ |handle, param|
|
40
|
+
buf = "\0" * 200
|
41
|
+
@api_gwt.call(handle, buf, 200);
|
42
|
+
buf.index(param).nil? ? true : false
|
43
|
+
}
|
44
|
+
}
|
45
|
+
assert_nothing_raised{ @api_ew.call(@callback, 'UEDIT32') }
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_constructor_expected_errors
|
49
|
+
assert_raise(API::Callback::Error){ API::Callback.new('X') }
|
50
|
+
end
|
51
|
+
|
52
|
+
def teardown
|
53
|
+
@buffer = nil
|
54
|
+
@api_ew = nil
|
55
|
+
@api_gwt = nil
|
56
|
+
@callback = nil
|
57
|
+
end
|
58
58
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: win32-api
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.0.
|
7
|
-
date: 2007-09-
|
6
|
+
version: 1.0.1
|
7
|
+
date: 2007-09-27 00:00:00 -06:00
|
8
8
|
summary: A superior replacement for Win32API
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -29,13 +29,13 @@ post_install_message:
|
|
29
29
|
authors:
|
30
30
|
- Daniel J. Berger
|
31
31
|
files:
|
32
|
+
- lib/win32
|
32
33
|
- lib/win32/api.so
|
33
34
|
- test/tc_win32_api.rb
|
34
35
|
- test/tc_win32_api_callback.rb
|
35
36
|
- README
|
36
37
|
- CHANGES
|
37
38
|
- MANIFEST
|
38
|
-
- ext/win32/api.c
|
39
39
|
test_files:
|
40
40
|
- test/tc_win32_api.rb
|
41
41
|
- test/tc_win32_api_callback.rb
|
@@ -45,7 +45,6 @@ extra_rdoc_files:
|
|
45
45
|
- README
|
46
46
|
- CHANGES
|
47
47
|
- MANIFEST
|
48
|
-
- ext/win32/api.c
|
49
48
|
executables: []
|
50
49
|
|
51
50
|
extensions: []
|
data/ext/win32/api.c
DELETED
@@ -1,496 +0,0 @@
|
|
1
|
-
#include <ruby.h>
|
2
|
-
#include <windows.h>
|
3
|
-
|
4
|
-
#define MAX_BUF 1024
|
5
|
-
#define WINDOWS_API_VERSION "1.0.0"
|
6
|
-
|
7
|
-
#define _T_VOID 0
|
8
|
-
#define _T_LONG 1
|
9
|
-
#define _T_POINTER 2
|
10
|
-
#define _T_INTEGER 3
|
11
|
-
#define _T_CALLBACK 4
|
12
|
-
|
13
|
-
VALUE cAPIError, cCallbackError;
|
14
|
-
|
15
|
-
/* Helper function that converts the error number returned by GetLastError()
|
16
|
-
* into a human readable string. Internal use only.
|
17
|
-
*/
|
18
|
-
char* StringError(DWORD dwError){
|
19
|
-
LPVOID lpMsgBuf;
|
20
|
-
static char buf[MAX_PATH];
|
21
|
-
DWORD dwLen;
|
22
|
-
|
23
|
-
/* Assume ASCII error messages from the Windows API */
|
24
|
-
dwLen = FormatMessageA(
|
25
|
-
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
26
|
-
FORMAT_MESSAGE_FROM_SYSTEM |
|
27
|
-
FORMAT_MESSAGE_IGNORE_INSERTS,
|
28
|
-
NULL,
|
29
|
-
dwError,
|
30
|
-
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
31
|
-
(LPSTR)&lpMsgBuf,
|
32
|
-
0,
|
33
|
-
NULL
|
34
|
-
);
|
35
|
-
|
36
|
-
if(!dwLen)
|
37
|
-
rb_raise(cAPIError, "Attempt to format message failed");
|
38
|
-
|
39
|
-
memset(buf, 0, MAX_PATH);
|
40
|
-
|
41
|
-
/* remove \r\n */
|
42
|
-
#ifdef HAVE_STRNCPY_S
|
43
|
-
strncpy_s(buf, MAX_PATH, lpMsgBuf, dwLen - 2);
|
44
|
-
#else
|
45
|
-
strncpy(buf, lpMsgBuf, dwLen - 2);
|
46
|
-
#endif
|
47
|
-
|
48
|
-
LocalFree(lpMsgBuf);
|
49
|
-
|
50
|
-
return buf;
|
51
|
-
}
|
52
|
-
|
53
|
-
/*
|
54
|
-
* call-seq:
|
55
|
-
* Win32::API::Callback.new(prototype, return='L')
|
56
|
-
*
|
57
|
-
* Creates and returns a new Win32::API::Callback object. The +function+ is
|
58
|
-
* the name of the Windows function.
|
59
|
-
*
|
60
|
-
* The +prototype+ is the function prototype for the callback function. This
|
61
|
-
* is a string. The possible valid characters are 'I' (integer), 'L' (long),
|
62
|
-
* 'V' (void), or 'P' (pointer). Unlike API objects, API::Callback objects
|
63
|
-
* do not have a default prototype.
|
64
|
-
*
|
65
|
-
* The +return+ argument is the return type for the callback function. The
|
66
|
-
* valid characters are the same as for the +prototype+. The default is
|
67
|
-
* 'L' (long).
|
68
|
-
*/
|
69
|
-
static VALUE callback_init(int argc, VALUE* argv, VALUE self)
|
70
|
-
{
|
71
|
-
VALUE v_proto, v_return, v_proc;
|
72
|
-
|
73
|
-
rb_scan_args(argc, argv, "11", &v_proto, &v_return);
|
74
|
-
|
75
|
-
if(NIL_P(v_return) || RARRAY(v_return)->len == 0)
|
76
|
-
v_return = rb_str_new2("L");
|
77
|
-
|
78
|
-
if(rb_block_given_p())
|
79
|
-
v_proc = rb_block_proc();
|
80
|
-
else
|
81
|
-
v_proc = Qnil;
|
82
|
-
|
83
|
-
rb_iv_set(self, "@function", v_proc);
|
84
|
-
rb_iv_set(self, "@prototype", v_proto);
|
85
|
-
rb_iv_set(self, "@return_type", v_return);
|
86
|
-
|
87
|
-
return self;
|
88
|
-
}
|
89
|
-
|
90
|
-
|
91
|
-
typedef struct {
|
92
|
-
HANDLE library;
|
93
|
-
FARPROC function;
|
94
|
-
int return_type;
|
95
|
-
int prototype[];
|
96
|
-
} Win32API;
|
97
|
-
|
98
|
-
static void api_free(Win32API* ptr){
|
99
|
-
if(ptr->library)
|
100
|
-
FreeLibrary(ptr->library);
|
101
|
-
|
102
|
-
free(ptr);
|
103
|
-
}
|
104
|
-
|
105
|
-
static VALUE api_allocate(VALUE klass){
|
106
|
-
Win32API* ptr = malloc(sizeof(Win32API));
|
107
|
-
return Data_Wrap_Struct(klass, 0, api_free, ptr);
|
108
|
-
}
|
109
|
-
|
110
|
-
/*
|
111
|
-
* call-seq:
|
112
|
-
* Win32::API.new(function, prototype='V', return='L', dll='kernel32')
|
113
|
-
*
|
114
|
-
* Creates and returns a new Win32::API object. The +function+ is the name
|
115
|
-
* of the Windows function.
|
116
|
-
*
|
117
|
-
* The +prototype+ is the function prototype for +function+. This can be a
|
118
|
-
* string or an array of characters. The possible valid characters are 'I'
|
119
|
-
* (integer), 'L' (long), 'V' (void), 'P' (pointer), or 'K' (callback).
|
120
|
-
* The default is void ('V').
|
121
|
-
*
|
122
|
-
* The +return+ argument is the return type for the function. The valid
|
123
|
-
* characters are the same as for the +prototype+. The default is 'L' (long).
|
124
|
-
*
|
125
|
-
* The +dll+ is the name of the DLL file that the function is exported from.
|
126
|
-
* The default is 'kernel32'.
|
127
|
-
*
|
128
|
-
* If the function cannot be found then an API::Error is raised (a subclass
|
129
|
-
* of RuntimeError).
|
130
|
-
*/
|
131
|
-
static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
132
|
-
{
|
133
|
-
HMODULE hLibrary;
|
134
|
-
FARPROC fProc;
|
135
|
-
Win32API* ptr;
|
136
|
-
int i;
|
137
|
-
VALUE v_proc, v_proto, v_return, v_dll, v_bool, v_name;
|
138
|
-
|
139
|
-
rb_scan_args(argc, argv, "13", &v_proc, &v_proto, &v_return, &v_dll);
|
140
|
-
|
141
|
-
Data_Get_Struct(self, Win32API, ptr);
|
142
|
-
|
143
|
-
/* Convert a string prototype to an array of characters */
|
144
|
-
if(rb_respond_to(v_proto, rb_intern("split")))
|
145
|
-
v_proto = rb_str_split(v_proto, "");
|
146
|
-
|
147
|
-
/* Set an arbitrary limit of 16 parameters */
|
148
|
-
if(16 < RARRAY(v_proto)->len)
|
149
|
-
rb_raise(rb_eArgError, "too many parameters: %d\n", RARRAY(v_proto)->len);
|
150
|
-
|
151
|
-
/* Convert a nil or empty prototype to 'V' (void) automatically */
|
152
|
-
if(NIL_P(v_proto) || RARRAY(v_proto)->len == 0){
|
153
|
-
v_proto = rb_ary_new();
|
154
|
-
rb_ary_push(v_proto, rb_str_new2("V"));
|
155
|
-
}
|
156
|
-
|
157
|
-
/* Set the default dll to 'kernel32' */
|
158
|
-
if(NIL_P(v_dll))
|
159
|
-
v_dll = rb_str_new2("kernel32");
|
160
|
-
|
161
|
-
/* Set the default return type to 'L' (DWORD) */
|
162
|
-
if(NIL_P(v_return))
|
163
|
-
v_return = rb_str_new2("L");
|
164
|
-
|
165
|
-
SafeStringValue(v_dll);
|
166
|
-
SafeStringValue(v_proc);
|
167
|
-
|
168
|
-
hLibrary = LoadLibrary(TEXT(RSTRING(v_dll)->ptr));
|
169
|
-
|
170
|
-
/* The most likely cause of failure is a bad DLL load path */
|
171
|
-
if(!hLibrary){
|
172
|
-
rb_raise(cAPIError, "LoadLibrary() function failed for '%s': %s",
|
173
|
-
RSTRING(v_dll)->ptr,
|
174
|
-
StringError(GetLastError())
|
175
|
-
);
|
176
|
-
}
|
177
|
-
|
178
|
-
ptr->library = hLibrary;
|
179
|
-
|
180
|
-
/* Attempt to get the function. If it fails, try again with an 'A'
|
181
|
-
* appended. If that fails, try again with a 'W' appended. If that
|
182
|
-
* still fails, raise an API::Error.
|
183
|
-
*/
|
184
|
-
fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_proc)->ptr));
|
185
|
-
|
186
|
-
if(!fProc){
|
187
|
-
VALUE v_ascii = rb_str_new3(v_proc);
|
188
|
-
v_ascii = rb_str_cat(v_ascii, "A", 1);
|
189
|
-
fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_ascii)->ptr));
|
190
|
-
|
191
|
-
if(!fProc){
|
192
|
-
VALUE v_unicode = rb_str_new3(v_proc);
|
193
|
-
v_unicode = rb_str_cat(v_unicode, "W", 1);
|
194
|
-
fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_unicode)->ptr));
|
195
|
-
|
196
|
-
if(!fProc){
|
197
|
-
rb_raise(
|
198
|
-
cAPIError,
|
199
|
-
"GetProcAddress() failed for '%s', '%s' and '%s': %s",
|
200
|
-
RSTRING(v_proc)->ptr,
|
201
|
-
RSTRING(v_ascii)->ptr,
|
202
|
-
RSTRING(v_unicode)->ptr,
|
203
|
-
StringError(GetLastError())
|
204
|
-
);
|
205
|
-
}
|
206
|
-
}
|
207
|
-
}
|
208
|
-
|
209
|
-
ptr->function = fProc;
|
210
|
-
|
211
|
-
/* Push the numeric prototypes onto our int array for later use. */
|
212
|
-
for(i = 0; i < RARRAY(v_proto)->len; i++){
|
213
|
-
SafeStringValue(RARRAY(v_proto)->ptr[i]);
|
214
|
-
switch(*(char*)StringValuePtr(RARRAY(v_proto)->ptr[i])){
|
215
|
-
case 'L':
|
216
|
-
ptr->prototype[i] = _T_LONG;
|
217
|
-
break;
|
218
|
-
case 'P':
|
219
|
-
ptr->prototype[i] = _T_POINTER;
|
220
|
-
break;
|
221
|
-
case 'I': case 'B':
|
222
|
-
ptr->prototype[i] = _T_INTEGER;
|
223
|
-
break;
|
224
|
-
case 'V':
|
225
|
-
ptr->prototype[i] = _T_VOID;
|
226
|
-
break;
|
227
|
-
case 'K':
|
228
|
-
ptr->prototype[i] = _T_CALLBACK;
|
229
|
-
break;
|
230
|
-
default:
|
231
|
-
rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
|
232
|
-
}
|
233
|
-
}
|
234
|
-
|
235
|
-
/* Store the return type for later use. Automatically convert empty
|
236
|
-
* strings or nil to type void.
|
237
|
-
*/
|
238
|
-
if(NIL_P(v_return) || RSTRING(v_return)->len == 0){
|
239
|
-
v_return = rb_str_new2("V");
|
240
|
-
ptr->return_type = _T_VOID;
|
241
|
-
}
|
242
|
-
else{
|
243
|
-
SafeStringValue(v_return);
|
244
|
-
switch(*RSTRING(v_return)->ptr){
|
245
|
-
case 'L':
|
246
|
-
ptr->return_type = _T_LONG;
|
247
|
-
break;
|
248
|
-
case 'P':
|
249
|
-
ptr->return_type = _T_POINTER;
|
250
|
-
break;
|
251
|
-
case 'I': case 'B':
|
252
|
-
ptr->return_type = _T_INTEGER;
|
253
|
-
break;
|
254
|
-
case 'V':
|
255
|
-
ptr->return_type = _T_VOID;
|
256
|
-
break;
|
257
|
-
default:
|
258
|
-
rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
|
259
|
-
}
|
260
|
-
}
|
261
|
-
|
262
|
-
rb_iv_set(self, "@dll_name", v_dll);
|
263
|
-
rb_iv_set(self, "@function_name", v_proc);
|
264
|
-
rb_iv_set(self, "@prototype", v_proto);
|
265
|
-
rb_iv_set(self, "@return_type", v_return);
|
266
|
-
|
267
|
-
return self;
|
268
|
-
}
|
269
|
-
|
270
|
-
typedef struct {
|
271
|
-
DWORD params[1];
|
272
|
-
} PARAM;
|
273
|
-
|
274
|
-
static VALUE ActiveCallback;
|
275
|
-
|
276
|
-
DWORD CallbackFunction(PARAM param)
|
277
|
-
{
|
278
|
-
VALUE v_proto, v_return, v_proc, v_retval;
|
279
|
-
VALUE argv[16];
|
280
|
-
int i, argc;
|
281
|
-
char *a_proto;
|
282
|
-
char *a_return;
|
283
|
-
|
284
|
-
if(!NIL_P(ActiveCallback)){
|
285
|
-
v_proto = rb_iv_get(ActiveCallback, "@prototype");
|
286
|
-
a_proto = RSTRING(v_proto)->ptr;
|
287
|
-
|
288
|
-
v_return = rb_iv_get(ActiveCallback, "@return_type");
|
289
|
-
a_return = RSTRING(v_return)->ptr;
|
290
|
-
|
291
|
-
v_proc = rb_iv_get(ActiveCallback, "@function");
|
292
|
-
argc = RSTRING(v_proto)->len;
|
293
|
-
|
294
|
-
for(i=0; i < RSTRING(v_proto)->len; i++){
|
295
|
-
argv[i] = Qnil;
|
296
|
-
switch(a_proto[i]){
|
297
|
-
case 'L':
|
298
|
-
argv[i] = ULONG2NUM(param.params[i]);
|
299
|
-
break;
|
300
|
-
case 'P':
|
301
|
-
if(param.params[i])
|
302
|
-
argv[i] = rb_str_new2((char *)param.params[i]);
|
303
|
-
break;
|
304
|
-
case 'I':
|
305
|
-
argv[i] = INT2NUM(param.params[i]);
|
306
|
-
break;
|
307
|
-
default:
|
308
|
-
rb_raise(cCallbackError, "Illegal prototype '%s'", a_proto[i]);
|
309
|
-
}
|
310
|
-
}
|
311
|
-
|
312
|
-
v_retval = rb_funcall2(v_proc, rb_intern("call"), argc, argv);
|
313
|
-
|
314
|
-
/* Handle true and false explicitly, as some CALLBACK functions
|
315
|
-
* require TRUE or FALSE to break out of loops, etc.
|
316
|
-
*/
|
317
|
-
if(v_retval == Qtrue)
|
318
|
-
return TRUE;
|
319
|
-
else if(v_retval == Qfalse)
|
320
|
-
return FALSE;
|
321
|
-
|
322
|
-
switch (*a_return) {
|
323
|
-
case 'I':
|
324
|
-
return NUM2INT(v_retval);
|
325
|
-
break;
|
326
|
-
case 'L':
|
327
|
-
return NUM2ULONG(v_retval);
|
328
|
-
break;
|
329
|
-
case 'P':
|
330
|
-
if(NIL_P(v_retval)){
|
331
|
-
return 0;
|
332
|
-
}
|
333
|
-
else if (FIXNUM_P(v_retval)){
|
334
|
-
return NUM2ULONG(v_retval);
|
335
|
-
}
|
336
|
-
else{
|
337
|
-
StringValue(v_retval);
|
338
|
-
rb_str_modify(v_retval);
|
339
|
-
return (unsigned long)StringValuePtr(v_retval);
|
340
|
-
}
|
341
|
-
break;
|
342
|
-
}
|
343
|
-
}
|
344
|
-
|
345
|
-
return 0;
|
346
|
-
}
|
347
|
-
|
348
|
-
/*
|
349
|
-
* call-seq:
|
350
|
-
* Win32::API#call(arg1, arg2, ...)
|
351
|
-
*
|
352
|
-
* Calls the function pointer with the given arguments (if any). Note that,
|
353
|
-
* while this method will catch some prototype mismatches (raising a TypeError
|
354
|
-
* in the process), it is not fulproof. It is ultimately your job to make
|
355
|
-
* sure the arguments match the +prototype+ specified in the constructor.
|
356
|
-
*
|
357
|
-
* For convenience, nil is converted to NULL, true is converted to TRUE (1)
|
358
|
-
* and false is converted to FALSE (0).
|
359
|
-
*/
|
360
|
-
static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
361
|
-
VALUE v_proto, v_args, v_arg, v_return;
|
362
|
-
Win32API* ptr;
|
363
|
-
unsigned long return_value;
|
364
|
-
int i = 0;
|
365
|
-
|
366
|
-
struct{
|
367
|
-
unsigned long params[16];
|
368
|
-
} param;
|
369
|
-
|
370
|
-
Data_Get_Struct(self, Win32API, ptr);
|
371
|
-
|
372
|
-
rb_scan_args(argc, argv, "0*", &v_args);
|
373
|
-
|
374
|
-
v_proto = rb_iv_get(self, "@prototype");
|
375
|
-
|
376
|
-
if(RARRAY(v_proto)->len != RARRAY(v_args)->len)
|
377
|
-
rb_raise(rb_eArgError, "wrong number of parameters: expected %d, got %d",
|
378
|
-
RARRAY(v_proto)->len, RARRAY(v_args)->len
|
379
|
-
);
|
380
|
-
|
381
|
-
for(i = 0; i < RARRAY(v_proto)->len; i++){
|
382
|
-
v_arg = RARRAY(v_args)->ptr[i];
|
383
|
-
|
384
|
-
/* Convert nil to NULL. Otherwise convert as appropriate. */
|
385
|
-
if(NIL_P(v_arg))
|
386
|
-
param.params[i] = (unsigned long)NULL;
|
387
|
-
else if(v_arg == Qtrue)
|
388
|
-
param.params[i] = TRUE;
|
389
|
-
else if(v_arg == Qfalse)
|
390
|
-
param.params[i] = FALSE;
|
391
|
-
else
|
392
|
-
switch(ptr->prototype[i]){
|
393
|
-
case _T_LONG:
|
394
|
-
param.params[i] = NUM2ULONG(v_arg);
|
395
|
-
break;
|
396
|
-
case _T_INTEGER:
|
397
|
-
param.params[i] = NUM2INT(v_arg);
|
398
|
-
break;
|
399
|
-
case _T_POINTER:
|
400
|
-
if(FIXNUM_P(v_arg))
|
401
|
-
param.params[i] = NUM2ULONG(v_arg);
|
402
|
-
else
|
403
|
-
param.params[i] = (unsigned long)StringValuePtr(v_arg);
|
404
|
-
break;
|
405
|
-
case _T_CALLBACK:
|
406
|
-
ActiveCallback = v_arg;
|
407
|
-
param.params[i] = (LPARAM)CallbackFunction;
|
408
|
-
break;
|
409
|
-
default:
|
410
|
-
param.params[i] = NUM2ULONG(v_arg);
|
411
|
-
}
|
412
|
-
}
|
413
|
-
|
414
|
-
/* Call the function, get the return value */
|
415
|
-
return_value = ptr->function(param);
|
416
|
-
|
417
|
-
/* Return the appropriate type based on the return type specified
|
418
|
-
* in the constructor.
|
419
|
-
*/
|
420
|
-
switch(ptr->return_type){
|
421
|
-
case _T_INTEGER:
|
422
|
-
v_return = INT2NUM(return_value);
|
423
|
-
break;
|
424
|
-
case _T_LONG:
|
425
|
-
v_return = LONG2NUM(return_value);
|
426
|
-
break;
|
427
|
-
case _T_VOID:
|
428
|
-
v_return = Qnil;
|
429
|
-
break;
|
430
|
-
case _T_POINTER:
|
431
|
-
v_return = rb_str_new2((TCHAR*)return_value);
|
432
|
-
break;
|
433
|
-
default:
|
434
|
-
v_return = INT2NUM(0);
|
435
|
-
}
|
436
|
-
|
437
|
-
return v_return;
|
438
|
-
}
|
439
|
-
|
440
|
-
/*
|
441
|
-
* Wraps the Windows API functions in a Ruby interface.
|
442
|
-
*/
|
443
|
-
void Init_api(){
|
444
|
-
VALUE mWin32, cAPI, cCallback;
|
445
|
-
|
446
|
-
/* Modules and Classes */
|
447
|
-
|
448
|
-
/* The Win32 module serves as a namespace only */
|
449
|
-
mWin32 = rb_define_module("Win32");
|
450
|
-
|
451
|
-
/* The API class encapsulates a function pointer to Windows API function */
|
452
|
-
cAPI = rb_define_class_under(mWin32, "API", rb_cObject);
|
453
|
-
|
454
|
-
/* The API::Callback class encapsulates a Windows CALLBACK function */
|
455
|
-
cCallback = rb_define_class_under(cAPI, "Callback", rb_cObject);
|
456
|
-
|
457
|
-
/* The API::Error class is raised if the constructor fails */
|
458
|
-
cAPIError = rb_define_class_under(cAPI, "Error", rb_eRuntimeError);
|
459
|
-
|
460
|
-
/* The API::Callback::Error class is raised if the constructor fails */
|
461
|
-
cCallbackError = rb_define_class_under(cCallback, "Error", rb_eRuntimeError);
|
462
|
-
|
463
|
-
/* Miscellaneous */
|
464
|
-
rb_define_alloc_func(cAPI, api_allocate);
|
465
|
-
|
466
|
-
/* Win32::API Instance Methods */
|
467
|
-
rb_define_method(cAPI, "initialize", api_init, -1);
|
468
|
-
rb_define_method(cAPI, "call", api_call, -1);
|
469
|
-
|
470
|
-
rb_define_method(cCallback, "initialize", callback_init, -1);
|
471
|
-
|
472
|
-
/* The name of the DLL that exports the API function */
|
473
|
-
rb_define_attr(cAPI, "dll_name", 1, 0);
|
474
|
-
|
475
|
-
/* The name of the function */
|
476
|
-
rb_define_attr(cAPI, "function_name", 1, 0);
|
477
|
-
|
478
|
-
/* The prototype, returned as an array of characters */
|
479
|
-
rb_define_attr(cAPI, "prototype", 1, 0);
|
480
|
-
|
481
|
-
/* The return type, returned as a single character, P, L, I, V or B */
|
482
|
-
rb_define_attr(cAPI, "return_type", 1, 0);
|
483
|
-
|
484
|
-
/* Win32::API::Callback Instance Methods */
|
485
|
-
|
486
|
-
/* The prototype, returned as an array of characters */
|
487
|
-
rb_define_attr(cCallback, "prototype", 1, 0);
|
488
|
-
|
489
|
-
/* The return type, returned as a single character, P, L, I, V or B */
|
490
|
-
rb_define_attr(cCallback, "return_type", 1, 0);
|
491
|
-
|
492
|
-
/* Constants */
|
493
|
-
|
494
|
-
/* 1.0.0: The version of this library, returned as a String */
|
495
|
-
rb_define_const(cAPI, "VERSION", rb_str_new2(WINDOWS_API_VERSION));
|
496
|
-
}
|