windows-api 0.4.0 → 0.4.1

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