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

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 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')