win32-api 1.1.0-x86-mswin32-60 → 1.2.0-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,12 @@
1
+ = 1.2.0 - 22-Jul-2008
2
+ * Added support for the 'S' (string) prototype and return type. It can be
3
+ used instead of 'P' (pointer) for const char*.
4
+ * Some internal refactoring. The attempts to load ANSI and/or Wide character
5
+ versions of functions are skipped for MSVCRT functions, since they do not
6
+ exist. This eliminates some unnecessary LoadLibrary() calls.
7
+ * Added a couple of gem building Rake tasks.
8
+ * Added a few more tests.
9
+
1
10
  = 1.1.0 - 12-Jun-2008
2
11
  * Added the Windows::API::Function class. This is a subclass of Win32::API
3
12
  meant only for use with raw function pointers.
data/README CHANGED
@@ -39,10 +39,12 @@
39
39
  = Differences between win32-api and Win32API
40
40
  * This library has callback support
41
41
  * This library supports raw function pointers.
42
+ * This library supports a separate string type for const char* (S).
42
43
  * Argument order change. The DLL name is now last, not first.
43
- * Removed the 'N' and 'n'. Always use 'L' for longs now.
44
+ * Removed the 'N' and 'n' prototypes. Always use 'L' for longs now.
44
45
  * Sensible default arguments for the prototype, return type and DLL name.
45
- * Reader methods for the function name, prototype, return type and DLL.
46
+ * Reader methods for the function name, effective function name, prototype,
47
+ return type and DLL.
46
48
  * Removed the support for lower case prototype and return types. Always
47
49
  use capital letters.
48
50
  * Resorts to wide character functions (where possible) when $KCODE is set
@@ -82,9 +84,12 @@
82
84
  implied warranties, including, without limitation, the implied
83
85
  warranties of merchantability and fitness for a particular purpose.
84
86
 
85
- = Known Bugs
86
- None that I'm aware of. Please submit any bug reports to the project page
87
- at http://www.rubyforge.org/projects/win32utils.
87
+ = Known Issues
88
+ Possible callback issues when dealing with multi-threaded applications.
89
+ We are working on this for the next 1.2.x release.
90
+
91
+ Please submit any bug reports to the project page at
92
+ http://www.rubyforge.org/projects/win32utils.
88
93
 
89
94
  = Copyright
90
95
  (C) 2003-2008 Daniel J. Berger
@@ -95,4 +100,4 @@
95
100
 
96
101
  = Authors
97
102
  Daniel J. Berger
98
- Park Heesob
103
+ Park Heesob
data/ext/win32/api.c CHANGED
@@ -2,13 +2,14 @@
2
2
  #include <windows.h>
3
3
 
4
4
  #define MAX_BUF 1024
5
- #define WINDOWS_API_VERSION "1.1.0"
5
+ #define WINDOWS_API_VERSION "1.2.0"
6
6
 
7
7
  #define _T_VOID 0
8
8
  #define _T_LONG 1
9
9
  #define _T_POINTER 2
10
10
  #define _T_INTEGER 3
11
11
  #define _T_CALLBACK 4
12
+ #define _T_STRING 5
12
13
 
13
14
  VALUE cAPIError, cCallbackError;
14
15
 
