windows-api 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 947bf71415752d4089b21d5d768bc5bcd3c11c28
4
- data.tar.gz: efbecf8bb158ad198d531b04034d09e841b50c2c
3
+ metadata.gz: a676d1572a63e8bce0c29b891ae0318037f06e59
4
+ data.tar.gz: cd3bf62aba802cec22554f1325946505eb8f3081
5
5
  SHA512:
6
- metadata.gz: 5d8a0d631b46662c913a5c35f48f5de34320f534621b0ccdbf6ef1a8be32542303fc387e8c465e77ba857d67fe1df8c8ad2637a6b65e36929800e1785cd5eb44
7
- data.tar.gz: 502dd5015dd7ff56c736d4b0ad9ba9efbe1812803628146976bed8157b8db002413c99f0baa75087e4ebe65521c1760dab1a1367c8165ee6d1e6dc34d523b1eb
6
+ metadata.gz: 003418351fc46d6ffc391c3359562312dc71ec567300130236ce6b1b85caf10565c67b633f14a6735d1067117badc171220059f1f632d4e13eddcb8a4fcfb60d
7
+ data.tar.gz: 3caed1e8447b6e6841003ed428d916686c7168f5d3a4a50a050528ea59a4870e52e6127f4b40960774cf1156bd2f7d988a6b276952daac7c388b44d9d5ed7a2e
data/CHANGES CHANGED
@@ -1,64 +1,68 @@
1
- == 0.4.3 - 20-Oct-2014
2
- * Updates to the gemspec and Rakefile.
3
-
4
- == 0.4.2 - 13-Jul-2012
5
- * Fixed a bug in the way MSVCRT_DLL is set. Thanks go to Park Heesob for
6
- the spot and patch.
7
- * Some minor test refactoring and cosmetic udpates.
8
-
9
- == 0.4.1 - 27-Jan-2012
10
- * Switched Config to RbConfig to silence 1.9 warnings. Thanks go to
11
- Cameron Cox for the patch.
12
- * Some updates to the README, Rakefile, gemspec and test files.
13
-
14
- == 0.4.0 - 18-Oct-2009
15
- * Methods that begin with an underscore, such as _umask(), are now preserved.
16
- A method alias is also created without an underscore, e.g. umask().
17
- * Added the gem task to the Rakefile.
18
- * Minor updates to the gemspec.
19
-
20
- == 0.3.1 - 18-Aug-2009
21
- * Changed license to Artistic 2.0.
22
- * Some gemspec updates, including the addition of a license, an updated
23
- description and a dependency update.
24
- * One test update for VC++ 9.
25
-
26
- == 0.3.0 - 1-Feb-2009
27
- * No longer explicitly checks for an error in the constructor. It lets the
28
- underlying Win32::API library deal with it.
29
- * More dynamic handling and setting of the MSVCRT_DLL variable.
30
- * Added a WideString implementation. Internal use only.
31
-
32
- == 0.2.4 - 18-Jul-2008
33
- * Eliminated unnecessary LoadLibrary() attempts for functions that explicitly
34
- end with an 'A' or 'W', and all MSVCRT functions, since they have no 'A'
35
- or 'W' equivalent.
36
- * Replaced all of the attr_reader's with a delegation scheme using Forwardable.
37
- All Win32::API functions now delegate to the internally stored Win32::API
38
- object instead of reimplementing them. This change also fixed a bug where
39
- the effective_function_name method did not work properly.
40
- * Added more tests, and fixed one assertion that was wrong (the prototype).
41
- * Some documentation additions.
42
-
43
- == 0.2.3 - 26-Apr-2008
44
- * Improved API.auto_constant and API.auto_method handling for functions that
45
- start with a lower case character or an underscore.
46
-
47
- == 0.2.2 - 17-Apr-2008
48
- * Added the Windows::MSVCRT_DLL constant so that users can specify MSVCRT_DLL
49
- for the DLL name and it will do the right thing, instead of having to worry
50
- about specifying a DLL or associated DLL.
51
-
52
- == 0.2.1 - 10-Feb-2008
53
- * Added support for long data type names, e.g. 'DWORD' instead of 'L', for
54
- both the prototype and return type.
55
-
56
- == 0.2.0 - 20-Sep-2007
57
- * Now requires the win32-api library.
58
- * Replaced class variables with class instance variables to prevent conflicts.
59
-
60
- == 0.1.1 - 25-May-2007
61
- * Fixed a void parameter bug.
62
-
63
- == 0.1.0 - 24-May-2007
64
- * Initial release
1
+ == 0.4.4 - 18-Mar-2015
2
+ * Removed a duplicate hash entry. Thanks go to Baptiste Courtois for the spot.
3
+ * Added some specialized test tasks.
4
+
5
+ == 0.4.3 - 20-Oct-2014
6
+ * Updates to the gemspec and Rakefile.
7
+
8
+ == 0.4.2 - 13-Jul-2012
9
+ * Fixed a bug in the way MSVCRT_DLL is set. Thanks go to Park Heesob for
10
+ the spot and patch.
11
+ * Some minor test refactoring and cosmetic udpates.
12
+
13
+ == 0.4.1 - 27-Jan-2012
14
+ * Switched Config to RbConfig to silence 1.9 warnings. Thanks go to
15
+ Cameron Cox for the patch.
16
+ * Some updates to the README, Rakefile, gemspec and test files.
17
+
18
+ == 0.4.0 - 18-Oct-2009
19
+ * Methods that begin with an underscore, such as _umask(), are now preserved.
20
+ A method alias is also created without an underscore, e.g. umask().
21
+ * Added the gem task to the Rakefile.
22
+ * Minor updates to the gemspec.
23
+
24
+ == 0.3.1 - 18-Aug-2009
25
+ * Changed license to Artistic 2.0.
26
+ * Some gemspec updates, including the addition of a license, an updated
27
+ description and a dependency update.
28
+ * One test update for VC++ 9.
29
+
30
+ == 0.3.0 - 1-Feb-2009
31
+ * No longer explicitly checks for an error in the constructor. It lets the
32
+ underlying Win32::API library deal with it.
33
+ * More dynamic handling and setting of the MSVCRT_DLL variable.
34
+ * Added a WideString implementation. Internal use only.
35
+
36
+ == 0.2.4 - 18-Jul-2008
37
+ * Eliminated unnecessary LoadLibrary() attempts for functions that explicitly
38
+ end with an 'A' or 'W', and all MSVCRT functions, since they have no 'A'
39
+ or 'W' equivalent.
40
+ * Replaced all of the attr_reader's with a delegation scheme using Forwardable.
41
+ All Win32::API functions now delegate to the internally stored Win32::API
42
+ object instead of reimplementing them. This change also fixed a bug where
43
+ the effective_function_name method did not work properly.
44
+ * Added more tests, and fixed one assertion that was wrong (the prototype).
45
+ * Some documentation additions.
46
+
47
+ == 0.2.3 - 26-Apr-2008
48
+ * Improved API.auto_constant and API.auto_method handling for functions that
49
+ start with a lower case character or an underscore.
50
+
51
+ == 0.2.2 - 17-Apr-2008
52
+ * Added the Windows::MSVCRT_DLL constant so that users can specify MSVCRT_DLL
53
+ for the DLL name and it will do the right thing, instead of having to worry
54
+ about specifying a DLL or associated DLL.
55
+
56
+ == 0.2.1 - 10-Feb-2008
57
+ * Added support for long data type names, e.g. 'DWORD' instead of 'L', for
58
+ both the prototype and return type.
59
+
60
+ == 0.2.0 - 20-Sep-2007
61
+ * Now requires the win32-api library.
62
+ * Replaced class variables with class instance variables to prevent conflicts.
63
+
64
+ == 0.1.1 - 25-May-2007
65
+ * Fixed a void parameter bug.
66
+
67
+ == 0.1.0 - 24-May-2007
68
+ * Initial release
data/README CHANGED
@@ -79,15 +79,15 @@
79
79
  if you installed this as a gem.
