windows-api 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES CHANGED
@@ -1,3 +1,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