win32-api 1.0.0-mswin32 → 1.0.1-mswin32
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 +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
|
-
}
|