80
80
 
81
81
  == Future Plans
82
- This library will eventually be dropped in favor of FFI once I'm convinced
83
- that FFI is stable for both mingw and mswin.
82
+ I have no future plans for this library other than bug fixes. You should
83
+ use FFI instead of win32-api for all projects where possible.
84
84
 
85
85
  == Bugs
86
86
  None that I'm aware of. Please submit any bugs to the project page at
87
87
  https://github.com/djberg96/windows-api.
88
88
 
89
89
  == Copyright
90
- (C) 2007-2014, Daniel J. Berger
90
+ (C) 2007-2015, Daniel J. Berger
91
91
 
92
92
  == License
93
93
  Artistic 2.0
data/Rakefile CHANGED
@@ -28,4 +28,20 @@ Rake::TestTask.new do |test|
28
28
  test.verbose = true
29
29
  end
30
30
 
31
+ namespace :test do
32
+ desc "Test the core windows-api library"
33
+ Rake::TestTask.new(:api) do |t|
34
+ t.warning = true
35
+ t.verbose = true
36
+ t.test_files = FileList['test/test_windows_api.rb']
37
+ end
38
+
39
+ desc "Test the wide string methods"
40
+ Rake::TestTask.new(:wide) do |t|
41
+ t.warning = true
42
+ t.verbose = true
43
+ t.test_files = FileList['test/test_wide_string.rb']
44
+ end
45
+ end
46
+
31
47
  task :default => :test