@@ -80,8 +81,8 @@ char* StringError(DWORD dwError){
80
81
  *
81
82
  * The +prototype+ is the function prototype for the callback function. This
82
83
  * is a string. The possible valid characters are 'I' (integer), 'L' (long),
83
- * 'V' (void), or 'P' (pointer). Unlike API objects, API::Callback objects
84
- * do not have a default prototype.
84
+ * 'V' (void), 'P' (pointer) or 'S' (string). Unlike API objects, API::Callback
85
+ * objects do not have a default prototype.
85
86
  *
86
87
  * The +return+ argument is the return type for the callback function. The
87
88
  * valid characters are the same as for the +prototype+. The default is
@@ -93,6 +94,7 @@ char* StringError(DWORD dwError){
93
94
  *
94
95
  * EnumWindows = API.new('EnumWindows', 'KP', 'L', 'user32')
95
96
  * GetWindowText = API.new('GetWindowText', 'LPI', 'I', 'user32')
97
+ *
96
98
  * EnumWindowsProc = API::Callback.new('LP', 'I'){ |handle, param|
97
99
  * buf = "\0" * 200
98
100
  * GetWindowText.call(handle, buf, 200);
@@ -112,7 +114,7 @@ static VALUE callback_init(int argc, VALUE* argv, VALUE self)
112
114
  /* Validate prototype characters */
113
115
  for(i = 0; i < RSTRING(v_proto)->len; i++){
114
116
  switch(RSTRING(v_proto)->ptr[i]){
115
- case 'I': case 'L': case 'P': case 'V':
117
+ case 'I': case 'L': case 'P': case 'V': case 'S':
116
118
  break;
117
119
  default:
118
120
  rb_raise(cCallbackError, "Illegal prototype '%c'",
@@ -139,8 +141,13 @@ static VALUE callback_init(int argc, VALUE* argv, VALUE self)
139
141
  *
140
142
  * The +prototype+ is the function prototype for +function+. This can be a
141
143
  * string or an array of characters. The possible valid characters are 'I'
142
- * (integer), 'L' (long), 'V' (void), 'P' (pointer), or 'K' (callback).
144
+ * (integer), 'L' (long), 'V' (void), 'P' (pointer), 'K' (callback) or 'S'
145
+ * (string).
146
+ *
143
147
  * The default is void ('V').
148
+ *
149
+ * Constant (const char*) strings should use 'S'. Pass by reference string
150
+ * buffers should use 'P'. The former is faster, but cannot be modified.
144
151
  *
145
152
  * The +return+ argument is the return type for the function. The valid
146
153
  * characters are the same as for the +prototype+. The default is 'L' (long).
@@ -227,33 +234,44 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
227
234
  second = "A";
228
235
  }
229
236
 
237
+ // Skip the ANSI and Wide function checks for MSVCRT functions.
230
238
  if(!fProc){
231
- VALUE v_ascii = rb_str_new3(v_proc);
232
- v_ascii = rb_str_cat(v_ascii, first, 1);
233
- fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_ascii)->ptr));
234
-
235
- if(!fProc){
236
- VALUE v_unicode = rb_str_new3(v_proc);
237
- v_unicode = rb_str_cat(v_unicode, second, 1);
238
- fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_unicode)->ptr));
239
+ if(!strcmp(RSTRING(v_dll)->ptr, "msvcrt")){
240
+ rb_raise(
241
+ cAPIError,
242
+ "GetProcAddress() failed for '%s': %s",
243
+ RSTRING(v_proc)->ptr,
244
+ StringError(GetLastError())
245
+ );
246
+ }
247
+ else{
248
+ VALUE v_ascii = rb_str_new3(v_proc);
249
+ v_ascii = rb_str_cat(v_ascii, first, 1);
250
+ fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_ascii)->ptr));
239
251
 
240
252
  if(!fProc){
241
- rb_raise(
242
- cAPIError,
243
- "GetProcAddress() failed for '%s', '%s' and '%s': %s",
244
- RSTRING(v_proc)->ptr,
245
- RSTRING(v_ascii)->ptr,
246
- RSTRING(v_unicode)->ptr,
247
- StringError(GetLastError())
248
- );
253
+ VALUE v_unicode = rb_str_new3(v_proc);
254
+ v_unicode = rb_str_cat(v_unicode, second, 1);
255
+ fProc = GetProcAddress(hLibrary, TEXT(RSTRING(v_unicode)->ptr));
256
+
257
+ if(!fProc){
258
+ rb_raise(
259
+ cAPIError,
260
+ "GetProcAddress() failed for '%s', '%s' and '%s': %s",
261
+ RSTRING(v_proc)->ptr,
262
+ RSTRING(v_ascii)->ptr,
263
+ RSTRING(v_unicode)->ptr,
264
+ StringError(GetLastError())
265
+ );
266
+ }
267
+ else{
268
+ rb_iv_set(self, "@effective_function_name", v_unicode);
269
+ }
249
270
  }
250
271
  else{
251
- rb_iv_set(self, "@effective_function_name", v_unicode);
272
+ rb_iv_set(self, "@effective_function_name", v_ascii);
252
273
  }
253
274
  }
254
- else{
255
- rb_iv_set(self, "@effective_function_name", v_ascii);
256
- }
257
275
  }
258
276
  else{
259
277
  rb_iv_set(self, "@effective_function_name", v_proc);
@@ -281,6 +299,9 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
281
299
  case 'K':
282
300
  ptr->prototype[i] = _T_CALLBACK;
283
301
  break;
302
+ case 'S':
303
+ ptr->prototype[i] = _T_STRING;
304
+ break;
284
305
  default:
285
306
  rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
286
307
  }
