win32-api 1.0.3-mswin32 → 1.0.4-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +23 -17
- data/MANIFEST +9 -9
- data/README +71 -71
- data/ext/extconf.rb +10 -0
- data/ext/win32/api.c +524 -0
- data/lib/win32/api.so +0 -0
- data/test/tc_win32_api.rb +1 -1
- metadata +7 -3
data/CHANGES
CHANGED
@@ -1,18 +1,24 @@
|
|
1
|
-
= 1.0.
|
2
|
-
* Fixed a
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
*
|
16
|
-
|
17
|
-
= 1.0.
|
1
|
+
= 1.0.4 - 26-Oct-2007
|
2
|
+
* Fixed a bug where methods that returned pointers ('P') could choke if the
|
3
|
+
resulting pointer was 0 or NULL. In this case, nil is now returned instead.
|
4
|
+
* Tweak to the extconf.rb file that helps the gem build it from source
|
5
|
+
properly.
|
6
|
+
|
7
|
+
= 1.0.3 - 28-Sep-2007
|
8
|
+
* Fixed a subtle but dangerous copy-on-write bug in the API#call method.
|
9
|
+
|
10
|
+
= 1.0.2 - 28-Sep-2007
|
11
|
+
* Fixed a bug in an internal struct member that was causing segfaults. Thanks
|
12
|
+
go to Lars Olsson for the spot.
|
13
|
+
* Fixed the 'install' task in the Rakefile. This only affected native builds,
|
14
|
+
not the prebuilt binary.
|
15
|
+
* Added a few more tests.
|
16
|
+
|
17
|
+
= 1.0.1 - 27-Sep-2007
|
18
|
+
* Functions declared with a void prototype no longer require an explicit nil
|
19
|
+
argument to fulfill the arity requirement. You can still call them with an
|
20
|
+
explicit nil if you wish, however.
|
21
|
+
* Fixed the gemspec for the native build.
|
22
|
+
|
23
|
+
= 1.0.0 - 14-Sep-2007
|
18
24
|
* Initial release
|
data/MANIFEST
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
CHANGES
|
2
|
-
MANIFEST
|
3
|
-
README
|
4
|
-
Rakefile
|
5
|
-
win32-api.gemspec
|
6
|
-
ext/extconf.rb
|
7
|
-
ext/win32/api.c
|
8
|
-
test/tc_win32_api_callback.rb
|
9
|
-
test/tc_win32_api.rb
|
1
|
+
* CHANGES
|
2
|
+
* MANIFEST
|
3
|
+
* README
|
4
|
+
* Rakefile
|
5
|
+
* win32-api.gemspec
|
6
|
+
* ext/extconf.rb
|
7
|
+
* ext/win32/api.c
|
8
|
+
* test/tc_win32_api_callback.rb
|
9
|
+
* test/tc_win32_api.rb
|
data/README
CHANGED
@@ -1,72 +1,72 @@
|
|
1
|
-
= Description
|
2
|
-
This is a drop-in replacement for the Win32API library currently part of
|
3
|
-
Ruby's standard library.
|
4
|
-
|
5
|
-
= Synopsis
|
6
|
-
require 'win32/api'
|
7
|
-
include Win32
|
8
|
-
|
9
|
-
buf = 0.chr * 260
|
10
|
-
len = [@buf.length].pack('L')
|
11
|
-
|
12
|
-
GetUserName = API.new('GetUserName', 'PP', 'I', 'advapi32')
|
13
|
-
GetUserName.call(buf, len)
|
14
|
-
|
15
|
-
puts buf.strip
|
16
|
-
|
17
|
-
= Differences between win32-api and Win32API
|
18
|
-
* Argument order change. The DLL name is now last, not first.
|
19
|
-
* Removed the 'N' and 'n'. Always use 'L' for longs now.
|
20
|
-
* Sensible default arguments for the prototype, return type and DLL name.
|
21
|
-
* Reader methods for the function name, prototype, return type and DLL.
|
22
|
-
* Removed the support for lower case prototype and return types. Always
|
23
|
-
use capital letters.
|
24
|
-
|
25
|
-
= Developer's Notes
|
26
|
-
The current Win32API library that ships with the standard library has been
|
27
|
-
slated for removal from Ruby 2.0 and it will not receive any updates in the
|
28
|
-
Ruby 1.8.x branch. I have far too many libraries invested in it to let it
|
29
|
-
die at this point.
|
30
|
-
|
31
|
-
In addition, the current Win32API library was written in the bad old Ruby
|
32
|
-
1.6.x days, which means it doesn't use the newer allocation framework.
|
33
|
-
There were several other refactorings that I felt it needed to more closely
|
34
|
-
match how it was actually being used in practice.
|
35
|
-
|
36
|
-
The first order of business was changing the order of the arguments. By
|
37
|
-
moving the DLL name from first to last, I was able to provide reasonable
|
38
|
-
default arguments for the prototype, return type and the DLL. Only the
|
39
|
-
function name is required now.
|
40
|
-
|
41
|
-
There was a laundry list of other refactorings that were needed: sensical
|
42
|
-
instance variable names with proper accessors, removing support for lower
|
43
|
-
case prototype and return value characters that no one used in practice,
|
44
|
-
better naming conventions, the addition of RDoc ready comments and,
|
45
|
-
especially, callback support.
|
46
|
-
|
47
|
-
Most importantly, we can now add, modify and fix any features that we feel
|
48
|
-
best benefit our end users.
|
49
|
-
|
50
|
-
= Documentation
|
51
|
-
The source file contains inline RDoc documentation. If you installed
|
52
|
-
this file as a gem, then you have the docs.
|
53
|
-
|
54
|
-
= Warranty
|
55
|
-
This package is provided "as is" and without any express or
|
56
|
-
implied warranties, including, without limitation, the implied
|
57
|
-
warranties of merchantability and fitness for a particular purpose.
|
58
|
-
|
59
|
-
= Known Bugs
|
60
|
-
None that I'm aware of. Please submit any bug reports to the project page
|
61
|
-
at http://www.rubyforge.org/projects/win32utils.
|
62
|
-
|
63
|
-
= Copyright
|
64
|
-
(C) 2003-2007 Daniel J. Berger
|
65
|
-
All Rights Reserved
|
66
|
-
|
67
|
-
= License
|
68
|
-
Ruby's
|
69
|
-
|
70
|
-
= Authors
|
71
|
-
Daniel J. Berger
|
1
|
+
= Description
|
2
|
+
This is a drop-in replacement for the Win32API library currently part of
|
3
|
+
Ruby's standard library.
|
4
|
+
|
5
|
+
= Synopsis
|
6
|
+
require 'win32/api'
|
7
|
+
include Win32
|
8
|
+
|
9
|
+
buf = 0.chr * 260
|
10
|
+
len = [@buf.length].pack('L')
|
11
|
+
|
12
|
+
GetUserName = API.new('GetUserName', 'PP', 'I', 'advapi32')
|
13
|
+
GetUserName.call(buf, len)
|
14
|
+
|
15
|
+
puts buf.strip
|
16
|
+
|
17
|
+
= Differences between win32-api and Win32API
|
18
|
+
* Argument order change. The DLL name is now last, not first.
|
19
|
+
* Removed the 'N' and 'n'. Always use 'L' for longs now.
|
20
|
+
* Sensible default arguments for the prototype, return type and DLL name.
|
21
|
+
* Reader methods for the function name, prototype, return type and DLL.
|
22
|
+
* Removed the support for lower case prototype and return types. Always
|
23
|
+
use capital letters.
|
24
|
+
|
25
|
+
= Developer's Notes
|
26
|
+
The current Win32API library that ships with the standard library has been
|
27
|
+
slated for removal from Ruby 2.0 and it will not receive any updates in the
|
28
|
+
Ruby 1.8.x branch. I have far too many libraries invested in it to let it
|
29
|
+
die at this point.
|
30
|
+
|
31
|
+
In addition, the current Win32API library was written in the bad old Ruby
|
32
|
+
1.6.x days, which means it doesn't use the newer allocation framework.
|
33
|
+
There were several other refactorings that I felt it needed to more closely
|
34
|
+
match how it was actually being used in practice.
|
35
|
+
|
36
|
+
The first order of business was changing the order of the arguments. By
|
37
|
+
moving the DLL name from first to last, I was able to provide reasonable
|
38
|
+
default arguments for the prototype, return type and the DLL. Only the
|
39
|
+
function name is required now.
|
40
|
+
|
41
|
+
There was a laundry list of other refactorings that were needed: sensical
|
42
|
+
instance variable names with proper accessors, removing support for lower
|
43
|
+
case prototype and return value characters that no one used in practice,
|
44
|
+
better naming conventions, the addition of RDoc ready comments and,
|
45
|
+
especially, callback support.
|
46
|
+
|
47
|
+
Most importantly, we can now add, modify and fix any features that we feel
|
48
|
+
best benefit our end users.
|
49
|
+
|
50
|
+
= Documentation
|
51
|
+
The source file contains inline RDoc documentation. If you installed
|
52
|
+
this file as a gem, then you have the docs.
|
53
|
+
|
54
|
+
= Warranty
|
55
|
+
This package is provided "as is" and without any express or
|
56
|
+
implied warranties, including, without limitation, the implied
|
57
|
+
warranties of merchantability and fitness for a particular purpose.
|
58
|
+
|
59
|
+
= Known Bugs
|
60
|
+
None that I'm aware of. Please submit any bug reports to the project page
|
61
|
+
at http://www.rubyforge.org/projects/win32utils.
|
62
|
+
|
63
|
+
= Copyright
|
64
|
+
(C) 2003-2007 Daniel J. Berger
|
65
|
+
All Rights Reserved
|
66
|
+
|
67
|
+
= License
|
68
|
+
Ruby's
|
69
|
+
|
70
|
+
= Authors
|
71
|
+
Daniel J. Berger
|
72
72
|
Park Heesob
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
##########################################################################
|
2
|
+
# extconf.rb
|
3
|
+
#
|
4
|
+
# The Windows::API binary should be built using the Rake task, i.e.
|
5
|
+
# 'rake build' or 'rake install'.
|
6
|
+
##########################################################################
|
7
|
+
require 'mkmf'
|
8
|
+
|
9
|
+
have_func('strncpy_s')
|
10
|
+
create_makefile('win32/api', 'win32')
|
data/ext/win32/api.c
ADDED
@@ -0,0 +1,524 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <windows.h>
|
3
|
+
|
4
|
+
#define MAX_BUF 1024
|
5
|
+
#define WINDOWS_API_VERSION "1.0.4"
|
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
|
+
int i;
|
73
|
+
|
74
|
+
rb_scan_args(argc, argv, "11", &v_proto, &v_return);
|
75
|
+
|
76
|
+
/* Validate prototype characters */
|
77
|
+
for(i = 0; i < RSTRING(v_proto)->len; i++){
|
78
|
+
switch(RSTRING(v_proto)->ptr[i]){
|
79
|
+
case 'I': case 'L': case 'P': case 'V':
|
80
|
+
break;
|
81
|
+
default:
|
82
|
+
rb_raise(cCallbackError, "Illegal prototype '%c'",
|
83
|
+
RSTRING(v_proto)->ptr[i]);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
if(NIL_P(v_return) || RARRAY(v_return)->len == 0)
|
88
|
+
v_return = rb_str_new2("L");
|
89
|
+
|
90
|
+
if(rb_block_given_p())
|
91
|
+
v_proc = rb_block_proc();
|
92
|
+
else
|
93
|
+
v_proc = Qnil;
|
94
|
+
|
95
|
+
rb_iv_set(self, "@function", v_proc);
|
96
|
+
rb_iv_set(self, "@prototype", v_proto);
|
97
|
+
rb_iv_set(self, "@return_type", v_return);
|
98
|
+
|
99
|
+
return self;
|
100
|
+
}
|
101
|
+
|
102
|
+
|
103
|
+
typedef struct {
|
104
|
+
HANDLE library;
|
105
|
+
FARPROC function;
|
106
|
+
int return_type;
|
107
|
+
int prototype[16];
|
108
|
+
} Win32API;
|
109
|
+
|
110
|
+
static void api_free(Win32API* ptr){
|
111
|
+
if(ptr->library)
|
112
|
+
FreeLibrary(ptr->library);
|
113
|
+
|
114
|
+
free(ptr);
|
115
|
+
}
|
116
|
+
|
117
|
+
static VALUE api_allocate(VALUE klass){
|
118
|
+
Win32API* ptr = malloc(sizeof(Win32API));
|
119
|
+
return Data_Wrap_Struct(klass, 0, api_free, ptr);
|
120
|
+
}
|
121
|
+
|
122
|
+
/*
|
123
|
+
* call-seq:
|
124
|
+
* Win32::API.new(function, prototype='V', return='L', dll='kernel32')
|
125
|
+
*
|
126
|
+
* Creates and returns a new Win32::API object. The +function+ is the name
|
127
|
+
* of the Windows function.
|
128
|
+
*
|
129
|
+
* The +prototype+ is the function prototype for +function+. This can be a
|
130
|
+
* string or an array of characters. The possible valid characters are 'I'
|
131
|
+
* (integer), 'L' (long), 'V' (void), 'P' (pointer), or 'K' (callback).
|
132
|
+
* The default is void ('V').
|
133
|
+
*
|
134
|
+
* The +return+ argument is the return type for the function. The valid
|
135
|
+
* characters are the same as for the +prototype+. The default is 'L' (long).
|
136
|
+
*
|
137
|
+
* The +dll+ is the name of the DLL file that the function is exported from.
|
138
|
+
* The default is 'kernel32'.
|
139
|
+
*
|
140
|
+
* If the function cannot be found then an API::Error is raised (a subclass
|
141
|
+
* of RuntimeError).
|
142
|
+
*/
|
143
|
+
static VALUE api_init(int argc, VALUE* argv, VALUE self)
|
144
|
+
{
|
145
|
+
HMODULE hLibrary;
|
146
|
+
FARPROC fProc;
|
147
|
+
Win32API* ptr;
|
148
|
+
int i;
|
149
|
+
VALUE v_proc, v_proto, v_return, v_dll, v_bool, v_name;
|
150
|
+
|
151
|
+
rb_scan_args(argc, argv, "13", &v_proc, &v_proto, &v_return, &v_dll);
|
152
|
+
|
153
|
+
Data_Get_Struct(self, Win32API, ptr);
|
154
|
+
|
155
|
+
/* Convert a string prototype to an array of characters */
|
156
|
+
if(rb_respond_to(v_proto, rb_intern("split")))
|
157
|
+
v_proto = rb_str_split(v_proto, "");
|
158
|
+
|
159
|
+
/* Set an arbitrary limit of 16 parameters */
|
160
|
+
if(16 < RARRAY(v_proto)->len)
|
161
|
+
rb_raise(rb_eArgError, "too many parameters: %d\n", RARRAY(v_proto)->len);
|
162
|
+
|
163
|
+
/* Convert a nil or empty prototype to 'V' (void) automatically */
|
164
|
+
if(NIL_P(v_proto) || RARRAY(v_proto)->len == 0){
|
165
|
+
v_proto = rb_ary_new();
|
166
|
+
rb_ary_push(v_proto, rb_str_new2("V"));
|
167
|
+
}
|
168
|
+
|
169
|
+
/* Set the default dll to 'kernel32' */
|
170
|
+
if(NIL_P(v_dll))
|
171
|
+
v_dll = rb_str_new2("kernel32");
|
172
|
+
|
173
|
+
/* Set the default return type to 'L' (DWORD) */
|
174
|
+
if(NIL_P(v_return))
|
175
|
+
v_return = rb_str_new2("L");
|
176
|
+
|
177
|
+
SafeStringValue(v_dll);
|
178
|
+
SafeStringValue(v_proc);
|
179
|
+
|
180
|
+
hLibrary = LoadLibrary(TEXT(RSTRING(v_dll)->ptr));
|
181
|
+
|
182
|
+
/* The most likely cause of failure is a bad DLL load path */
|
183
|
+
if(!hLibrary){
|
184
|
+
rb_raise(cAPIError, "LoadLibrary() function failed for '%s': %s",
|
185
|
+
RSTRING(v_dll)->ptr,
|
186
|
+
StringError(GetLastError())
|
187
|
+
);
|
188
|
+
}
|
189
|
+
|
190
|
+
ptr->library = hLibrary;
|
191
|
+
|
192
|
+
/* Attempt to get the function. If it fails, try again with an 'A'
|
193
|
+
* appended. If that fails, try again with a 'W' appended. If that
|
194
|
+
* still fails, raise an API::Error.
|
195
|
+
*/
|
196
|
+
fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_proc)->ptr));
|
197
|
+
|
198
|
+
if(!fProc){
|
199
|
+
VALUE v_ascii = rb_str_new3(v_proc);
|
200
|
+
v_ascii = rb_str_cat(v_ascii, "A", 1);
|
201
|
+
fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_ascii)->ptr));
|
202
|
+
|
203
|
+
if(!fProc){
|
204
|
+
VALUE v_unicode = rb_str_new3(v_proc);
|
205
|
+
v_unicode = rb_str_cat(v_unicode, "W", 1);
|
206
|
+
fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_unicode)->ptr));
|
207
|
+
|
208
|
+
if(!fProc){
|
209
|
+
rb_raise(
|
210
|
+
cAPIError,
|
211
|
+
"GetProcAddress() failed for '%s', '%s' and '%s': %s",
|
212
|
+
RSTRING(v_proc)->ptr,
|
213
|
+
RSTRING(v_ascii)->ptr,
|
214
|
+
RSTRING(v_unicode)->ptr,
|
215
|
+
StringError(GetLastError())
|
216
|
+
);
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
ptr->function = fProc;
|
222
|
+
|
223
|
+
/* Push the numeric prototypes onto our int array for later use. */
|
224
|
+
for(i = 0; i < RARRAY(v_proto)->len; i++){
|
225
|
+
SafeStringValue(RARRAY(v_proto)->ptr[i]);
|
226
|
+
switch(*(char*)StringValuePtr(RARRAY(v_proto)->ptr[i])){
|
227
|
+
case 'L':
|
228
|
+
ptr->prototype[i] = _T_LONG;
|
229
|
+
break;
|
230
|
+
case 'P':
|
231
|
+
ptr->prototype[i] = _T_POINTER;
|
232
|
+
break;
|
233
|
+
case 'I': case 'B':
|
234
|
+
ptr->prototype[i] = _T_INTEGER;
|
235
|
+
break;
|
236
|
+
case 'V':
|
237
|
+
ptr->prototype[i] = _T_VOID;
|
238
|
+
break;
|
239
|
+
case 'K':
|
240
|
+
ptr->prototype[i] = _T_CALLBACK;
|
241
|
+
break;
|
242
|
+
default:
|
243
|
+
rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
/* Store the return type for later use. Automatically convert empty
|
248
|
+
* strings or nil to type void.
|
249
|
+
*/
|
250
|
+
if(NIL_P(v_return) || RSTRING(v_return)->len == 0){
|
251
|
+
v_return = rb_str_new2("V");
|
252
|
+
ptr->return_type = _T_VOID;
|
253
|
+
}
|
254
|
+
else{
|
255
|
+
SafeStringValue(v_return);
|
256
|
+
switch(*RSTRING(v_return)->ptr){
|
257
|
+
case 'L':
|
258
|
+
ptr->return_type = _T_LONG;
|
259
|
+
break;
|
260
|
+
case 'P':
|
261
|
+
ptr->return_type = _T_POINTER;
|
262
|
+
break;
|
263
|
+
case 'I': case 'B':
|
264
|
+
ptr->return_type = _T_INTEGER;
|
265
|
+
break;
|
266
|
+
case 'V':
|
267
|
+
ptr->return_type = _T_VOID;
|
268
|
+
break;
|
269
|
+
default:
|
270
|
+
rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
rb_iv_set(self, "@dll_name", v_dll);
|
275
|
+
rb_iv_set(self, "@function_name", v_proc);
|
276
|
+
rb_iv_set(self, "@prototype", v_proto);
|
277
|
+
rb_iv_set(self, "@return_type", v_return);
|
278
|
+
|
279
|
+
return self;
|
280
|
+
}
|
281
|
+
|
282
|
+
typedef struct {
|
283
|
+
DWORD params[1];
|
284
|
+
} PARAM;
|
285
|
+
|
286
|
+
static VALUE ActiveCallback;
|
287
|
+
|
288
|
+
DWORD CallbackFunction(PARAM param)
|
289
|
+
{
|
290
|
+
VALUE v_proto, v_return, v_proc, v_retval;
|
291
|
+
VALUE argv[16];
|
292
|
+
int i, argc;
|
293
|
+
char *a_proto;
|
294
|
+
char *a_return;
|
295
|
+
|
296
|
+
if(!NIL_P(ActiveCallback)){
|
297
|
+
v_proto = rb_iv_get(ActiveCallback, "@prototype");
|
298
|
+
a_proto = RSTRING(v_proto)->ptr;
|
299
|
+
|
300
|
+
v_return = rb_iv_get(ActiveCallback, "@return_type");
|
301
|
+
a_return = RSTRING(v_return)->ptr;
|
302
|
+
|
303
|
+
v_proc = rb_iv_get(ActiveCallback, "@function");
|
304
|
+
argc = RSTRING(v_proto)->len;
|
305
|
+
|
306
|
+
for(i=0; i < RSTRING(v_proto)->len; i++){
|
307
|
+
argv[i] = Qnil;
|
308
|
+
switch(a_proto[i]){
|
309
|
+
case 'L':
|
310
|
+
argv[i] = ULONG2NUM(param.params[i]);
|
311
|
+
break;
|
312
|
+
case 'P':
|
313
|
+
if(param.params[i])
|
314
|
+
argv[i] = rb_str_new2((char *)param.params[i]);
|
315
|
+
break;
|
316
|
+
case 'I':
|
317
|
+
argv[i] = INT2NUM(param.params[i]);
|
318
|
+
break;
|
319
|
+
default:
|
320
|
+
rb_raise(cCallbackError, "Illegal prototype '%c'", a_proto[i]);
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
v_retval = rb_funcall2(v_proc, rb_intern("call"), argc, argv);
|
325
|
+
|
326
|
+
/* Handle true and false explicitly, as some CALLBACK functions
|
327
|
+
* require TRUE or FALSE to break out of loops, etc.
|
328
|
+
*/
|
329
|
+
if(v_retval == Qtrue)
|
330
|
+
return TRUE;
|
331
|
+
else if(v_retval == Qfalse)
|
332
|
+
return FALSE;
|
333
|
+
|
334
|
+
switch (*a_return) {
|
335
|
+
case 'I':
|
336
|
+
return NUM2INT(v_retval);
|
337
|
+
break;
|
338
|
+
case 'L':
|
339
|
+
return NUM2ULONG(v_retval);
|
340
|
+
break;
|
341
|
+
case 'P':
|
342
|
+
if(NIL_P(v_retval)){
|
343
|
+
return 0;
|
344
|
+
}
|
345
|
+
else if (FIXNUM_P(v_retval)){
|
346
|
+
return NUM2ULONG(v_retval);
|
347
|
+
}
|
348
|
+
else{
|
349
|
+
StringValue(v_retval);
|
350
|
+
rb_str_modify(v_retval);
|
351
|
+
return (unsigned long)StringValuePtr(v_retval);
|
352
|
+
}
|
353
|
+
break;
|
354
|
+
}
|
355
|
+
}
|
356
|
+
|
357
|
+
return 0;
|
358
|
+
}
|
359
|
+
|
360
|
+
/*
|
361
|
+
* call-seq:
|
362
|
+
* Win32::API#call(arg1, arg2, ...)
|
363
|
+
*
|
364
|
+
* Calls the function pointer with the given arguments (if any). Note that,
|
365
|
+
* while this method will catch some prototype mismatches (raising a TypeError
|
366
|
+
* in the process), it is not fulproof. It is ultimately your job to make
|
367
|
+
* sure the arguments match the +prototype+ specified in the constructor.
|
368
|
+
*
|
369
|
+
* For convenience, nil is converted to NULL, true is converted to TRUE (1)
|
370
|
+
* and false is converted to FALSE (0).
|
371
|
+
*/
|
372
|
+
static VALUE api_call(int argc, VALUE* argv, VALUE self){
|
373
|
+
VALUE v_proto, v_args, v_arg, v_return;
|
374
|
+
Win32API* ptr;
|
375
|
+
unsigned long return_value;
|
376
|
+
int i = 0;
|
377
|
+
|
378
|
+
struct{
|
379
|
+
unsigned long params[16];
|
380
|
+
} param;
|
381
|
+
|
382
|
+
Data_Get_Struct(self, Win32API, ptr);
|
383
|
+
|
384
|
+
rb_scan_args(argc, argv, "0*", &v_args);
|
385
|
+
|
386
|
+
v_proto = rb_iv_get(self, "@prototype");
|
387
|
+
|
388
|
+
/* For void prototypes, allow either no args or an explicit nil */
|
389
|
+
if(RARRAY(v_proto)->len != RARRAY(v_args)->len){
|
390
|
+
char* c = StringValuePtr(RARRAY(v_proto)->ptr[0]);
|
391
|
+
if(!strcmp(c, "V")){
|
392
|
+
rb_ary_push(v_args, Qnil);
|
393
|
+
}
|
394
|
+
else{
|
395
|
+
rb_raise(rb_eArgError,
|
396
|
+
"wrong number of parameters: expected %d, got %d",
|
397
|
+
RARRAY(v_proto)->len, RARRAY(v_args)->len
|
398
|
+
);
|
399
|
+
}
|
400
|
+
}
|
401
|
+
|
402
|
+
for(i = 0; i < RARRAY(v_proto)->len; i++){
|
403
|
+
v_arg = RARRAY(v_args)->ptr[i];
|
404
|
+
|
405
|
+
/* Convert nil to NULL. Otherwise convert as appropriate. */
|
406
|
+
if(NIL_P(v_arg))
|
407
|
+
param.params[i] = (unsigned long)NULL;
|
408
|
+
else if(v_arg == Qtrue)
|
409
|
+
param.params[i] = TRUE;
|
410
|
+
else if(v_arg == Qfalse)
|
411
|
+
param.params[i] = FALSE;
|
412
|
+
else
|
413
|
+
switch(ptr->prototype[i]){
|
414
|
+
case _T_LONG:
|
415
|
+
param.params[i] = NUM2ULONG(v_arg);
|
416
|
+
break;
|
417
|
+
case _T_INTEGER:
|
418
|
+
param.params[i] = NUM2INT(v_arg);
|
419
|
+
break;
|
420
|
+
case _T_POINTER:
|
421
|
+
if(FIXNUM_P(v_arg)){
|
422
|
+
param.params[i] = NUM2ULONG(v_arg);
|
423
|
+
}
|
424
|
+
else{
|
425
|
+
StringValue(v_arg);
|
426
|
+
rb_str_modify(v_arg);
|
427
|
+
param.params[i] = (unsigned long)StringValuePtr(v_arg);
|
428
|
+
}
|
429
|
+
break;
|
430
|
+
case _T_CALLBACK:
|
431
|
+
ActiveCallback = v_arg;
|
432
|
+
param.params[i] = (LPARAM)CallbackFunction;
|
433
|
+
break;
|
434
|
+
default:
|
435
|
+
param.params[i] = NUM2ULONG(v_arg);
|
436
|
+
}
|
437
|
+
}
|
438
|
+
|
439
|
+
/* Call the function, get the return value */
|
440
|
+
return_value = ptr->function(param);
|
441
|
+
|
442
|
+
/* Return the appropriate type based on the return type specified
|
443
|
+
* in the constructor.
|
444
|
+
*/
|
445
|
+
switch(ptr->return_type){
|
446
|
+
case _T_INTEGER:
|
447
|
+
v_return = INT2NUM(return_value);
|
448
|
+
break;
|
449
|
+
case _T_LONG:
|
450
|
+
v_return = LONG2NUM(return_value);
|
451
|
+
break;
|
452
|
+
case _T_VOID:
|
453
|
+
v_return = Qnil;
|
454
|
+
break;
|
455
|
+
case _T_POINTER:
|
456
|
+
if(!return_value)
|
457
|
+
v_return = Qnil;
|
458
|
+
else
|
459
|
+
v_return = rb_str_new2((TCHAR*)return_value);
|
460
|
+
break;
|
461
|
+
default:
|
462
|
+
v_return = INT2NUM(0);
|
463
|
+
}
|
464
|
+
|
465
|
+
return v_return;
|
466
|
+
}
|
467
|
+
|
468
|
+
/*
|
469
|
+
* Wraps the Windows API functions in a Ruby interface.
|
470
|
+
*/
|
471
|
+
void Init_api(){
|
472
|
+
VALUE mWin32, cAPI, cCallback;
|
473
|
+
|
474
|
+
/* Modules and Classes */
|
475
|
+
|
476
|
+
/* The Win32 module serves as a namespace only */
|
477
|
+
mWin32 = rb_define_module("Win32");
|
478
|
+
|
479
|
+
/* The API class encapsulates a function pointer to Windows API function */
|
480
|
+
cAPI = rb_define_class_under(mWin32, "API", rb_cObject);
|
481
|
+
|
482
|
+
/* The API::Callback class encapsulates a Windows CALLBACK function */
|
483
|
+
cCallback = rb_define_class_under(cAPI, "Callback", rb_cObject);
|
484
|
+
|
485
|
+
/* The API::Error class is raised if the constructor fails */
|
486
|
+
cAPIError = rb_define_class_under(cAPI, "Error", rb_eRuntimeError);
|
487
|
+
|
488
|
+
/* The API::Callback::Error class is raised if the constructor fails */
|
489
|
+
cCallbackError = rb_define_class_under(cCallback, "Error", rb_eRuntimeError);
|
490
|
+
|
491
|
+
/* Miscellaneous */
|
492
|
+
rb_define_alloc_func(cAPI, api_allocate);
|
493
|
+
|
494
|
+
/* Win32::API Instance Methods */
|
495
|
+
rb_define_method(cAPI, "initialize", api_init, -1);
|
496
|
+
rb_define_method(cAPI, "call", api_call, -1);
|
497
|
+
|
498
|
+
rb_define_method(cCallback, "initialize", callback_init, -1);
|
499
|
+
|
500
|
+
/* The name of the DLL that exports the API function */
|
501
|
+
rb_define_attr(cAPI, "dll_name", 1, 0);
|
502
|
+
|
503
|
+
/* The name of the function */
|
504
|
+
rb_define_attr(cAPI, "function_name", 1, 0);
|
505
|
+
|
506
|
+
/* The prototype, returned as an array of characters */
|
507
|
+
rb_define_attr(cAPI, "prototype", 1, 0);
|
508
|
+
|
509
|
+
/* The return type, returned as a single character, P, L, I, V or B */
|
510
|
+
rb_define_attr(cAPI, "return_type", 1, 0);
|
511
|
+
|
512
|
+
/* Win32::API::Callback Instance Methods */
|
513
|
+
|
514
|
+
/* The prototype, returned as an array of characters */
|
515
|
+
rb_define_attr(cCallback, "prototype", 1, 0);
|
516
|
+
|
517
|
+
/* The return type, returned as a single character, P, L, I, V or B */
|
518
|
+
rb_define_attr(cCallback, "return_type", 1, 0);
|
519
|
+
|
520
|
+
/* Constants */
|
521
|
+
|
522
|
+
/* 1.0.0: The version of this library, returned as a String */
|
523
|
+
rb_define_const(cAPI, "VERSION", rb_str_new2(WINDOWS_API_VERSION));
|
524
|
+
}
|
data/lib/win32/api.so
CHANGED
Binary file
|
data/test/tc_win32_api.rb
CHANGED
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-
|
6
|
+
version: 1.0.4
|
7
|
+
date: 2007-10-29 00:00:00 -07:00
|
8
8
|
summary: A superior replacement for Win32API
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -29,9 +29,12 @@ post_install_message:
|
|
29
29
|
authors:
|
30
30
|
- Daniel J. Berger
|
31
31
|
files:
|
32
|
-
-
|
32
|
+
- ext/extconf.rb
|
33
|
+
- ext/win32
|
34
|
+
- ext/win32/api.c
|
33
35
|
- test/tc_win32_api.rb
|
34
36
|
- test/tc_win32_api_callback.rb
|
37
|
+
- lib/win32/api.so
|
35
38
|
- README
|
36
39
|
- CHANGES
|
37
40
|
- MANIFEST
|
@@ -44,6 +47,7 @@ extra_rdoc_files:
|
|
44
47
|
- README
|
45
48
|
- CHANGES
|
46
49
|
- MANIFEST
|
50
|
+
- ext/win32/api.c
|
47
51
|
executables: []
|
48
52
|
|
49
53
|
extensions: []
|