@@ -1,504 +1,503 @@
1
- require 'win32/api'
2
- require 'rbconfig'
3
- require 'forwardable'
4
- include RbConfig
5
-
6
- # The Windows module serves as a namespace only
7
- module Windows
8
-
9
- # With Microsoft Visual C++ 8 and later users should use the associated
10
- # DLL instead of msvcrt directly, if possible.
11
- if CONFIG['host_os'].split('_')[1]
12
- if CONFIG['host_os'].split('_')[1].to_i >= 80
13
- MSVCRT_DLL = 'msvcr' + CONFIG['host_os'].split('_')[1]
14
- else
15
- MSVCRT_DLL = 'msvcrt'
16
- end
17
- else
18
- MSVCRT_DLL = 'msvcrt'
19
- end
20
-
21
- # Wrapper around the Win32::API class
22
- class API
23
- extend Forwardable
24
-
25
- # The version of the windows-api library
26
- VERSION = '0.4.3'
27
-
28
- # The methods from Win32::API are delegated to the appropriate object
29
- def_delegators(:@api, :function_name, :dll_name, :prototype)
30
- def_delegators(:@api, :return_type, :effective_function_name)
31
-
32
- private
33
-
34
- # Verbose data types that can be used instead of single letters
35
- DATA_TYPES = {
36
- 'ATOM' => 'I',
37
- 'BOOL' => 'B',
38
- 'BOOLEAN' => 'B',
39
- 'BYTE' => 'I',
40
- 'CALLBACK' => 'K',
41
- 'CHAR' => 'I',
42
- 'COLORREF' => 'L',
43
- 'DWORD' => 'L',
44
- 'DWORDLONG' => 'L',
45
- 'DWORD_PTR' => 'P',
46
- 'DWORD32' => 'I',
47
- 'DWORD64' => 'L',
48
- 'HACCEL' => 'L',
49
- 'HANDLE' => 'L',
50
- 'HBITMAP' => 'L',
51
- 'HBRUSH' => 'L',
52
- 'HCOLORSPACE' => 'L',
53
- 'HCONV' => 'L',
54
- 'HDC' => 'L',
55
- 'HFILE' => 'I',
56
- 'HKEY' => 'L',
57
- 'HFONT' => 'L',
58
- 'HINSTANCE' => 'L',
59
- 'HKEY' => 'L',
60
- 'HLOCAL' => 'L',
61
- 'HMENU' => 'L',
62
- 'HMODULE' => 'L',
63
- 'HRESULT' => 'L',
64
- 'HWND' => 'L',
65
- 'INT' => 'I',
66
- 'INT_PTR' => 'P',
67
- 'INT32' => 'I',
68
- 'INT64' => 'L',
69
- 'LANGID' => 'I',
70
- 'LCID' => 'L',
71
- 'LCTYPE' => 'L',
72
- 'LONG' => 'L',
73
- 'LONGLONG' => 'L',
74
- 'LONG_PTR' => 'P',
75
- 'LONG32' => 'L',
76
- 'LONG64' => 'L',
77
- 'LPARAM' => 'P',
78
- 'LPBOOL' => 'P',
79
- 'LPBYTE' => 'P',
80
- 'LPCOLORREF' => 'P',
81
- 'LPCSTR' => 'P',
82
- 'LPCTSTR' => 'P',
83
- 'LPCVOID' => 'L',
84
- 'LPCWSTR' => 'P',
85
- 'LPDWORD' => 'P',
86
- 'LPHANDLE' => 'P',
87
- 'LPINT' => 'P',
88
- 'LPLONG' => 'P',
89
- 'LPSTR' => 'P',
90
- 'LPTSTR' => 'P',
91
- 'LPVOID' => 'L',
92
- 'LPWORD' => 'P',
93
- 'LPWSTR' => 'P',
94
- 'LRESULT' => 'P',
95
- 'PBOOL' => 'P',
96
- 'PBOOLEAN' => 'P',
97
- 'PBYTE' => 'P',
98
- 'PHKEY' => 'P',
99
- 'SC_HANDLE' => 'L',
100
- 'SC_LOCK' => 'L',
101
- 'SERVICE_STATUS_HANDLE' => 'L',
102
- 'SHORT' => 'I',
103
- 'SIZE_T' => 'P',
104
- 'TCHAR' => 'L',
105
- 'UINT' => 'I',
106
- 'UINT_PTR' => 'P',
107
- 'UINT32' => 'I',
108
- 'UINT64' => 'L',
109
- 'ULONG' => 'L',
110
- 'ULONGLONG' => 'L',
111
- 'ULONG_PTR' => 'P',
112
- 'ULONG32' => 'L',
113
- 'ULONG64' => 'L',
114
- 'USHORT' => 'I',
115
- 'USN' => 'L',
116
- 'WINAPI' => 'L',
117
- 'WORD' => 'I'
118
- }
119
-
120
- public
121
-
122
- @auto_constant = false
123
- @auto_method = false
124
- @auto_unicode = false
125
- @auto_namespace = nil
126
-
127
- # Returns the value of the @auto_constant class instance variable. The
128
- # default is nil, i.e. none. See the Windows::API.auto_constant=
129
- # documentation for more information.
130
- #
131
- def self.auto_constant
132
- @auto_constant
133
- end
134
-
135
- # Automatically sets a constant to match the function name.
136
- #
137
- # The standard practice for defining Windows::API objects is to use
138
- # a constant that matches the function name. For example, this is a
139
- # typical idiom:
140
- #
141
- # module Windows
142
- # module File
143
- # GetFileAttributes = API.new('GetFileAttributes', 'P','L')
144
- # end
145
- # end
146
- #
147
- # With the API.auto_constant value set to true you can avoid the
148
- # assignment step and the matching constant name will be automatically
149
- # set for you in the namespace defined in API.auto_namespace. In other
150
- # words, this example is identical to the one above:
151
- #
152
- # module Windows
153
- # module File
154
- # API.auto_constant = true
155
- # API.auto_namespace = 'Windows::File'
156
- # API.new('GetFileAttributes', 'P', 'L')
157
- # end
158
- # end
159
- #
160
- # If the auto_constant class variable is set to true, but no
161
- # auto_namespace is set, an error will be raised. Note that the
162
- # namespace must refer to an existing module (not a class).
163
- #--
164
- # TODO: If there's a way to automatically grab the namespace internally,
165
- # nesting and all, I'd love to know the solution.
166
- #
167
- def self.auto_constant=(bool)
168
- @auto_constant = bool
169
- end
170
-
171
- # Returns the value of the auto_namespace class instance variable. Used
172
- # in conjunction with API.auto_constant and/or API.auto_method.
173
- #
174
- def self.auto_namespace
175
- @auto_namespace
176
- end
177
-
178
- # Sets the value of the auto_namespace class nstance variable. The
179
- # default is nil, i.e. none. Use in conjunction with the auto_constant
180
- # and/or auto_method class variables, this method will automatically set
181
- # a constant and/or method in +namespace+ equal to the function name set
182
- # in the constructor.
183
- #
184
- # The +namespace+ must refer to an existing module, not a class.
185
- #
186
- def self.auto_namespace=(namespace)
187
- @auto_namespace = namespace
188
- end
189
-
190
- # Returns the value of the auto_method class instance variable. Used in
191
- # conjunction with auto_unicode. See API.auto_method= for more
192
- # information.
193
- #
194
- def self.auto_method
195
- @auto_method
196
- end
197
-
198
- # If this option is set to true then a corresponding method is
199
- # automatically generated when you create a new Windows::API object.
200
- #
201
- # For example, instead of doing this:
202
- #
203
- # module Windows
204
- # module File
205
- # GetFileAttributes = API.new('GetFileAttributes', 'P', 'L')
206
- #
207
- # def GetFileAttributes(x)
208
- # GetFileAttributes.call(x)
209
- # end
210
- # end
211
- # end
212
- #
213
- # You can do this, and have the method autogenerated for you.
214
- #
215
- # module Windows
216
- # module File
217
- # API.auto_namespace = 'Windows::File'
218
- # API.auto_constant = true
219
- # API.auto_method = true
220
- # API.new('GetFileAttributes', 'P', 'L')
221
- # end
222
- # end
223
- #
224
- # include Windows::File
225
- # GetFileAttributes('C:/test.txt') # vs. GetFileAttributes.call
226
- #
227
- # If the Windows::API object is declared to be a boolean in the
228
- # constructor, then the method definition automatically includes a
229
- # '!= 0' clause at the end of the call. That way, you can do
230
- # 'if SomeMethod(x)' instead of having to do 'if SomeMethod(x) != 0',
231
- # and it will do the right thing.
232
- #
233
- # If the API.auto_unicode option is also set to true, then you will
234
- # get three method definitions. The standard function name, the explicit
235
- # ANSI ('A') version and the explicit Unicode/wide version ('W'). The
236
- # exception to this rule is that the explicit ANSI and Unicode methods
237
- # will NOT be generated if the function passed to the constructor
238
- # already ends with 'A' or 'W'.
239
- #
240
- def self.auto_method=(bool)
241
- @auto_method = bool
242
- end
243
-
244
- # Returns the value of the auto_unicode class instance variable. This
245
- # is used in conjunction with the auto_method and/or auto_constant class
246
- # variables. Not significant if neither of those variables are set.
247
- #
248
- def self.auto_unicode
249
- @auto_unicode
250
- end
251
-
252
- # If set to true, and the auto_constant variable is set, then the
253
- # automatic constant generation will generate the explicit ANSI ('A')
254
- # and Unicode/wide ('W') versions of the function passed to the
255
- # constructor, if such versions exist. Likewise, if the the
256
- # auto_method variable is set, then explicit ANSI and Unicode methods
257
- # are generated.
258
- #
259
- # Here's a typical idiom:
260
- #
261
- # module Windows
262
- # module Path
263
- # API.auto_namespace = Windows::Path
264
- # API.auto_constant = true
265
- # API.new('shlwapi', 'PathAddBackslash', 'P', 'P')
266
- # API.new('shlwapi', 'PathAddBackslashA', 'P', 'P')
267
- # API.new('shlwapi', 'PathAddBackslashW', 'P', 'P')
268
- # end
269
- # end
270
- #
271
- # That can be reduced to this:
272
- #
273
- # module Windows
274
- # module Path
275
- # API.auto_namespace = Windows::Path
276
- # API.auto_constant = true
277
- # API.auto_unicode = true
278
- # API.new('shlwapi', 'PathAddBackslash', 'P', 'P')
279
- # end
280
- # end
281
- #
282
- # This value is ignored if the function passed to the constructor
283
- # already ends with an 'A' or 'W'.
284
- #
285
- def self.auto_unicode=(bool)
286
- @auto_unicode = bool
287
- end
288
-
289
- # call-seq:
290
- # API.new(func, proto='V', rtype='L', dll='kernel32')
291
- #
292
- # Creates and returns a new Windows::API object. The +func+ is the
293
- # name of the Windows function.
294
- #
295
- # The +proto+ is the function prototype for +func+. This can be a
296
- # string or an array of characters. The possible valid characters
297
- # are 'I' (integer), 'B' (BOOL), 'L' (long), 'V' (void), or 'P' (pointer).
298
- # The default is void ('V').
299
- #
300
- # The +rtype+ argument is the return type for the function. The valid
301
- # characters are the same as for the +proto+. The default is long ('L').
302
- #
303
- # The 'B' (BOOL) return type is the same as 'I' (Integer). This is
304
- # significant only if the API.auto_method option is set to true, in which
305
- # case it alters the generated method definition slightly. See the
306
- # API.auto_method= class method for more information.
307
- #
308
- # The +dll+ is the name of the DLL file that the function is exported
309
- # from. The default is 'kernel32'.
310
- #
311
- # If the function cannot be found then an API::Error is raised (a subclass
312
- # of RuntimeError).
313
- #
314
- def initialize(func, proto='V', rtype='L', dll='kernel32')
315
- # Convert literal data types to values that win32-api understands
316
- if proto.is_a?(Array)
317
- proto.each_with_index{ |pt, index|
318
- if pt.length > 1
319
- proto[index].replace(DATA_TYPES[pt])
320
- end
321
- }
322
- end
323
-
324
- if rtype.length > 1
325
- rtype.replace(DATA_TYPES[rtype])
326
- end
327
-
328
- @function_name = func
329
- @prototype = proto
330
- @return_type = rtype == 'B' ? 'I' : rtype
331
- @dll_name = dll
332
- @boolean = rtype == 'B' ? true : false
333
-
334
- @api = Win32::API.new(func, proto, rtype, dll)
335
-
336
- api_a = nil
337
- api_w = nil
338
-
339
- # If the auto_unicode option is set, and the func is not already
340
- # an explicit ANSI or Wide function name, generate Win32::API
341
- # objects for those functions as well. Ignore errors because not
342
- # all functions have explicit ANSI or Wide character implementations.
343
- #
344
- # This entire bit of logic is skipped if the DLL is msvcrt, since
345
- # msvcrt functions never have explicit ANSI or Wide character
346
- # versions.
347
- #
348
- if Windows::API.auto_unicode && dll !~ /msvcr/i
349
- begin
350
- unless ['A', 'W'].include?(func[-1].chr)
351
- api_a = Win32::API.new("#{func}A", proto, rtype, dll)
352
- end
353
- rescue RuntimeError
354
- end
355
-
356
- begin
357
- unless ['W', 'A'].include?(func[-1].chr)
358
- api_w = Win32::API.new("#{func}W", proto, rtype, dll)
359
- end
360
- rescue RuntimeError
361
- end
362
- end
363
-
364
- func_upper = nil
365
-
366
- # Automatically define a constant matching the function name if the
367
- # auto_constant option is set. Lower case method names will have a
368
- # capitalized equivalent created, e.g. Memcpy for memcpy, etc.
369
- #
370
- if Windows::API.auto_constant && Windows::API.auto_namespace
371
- if Windows::API.auto_namespace != 'Windows'
372
- namespace = class_for(Windows::API.auto_namespace)
373
- else
374
- namespace = Windows::API.auto_namespace
375
- end
376
-
377
- # Convert e.g. 'strstr' to 'Strstr' as an equivalent constant
378
- if ('A'..'Z').include?(func[0].chr)
379
- namespace.const_set(func, @api)
380
- else
381
- func_upper = func.dup
382
- if func_upper[0].chr == '_'
383
- func_upper = func_upper[1, func_upper.length]
384
- end
385
- func_upper[0, 1] = func_upper[0].chr.capitalize
386
- namespace.const_set(func_upper, @api)
387
- end
388
-
389
- # Automatically define the explicit ANSI and Unicode functions
390
- # as constants as well, if appropriate.
391
- #
392
- if Windows::API.auto_unicode
393
- namespace.const_set("#{func}A", api_a) if api_a
394
- namespace.const_set("#{func}W", api_w) if api_w
395
- end
396
- end
397
-
398
- # Automatically define a method in the auto_namespace if the
399
- # auto_method option is set. The explicit ANSI and Unicode methods
400
- # are added as well if the auto_unicode option is set to true.
401
- #
402
- if Windows::API.auto_method && Windows::API.auto_namespace
403
- if proto == 'V'
404
- proto = ''
405
- else
406
- n = 0
407
- if proto.is_a?(String)
408
- proto = proto.split('').map{ |e|
409
- n += 1
410
- e.downcase + n.to_s
411
- }.join(', ')
412
- else
413
- proto = proto.map{ |e|
414
- n += 1
415
- e.downcase + n.to_s
416
- }.join(', ')
417
- end
418
- end
419
-
420
- # Use the upper case function equivalent if defined
421
- call_func = func_upper || func
422
-
423
- if @boolean
424
- string = <<-EOC
425
- module #{Windows::API.auto_namespace}
426
- def #{func}(#{proto})
427
- #{call_func}.call(#{proto}) != 0
428
- end
429
- EOC
430
-
431
- if api_a
432
- string << %Q{
433
- def #{func}A(#{proto})
434
- #{call_func}A.call(#{proto}) != 0
435
- end
436
- }
437
- end
438
-
439
- if api_w
440
- string << %Q{
441
- def #{func}W(#{proto})
442
- #{call_func}W.call(#{proto}) != 0
443
- end
444
- }
445
- end
446
-
447
- string << 'end'
448
- else
449
- string = <<-EOC
450
- module #{Windows::API.auto_namespace}
451
- def #{func}(#{proto})
452
- #{call_func}.call(#{proto})
453
- end
454
- EOC
455
-
456
- if api_a
457
- string << %Q{
458
- def #{func}A(#{proto})
459
- #{call_func}A.call(#{proto})
460
- end
461
- }
462
- end
463
-
464
- if api_w
465
- string << %Q{
466
- def #{func}W(#{proto})
467
- #{call_func}W.call(#{proto})
468
- end
469
- }
470
- end
471
-
472
- # Create aliases for methods with an underscore that do not
473
- # require an underscore, e.g. umask and _umask.
474
- if func[0].chr == '_'
475
- func_alias = func[1, func.length]
476
- string << "alias #{func_alias} #{func}\n"
477
- end
478
-
479
- string << 'end'
480
- end
481
-
482
- eval(string)
483
- end
484
- end
485
-
486
- # Calls the function name set in the constructor.
487
- #
488
- def call(*args)
489
- @api.call(*args)
490
- end
491
-
492
- private
493
-
494
- # Get a module's namespace. This is basically the equivalent of
495
- # the rb_path2class() function from intern.h
496
- #
497
- def class_for(class_name)
498
- names = class_name.split("::")
499
- result = Object
500
- names.each{ |n| result = result.const_get(n) }
501
- result
502
- end
503
- end
504
- end
1
+ require 'win32/api'
2
+ require 'rbconfig'
3
+ require 'forwardable'
4
+ include RbConfig
5
+
6
+ # The Windows module serves as a namespace only
7
+ module Windows
8
+
9
+ # With Microsoft Visual C++ 8 and later users should use the associated
10
+ # DLL instead of msvcrt directly, if possible.
11
+ if CONFIG['host_os'].split('_')[1]
12
+ if CONFIG['host_os'].split('_')[1].to_i >= 80
13
+ MSVCRT_DLL = 'msvcr' + CONFIG['host_os'].split('_')[1]
14
+ else
15
+ MSVCRT_DLL = 'msvcrt'
16
+ end
17
+ else
18
+ MSVCRT_DLL = 'msvcrt'
19
+ end
20
+
21
+ # Wrapper around the Win32::API class
22
+ class API
23
+ extend Forwardable
24
+
25
+ # The version of the windows-api library
26
+ VERSION = '0.4.4'
27
+
28
+ # The methods from Win32::API are delegated to the appropriate object
29
+ def_delegators(:@api, :function_name, :dll_name, :prototype)
30
+ def_delegators(:@api, :return_type, :effective_function_name)
31
+
32
+ private
33
+
34
+ # Verbose data types that can be used instead of single letters
35
+ DATA_TYPES = {
36
+ 'ATOM' => 'I',
37
+ 'BOOL' => 'B',
38
+ 'BOOLEAN' => 'B',
39
+ 'BYTE' => 'I',
40
+ 'CALLBACK' => 'K',
41
+ 'CHAR' => 'I',
42
+ 'COLORREF' => 'L',
43
+ 'DWORD' => 'L',
44
+ 'DWORDLONG' => 'L',
45
+ 'DWORD_PTR' => 'P',
46
+ 'DWORD32' => 'I',
47
+ 'DWORD64' => 'L',
48
+ 'HACCEL' => 'L',
49
+ 'HANDLE' => 'L',
50
+ 'HBITMAP' => 'L',
51
+ 'HBRUSH' => 'L',
52
+ 'HCOLORSPACE' => 'L',
53
+ 'HCONV' => 'L',
54
+ 'HDC' => 'L',
55
+ 'HFILE' => 'I',
56
+ 'HFONT' => 'L',
57
+ 'HINSTANCE' => 'L',
58
+ 'HKEY' => 'L',
59
+ 'HLOCAL' => 'L',
60
+ 'HMENU' => 'L',
61
+ 'HMODULE' => 'L',
62
+ 'HRESULT' => 'L',
63
+ 'HWND' => 'L',
64
+ 'INT' => 'I',
65
+ 'INT_PTR' => 'P',
66
+ 'INT32' => 'I',
67
+ 'INT64' => 'L',
68
+ 'LANGID' => 'I',
69
+ 'LCID' => 'L',
70
+ 'LCTYPE' => 'L',
71
+ 'LONG' => 'L',
72
+ 'LONGLONG' => 'L',
73
+ 'LONG_PTR' => 'P',
74
+ 'LONG32' => 'L',
75
+ 'LONG64' => 'L',
76
+ 'LPARAM' => 'P',
77
+ 'LPBOOL' => 'P',
78
+ 'LPBYTE' => 'P',
79
+ 'LPCOLORREF' => 'P',
80
+ 'LPCSTR' => 'P',
81
+ 'LPCTSTR' => 'P',
82
+ 'LPCVOID' => 'L',
83
+ 'LPCWSTR' => 'P',
84
+ 'LPDWORD' => 'P',
85
+ 'LPHANDLE' => 'P',
86
+ 'LPINT' => 'P',
87
+ 'LPLONG' => 'P',
88
+ 'LPSTR' => 'P',
89
+ 'LPTSTR' => 'P',
90
+ 'LPVOID' => 'L',
91
+ 'LPWORD' => 'P',
92
+ 'LPWSTR' => 'P',
93
+ 'LRESULT' => 'P',
94
+ 'PBOOL' => 'P',
95
+ 'PBOOLEAN' => 'P',
96
+ 'PBYTE' => 'P',
97
+ 'PHKEY' => 'P',
98
+ 'SC_HANDLE' => 'L',
99
+ 'SC_LOCK' => 'L',
100
+ 'SERVICE_STATUS_HANDLE' => 'L',
101
+ 'SHORT' => 'I',
102
+ 'SIZE_T' => 'P',
103
+ 'TCHAR' => 'L',
104
+ 'UINT' => 'I',
105
+ 'UINT_PTR' => 'P',
106
+ 'UINT32' => 'I',
107
+ 'UINT64' => 'L',
108
+ 'ULONG' => 'L',
109
+ 'ULONGLONG' => 'L',
110
+ 'ULONG_PTR' => 'P',
111
+ 'ULONG32' => 'L',
112
+ 'ULONG64' => 'L',
113
+ 'USHORT' => 'I',
114
+ 'USN' => 'L',
115
+ 'WINAPI' => 'L',
116
+ 'WORD' => 'I'
117
+ }
118
+
119
+ public
120
+
121
+ @auto_constant = false
122
+ @auto_method = false
123
+ @auto_unicode = false
124
+ @auto_namespace = nil
125
+
126
+ # Returns the value of the @auto_constant class instance variable. The
127
+ # default is nil, i.e. none. See the Windows::API.auto_constant=
128
+ # documentation for more information.
129
+ #
130
+ def self.auto_constant
131
+ @auto_constant
132
+ end
133
+
134
+ # Automatically sets a constant to match the function name.
135
+ #
136
+ # The standard practice for defining Windows::API objects is to use
137
+ # a constant that matches the function name. For example, this is a
138
+ # typical idiom:
139
+ #
140
+ # module Windows
141
+ # module File
142
+ # GetFileAttributes = API.new('GetFileAttributes', 'P','L')
143
+ # end
144
+ # end
145
+ #
146
+ # With the API.auto_constant value set to true you can avoid the
147
+ # assignment step and the matching constant name will be automatically
148
+ # set for you in the namespace defined in API.auto_namespace. In other
149
+ # words, this example is identical to the one above:
150
+ #
151
+ # module Windows
152
+ # module File
153
+ # API.auto_constant = true
154
+ # API.auto_namespace = 'Windows::File'
155
+ # API.new('GetFileAttributes', 'P', 'L')
156
+ # end
157
+ # end
158
+ #
159
+ # If the auto_constant class variable is set to true, but no
160
+ # auto_namespace is set, an error will be raised. Note that the
161
+ # namespace must refer to an existing module (not a class).
162
+ #--
163
+ # TODO: If there's a way to automatically grab the namespace internally,
164
+ # nesting and all, I'd love to know the solution.
165
+ #
166
+ def self.auto_constant=(bool)
167
+ @auto_constant = bool
168
+ end
169
+
170
+ # Returns the value of the auto_namespace class instance variable. Used
171
+ # in conjunction with API.auto_constant and/or API.auto_method.
172
+ #
173
+ def self.auto_namespace
174
+ @auto_namespace
175
+ end
176
+
177
+ # Sets the value of the auto_namespace class nstance variable. The
178
+ # default is nil, i.e. none. Use in conjunction with the auto_constant
179
+ # and/or auto_method class variables, this method will automatically set
180
+ # a constant and/or method in +namespace+ equal to the function name set
181
+ # in the constructor.
182
+ #
183
+ # The +namespace+ must refer to an existing module, not a class.
184
+ #
185
+ def self.auto_namespace=(namespace)
186
+ @auto_namespace = namespace
187
+ end
188
+
189
+ # Returns the value of the auto_method class instance variable. Used in
190
+ # conjunction with auto_unicode. See API.auto_method= for more
191
+ # information.
192
+ #
193
+ def self.auto_method
194
+ @auto_method
195
+ end
196
+
197
+ # If this option is set to true then a corresponding method is
198
+ # automatically generated when you create a new Windows::API object.
199
+ #
200
+ # For example, instead of doing this:
201
+ #
202
+ # module Windows
203
+ # module File
204
+ # GetFileAttributes = API.new('GetFileAttributes', 'P', 'L')
205
+ #
206
+ # def GetFileAttributes(x)
207
+ # GetFileAttributes.call(x)
208
+ # end
209
+ # end
210
+ # end
211
+ #
212
+ # You can do this, and have the method autogenerated for you.
213
+ #
214
+ # module Windows
215
+ # module File
216
+ # API.auto_namespace = 'Windows::File'
217
+ # API.auto_constant = true
218
+ # API.auto_method = true
219
+ # API.new('GetFileAttributes', 'P', 'L')
220
+ # end
221
+ # end
222
+ #
223
+ # include Windows::File
224
+ # GetFileAttributes('C:/test.txt') # vs. GetFileAttributes.call
225
+ #
226
+ # If the Windows::API object is declared to be a boolean in the
227
+ # constructor, then the method definition automatically includes a
228
+ # '!= 0' clause at the end of the call. That way, you can do
229
+ # 'if SomeMethod(x)' instead of having to do 'if SomeMethod(x) != 0',
230
+ # and it will do the right thing.
231
+ #
232
+ # If the API.auto_unicode option is also set to true, then you will
233
+ # get three method definitions. The standard function name, the explicit
234
+ # ANSI ('A') version and the explicit Unicode/wide version ('W'). The
235
+ # exception to this rule is that the explicit ANSI and Unicode methods
236
+ # will NOT be generated if the function passed to the constructor
237
+ # already ends with 'A' or 'W'.
238
+ #
239
+ def self.auto_method=(bool)
240
+ @auto_method = bool
241
+ end
242
+
243
+ # Returns the value of the auto_unicode class instance variable. This
244
+ # is used in conjunction with the auto_method and/or auto_constant class
245
+ # variables. Not significant if neither of those variables are set.
246
+ #
247
+ def self.auto_unicode
248
+ @auto_unicode
249
+ end
250
+
251
+ # If set to true, and the auto_constant variable is set, then the
252
+ # automatic constant generation will generate the explicit ANSI ('A')
253
+ # and Unicode/wide ('W') versions of the function passed to the
254
+ # constructor, if such versions exist. Likewise, if the the
255
+ # auto_method variable is set, then explicit ANSI and Unicode methods
256
+ # are generated.
257
+ #
258
+ # Here's a typical idiom:
259
+ #
260
+ # module Windows
261
+ # module Path
262
+ # API.auto_namespace = Windows::Path
263
+ # API.auto_constant = true
264
+ # API.new('shlwapi', 'PathAddBackslash', 'P', 'P')
265
+ # API.new('shlwapi', 'PathAddBackslashA', 'P', 'P')
266
+ # API.new('shlwapi', 'PathAddBackslashW', 'P', 'P')
267
+ # end
268
+ # end
269
+ #
270
+ # That can be reduced to this:
271
+ #
272
+ # module Windows
273
+ # module Path
274
+ # API.auto_namespace = Windows::Path
275
+ # API.auto_constant = true
276
+ # API.auto_unicode = true
277
+ # API.new('shlwapi', 'PathAddBackslash', 'P', 'P')
278
+ # end
279
+ # end
280
+ #
281
+ # This value is ignored if the function passed to the constructor
282
+ # already ends with an 'A' or 'W'.
283
+ #
284
+ def self.auto_unicode=(bool)
285
+ @auto_unicode = bool
286
+ end
287
+
288
+ # call-seq:
289
+ # API.new(func, proto='V', rtype='L', dll='kernel32')
290
+ #
291
+ # Creates and returns a new Windows::API object. The +func+ is the
292
+ # name of the Windows function.
293
+ #
294
+ # The +proto+ is the function prototype for +func+. This can be a
295
+ # string or an array of characters. The possible valid characters
296
+ # are 'I' (integer), 'B' (BOOL), 'L' (long), 'V' (void), or 'P' (pointer).
297
+ # The default is void ('V').
298
+ #
299
+ # The +rtype+ argument is the return type for the function. The valid
300
+ # characters are the same as for the +proto+. The default is long ('L').
301
+ #
302
+ # The 'B' (BOOL) return type is the same as 'I' (Integer). This is
303
+ # significant only if the API.auto_method option is set to true, in which
304
+ # case it alters the generated method definition slightly. See the
305
+ # API.auto_method= class method for more information.
306
+ #
307
+ # The +dll+ is the name of the DLL file that the function is exported
308
+ # from. The default is 'kernel32'.
309
+ #
310
+ # If the function cannot be found then an API::Error is raised (a subclass
311
+ # of RuntimeError).
312
+ #
313
+ def initialize(func, proto='V', rtype='L', dll='kernel32')
314
+ # Convert literal data types to values that win32-api understands
315
+ if proto.is_a?(Array)
316
+ proto.each_with_index{ |pt, index|
317
+ if pt.length > 1
318
+ proto[index].replace(DATA_TYPES[pt])
319
+ end
320
+ }
321
+ end
322
+
323
+ if rtype.length > 1
324
+ rtype.replace(DATA_TYPES[rtype])
325
+ end
326
+
327
+ @function_name = func
328
+ @prototype = proto
329
+ @return_type = rtype == 'B' ? 'I' : rtype
330
+ @dll_name = dll
331
+ @boolean = rtype == 'B' ? true : false
332
+
333
+ @api = Win32::API.new(func, proto, rtype, dll)
334
+
335
+ api_a = nil
336
+ api_w = nil
337
+
338
+ # If the auto_unicode option is set, and the func is not already
339
+ # an explicit ANSI or Wide function name, generate Win32::API
340
+ # objects for those functions as well. Ignore errors because not
341
+ # all functions have explicit ANSI or Wide character implementations.
342
+ #
343
+ # This entire bit of logic is skipped if the DLL is msvcrt, since
344
+ # msvcrt functions never have explicit ANSI or Wide character
345
+ # versions.
346
+ #
347
+ if Windows::API.auto_unicode && dll !~ /msvcr/i
348
+ begin
349
+ unless ['A', 'W'].include?(func[-1].chr)
350
+ api_a = Win32::API.new("#{func}A", proto, rtype, dll)
351
+ end
352
+ rescue RuntimeError
353
+ end
354
+
355
+ begin
356
+ unless ['W', 'A'].include?(func[-1].chr)
357
+ api_w = Win32::API.new("#{func}W", proto, rtype, dll)
358
+ end
359
+ rescue RuntimeError
360
+ end
361
+ end
362
+
363
+ func_upper = nil
364
+
365
+ # Automatically define a constant matching the function name if the
366
+ # auto_constant option is set. Lower case method names will have a
367
+ # capitalized equivalent created, e.g. Memcpy for memcpy, etc.
368
+ #
369
+ if Windows::API.auto_constant && Windows::API.auto_namespace
370
+ if Windows::API.auto_namespace != 'Windows'
371
+ namespace = class_for(Windows::API.auto_namespace)
372
+ else
373
+ namespace = Windows::API.auto_namespace
374
+ end
375
+
376
+ # Convert e.g. 'strstr' to 'Strstr' as an equivalent constant
377
+ if ('A'..'Z').include?(func[0].chr)
378
+ namespace.const_set(func, @api)
379
+ else
380
+ func_upper = func.dup
381
+ if func_upper[0].chr == '_'
382
+ func_upper = func_upper[1, func_upper.length]
383
+ end
384
+ func_upper[0, 1] = func_upper[0].chr.capitalize
385
+ namespace.const_set(func_upper, @api)
386
+ end
387
+
388
+ # Automatically define the explicit ANSI and Unicode functions
389
+ # as constants as well, if appropriate.
390
+ #
391
+ if Windows::API.auto_unicode
392
+ namespace.const_set("#{func}A", api_a) if api_a
393
+ namespace.const_set("#{func}W", api_w) if api_w
394
+ end
395
+ end
396
+
397
+ # Automatically define a method in the auto_namespace if the
398
+ # auto_method option is set. The explicit ANSI and Unicode methods
399
+ # are added as well if the auto_unicode option is set to true.
400
+ #
401
+ if Windows::API.auto_method && Windows::API.auto_namespace
402
+ if proto == 'V'
403
+ proto = ''
404
+ else
405
+ n = 0
406
+ if proto.is_a?(String)
407
+ proto = proto.split('').map{ |e|
408
+ n += 1
409
+ e.downcase + n.to_s
410
+ }.join(', ')
411
+ else
412
+ proto = proto.map{ |e|
413
+ n += 1
414
+ e.downcase + n.to_s
415
+ }.join(', ')
416
+ end
417
+ end
418
+
419
+ # Use the upper case function equivalent if defined
420
+ call_func = func_upper || func
421
+
422
+ if @boolean
423
+ string = <<-EOC
424
+ module #{Windows::API.auto_namespace}
425
+ def #{func}(#{proto})
426
+ #{call_func}.call(#{proto}) != 0
427
+ end
428
+ EOC
429
+
430
+ if api_a
431
+ string << %Q{
432
+ def #{func}A(#{proto})
433
+ #{call_func}A.call(#{proto}) != 0
434
+ end
435
+ }
436
+ end
437
+
438
+ if api_w
439
+ string << %Q{
440
+ def #{func}W(#{proto})
441
+ #{call_func}W.call(#{proto}) != 0
442
+ end
443
+ }
444
+ end
445
+
446
+ string << 'end'
447
+ else
448
+ string = <<-EOC
449
+ module #{Windows::API.auto_namespace}
450
+ def #{func}(#{proto})
451
+ #{call_func}.call(#{proto})
452
+ end
453
+ EOC
454
+
455
+ if api_a
456
+ string << %Q{
457
+ def #{func}A(#{proto})
458
+ #{call_func}A.call(#{proto})
459
+ end
460
+ }
461
+ end
462
+
463
+ if api_w
464
+ string << %Q{
465
+ def #{func}W(#{proto})
466
+ #{call_func}W.call(#{proto})
467
+ end
468
+ }
469
+ end
470
+
471
+ # Create aliases for methods with an underscore that do not
472
+ # require an underscore, e.g. umask and _umask.
473
+ if func[0].chr == '_'
474
+ func_alias = func[1, func.length]
475
+ string << "alias #{func_alias} #{func}\n"
476
+ end
477
+
478
+ string << 'end'
479
+ end
480
+
481
+ eval(string)
482
+ end
483
+ end
484
+
485
+ # Calls the function name set in the constructor.
486
+ #
487
+ def call(*args)
488
+ @api.call(*args)
489
+ end
490
+
491
+ private
492
+
493
+ # Get a module's namespace. This is basically the equivalent of
494
+ # the rb_path2class() function from intern.h
495
+ #
496
+ def class_for(class_name)
497
+ names = class_name.split("::")
498
+ result = Object
499
+ names.each{ |n| result = result.const_get(n) }
500
+ result
501
+ end
502
+ end
503
+ end