@@ -308,6 +329,9 @@ static VALUE api_init(int argc, VALUE* argv, VALUE self)
308
329
  case 'V':
309
330
  ptr->return_type = _T_VOID;
310
331
  break;
332
+ case 'S':
333
+ ptr->return_type = _T_STRING;
334
+ break;
311
335
  default:
312
336
  rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
313
337
  }
@@ -397,6 +421,9 @@ static VALUE func_init(int argc, VALUE* argv, VALUE self){
397
421
  case 'K':
398
422
  ptr->prototype[i] = _T_CALLBACK;
399
423
  break;
424
+ case 'S':
425
+ ptr->prototype[i] = _T_STRING;
426
+ break;
400
427
  default:
401
428
  rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
402
429
  }
@@ -424,6 +451,9 @@ static VALUE func_init(int argc, VALUE* argv, VALUE self){
424
451
  case 'V':
425
452
  ptr->return_type = _T_VOID;
426
453
  break;
454
+ case 'S':
455
+ ptr->return_type = _T_STRING;
456
+ break;
427
457
  default:
428
458
  rb_raise(cAPIError, "Illegal prototype '%s'", RARRAY(v_proto)->ptr[i]);
429
459
  }
@@ -495,6 +525,9 @@ DWORD CallbackFunction(PARAM param)
495
525
  case 'L':
496
526
  return NUM2ULONG(v_retval);
497
527
  break;
528
+ case 'S':
529
+ return (unsigned long)RSTRING(v_retval)->ptr;
530
+ break;
498
531
  case 'P':
499
532
  if(NIL_P(v_retval)){
500
533
  return 0;
@@ -588,6 +621,9 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
588
621
  ActiveCallback = v_arg;
589
622
  param.params[i] = (LPARAM)CallbackFunction;
590
623
  break;
624
+ case _T_STRING:
625
+ param.params[i] = (unsigned long)RSTRING(v_arg)->ptr;
626
+ break;
591
627
  default:
592
628
  param.params[i] = NUM2ULONG(v_arg);
593
629
  }
@@ -615,6 +651,9 @@ static VALUE api_call(int argc, VALUE* argv, VALUE self){
615
651
  else
616
652
  v_return = rb_str_new2((TCHAR*)return_value);
617
653
  break;
654
+ case _T_STRING:
655
+ v_return = rb_str_new2((TCHAR*)return_value);
656
+ break;
618
657
  default:
619
658
  v_return = INT2NUM(0);
620
659
  }
