windows-api 0.4.3 → 0.4.4

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.
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