@@ -676,7 +715,7 @@ void Init_api(){
676
715
  /* The prototype, returned as an array of characters */
677
716
  rb_define_attr(cAPI, "prototype", 1, 0);
678
717
 
679
- /* The return type, returned as a single character, P, L, I, V or B */
718
+ /* The return type, returned as a single character, S, P, L, I, V or B */
680
719
  rb_define_attr(cAPI, "return_type", 1, 0);
681
720
 
682
721
  /* Win32::API::Callback Instance Methods */
@@ -684,7 +723,7 @@ void Init_api(){
684
723
  /* The prototype, returned as an array of characters */
685
724
  rb_define_attr(cCallback, "prototype", 1, 0);
686
725
 
687
- /* The return type, returned as a single character, P, L, I, V or B */
726
+ /* The return type, returned as a single character, S, P, L, I, V or B */
688
727
  rb_define_attr(cCallback, "return_type", 1, 0);
689
728
 
690
729
  /* The numeric address of the function pointer */
@@ -692,6 +731,6 @@ void Init_api(){
692
731
 
693
732
  /* Constants */
694
733
 
695
- /* 1.1.0: The version of this library, returned as a String */
734
+ /* 1.2.0: The version of this library, returned as a String */
696
735
  rb_define_const(cAPI, "VERSION", rb_str_new2(WINDOWS_API_VERSION));
697
736
  }
data/lib/win32/api.so CHANGED
Binary file
@@ -13,10 +13,18 @@ class TC_Win32_API < Test::Unit::TestCase
13
13
  @buf = 0.chr * 260
14
14
  @api = API.new('GetCurrentDirectory', 'LP')
15
15
  @gle = API.new('GetLastError', 'V', 'L')
16
+ @str = API.new('strstr', 'PP', 'P', 'msvcrt')
16
17
  end
17
18
 
18
19
  def test_version
19
- assert_equal('1.1.0', API::VERSION)
20
+ assert_equal('1.2.0', API::VERSION)
21
+ end
22
+
23
+ def test_constructor_basic
24
+ assert_nothing_raised{ API.new('GetCurrentDirectory') }
25
+ assert_nothing_raised{ API.new('GetCurrentDirectory', 'LP') }
26
+ assert_nothing_raised{ API.new('GetCurrentDirectory', 'LP', 'L') }
27
+ assert_nothing_raised{ API.new('GetCurrentDirectory', 'LP', 'L', 'kernel32') }
20
28
  end
21
29
 
22
30
  def test_call
@@ -38,11 +46,13 @@ class TC_Win32_API < Test::Unit::TestCase
38
46
  def test_function_name
39
47
  assert_respond_to(@api, :function_name)
40
48
  assert_equal('GetCurrentDirectory', @api.function_name)
49
+ assert_equal('strstr', @str.function_name)
41
50
  end
42
51
 
43
52
  def test_effective_function_name
44
53
  assert_respond_to(@api, :effective_function_name)
45
54
  assert_equal('GetCurrentDirectoryA', @api.effective_function_name)
55
+ assert_equal('strstr', @str.effective_function_name)
46
56
 
47
57
  @api = API.new('GetCurrentDirectoryA', 'LP')
48
58
  assert_equal('GetCurrentDirectoryA', @api.effective_function_name)
@@ -68,9 +78,30 @@ class TC_Win32_API < Test::Unit::TestCase
68
78
  end
69
79
 
70
80
  def test_constructor_expected_failures
81
+ assert_raise(ArgumentError){ API.new }
71
82
  assert_raise(API::Error){ API.new('GetUserName', 'PL', 'I', 'foo') }
72
- assert_raise(API::Error){ API.new('GetUserName', 'X', 'I', 'foo') }
73
- assert_raise(API::Error){ API.new('GetUserName', 'PL', 'X', 'foo') }
83
+ assert_raise(API::Error){ API.new('GetUserName', 'X', 'I', 'kernel32') }
84
+ assert_raise(API::Error){ API.new('GetUserName', 'PL', 'X', 'kernel32') }
85
+ end
86
+
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
+ def test_constructor_expected_failure_messages
90
+ begin
91
+ API.new('GetBlah')
92
+ rescue API::Error => err
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
97
+
98
+ begin
99
+ API.new('strxxx', 'P', 'P', 'msvcrt')
100
+ rescue API::Error => err
101
+ expected = "GetProcAddress() failed for 'strxxx': The specified "
102
+ expected += "procedure could not be found."
103
+ assert_equal(expected, err.to_s)
104
+ end
74
105
  end
75
106
 
76
107
  def test_call_expected_failures
@@ -81,5 +112,6 @@ class TC_Win32_API < Test::Unit::TestCase
81
112
  @buf = nil
82
113
  @api = nil
83
114
  @gle = nil
115
+ @str = nil
84
116
  end
85
117
  end
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: win32-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: x86-mswin32-60
6
6
  authors:
7
7
  - Daniel J. Berger
8
+ - Park Heesob
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2008-06-12 00:00:00 -06:00
13
+ date: 2008-07-22 00:00:00 -06:00
13
14
  default_executable:
14
15
  dependencies: []
15
16
 
@@ -25,17 +26,14 @@ extra_rdoc_files:
25
26
  - MANIFEST
26
27
  - ext/win32/api.c
27
28
  files:
28
- - ext/extconf.rb
29
- - ext/win32
30
- - ext/win32/api.c
29
+ - lib/win32/api.so
31
30
  - test/test_win32_api.rb
32
31
  - test/test_win32_api_callback.rb
33
32
  - test/test_win32_api_function.rb
34
- - lib/win32
35
- - lib/win32/api.so
36
33
  - README
37
34
  - CHANGES
38
35
  - MANIFEST
36
+ - ext/win32/api.c
39
37
  has_rdoc: true
40
38
  homepage: http://www.rubyforge.org/projects/win32utils
41
39
  post_install_message:
@@ -58,9 +56,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
56
  requirements: []
59
57
 
60
58
  rubyforge_project: win32utils
61
- rubygems_version: 1.1.1
59
+ rubygems_version: 1.2.0
62
60
  signing_key:
63
61
  specification_version: 2
64
62
  summary: A superior replacement for Win32API
65
- test_files: []
66
-
63
+ test_files:
64
+ - test/test_win32_api.rb
65
+ - test/test_win32_api_callback.rb
66
+ - test/test_win32_api_function.rb
data/ext/extconf.rb DELETED
@@ -1,11 +0,0 @@
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
-
11
- create_makefile('win32/api', 'win32')