win 0.1.27 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -5
- data/.gitignore +21 -21
- data/LICENSE +20 -20
- data/README.rdoc +175 -175
- data/Rakefile +58 -58
- data/VERSION +1 -1
- data/features/support/env.rb +4 -4
- data/features/win.feature +9 -9
- data/lib/win/dde.rb +1234 -1234
- data/lib/win/error.rb +1223 -1223
- data/lib/win/extensions.rb +41 -41
- data/lib/win/gui.rb +16 -16
- data/lib/win/gui/dialog.rb +50 -50
- data/lib/win/gui/input.rb +319 -319
- data/lib/win/gui/message.rb +807 -807
- data/lib/win/gui/window.rb +679 -679
- data/lib/win/library.rb +463 -463
- data/spec/spec.opts +2 -2
- data/spec/spec_helper.rb +140 -135
- data/spec/test_apps/locknote/LockNote.exe +0 -0
- data/spec/win/dde_spec.rb +528 -528
- data/spec/win/error_spec.rb +112 -112
- data/spec/win/extensions_spec.rb +73 -73
- data/spec/win/gui/dialog_spec.rb +43 -43
- data/spec/win/gui/input_spec.rb +101 -101
- data/spec/win/gui/message_spec.rb +236 -236
- data/spec/win/gui/window_spec.rb +549 -548
- data/spec/win/library_spec.rb +341 -341
- data/win.gemspec +87 -87
- metadata +34 -17
data/lib/win/library.rb
CHANGED
@@ -1,464 +1,464 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
require 'win/extensions'
|
3
|
-
|
4
|
-
# Related Windows API functions are grouped by topic and defined in separate namespaces (modules),
|
5
|
-
# that also contain related constants and convenience methods. For example, Win::
|
6
|
-
# contains only functions related to DDE protocol such as DdeInitialize() as well as constants
|
7
|
-
# such as DMLERR_NO_ERROR, APPCLASS_STANDARD, etc. So if you need only DDE-related functions,
|
8
|
-
# there is no need to load all the other modules, clogging your namespaces - just <b> require 'win/dde' </b>
|
9
|
-
# and be done with it. Win is just a top level namespace (container) that holds all the other modules.
|
10
|
-
#
|
11
|
-
module Win
|
12
|
-
|
13
|
-
module Errors # :nodoc:
|
14
|
-
class NotFoundError < NameError # :nodoc:
|
15
|
-
def initialize(name=nil, libs=nil)
|
16
|
-
super %Q[Function #{name ? "'#{name}' ": ""}not found#{libs ? " in #{libs}" : ""}"]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# WIN::Library is a module that extends FFI::Library and is used to connect to Windows API functions
|
22
|
-
# and wrap them into Ruby methods using 'function' declaration. If you do not see your favorite Windows
|
23
|
-
# API functions among those already defined, you can easily 'include Win::Library’ into your module
|
24
|
-
# and declare them using ‘function’ class method (macro) - it does a lot of heavy lifting for you and
|
25
|
-
# can be customized with options and code blocks to give you reusable API wrapper methods with the exact
|
26
|
-
# behavior you need.
|
27
|
-
#
|
28
|
-
module Library
|
29
|
-
|
30
|
-
# Win::Library::API is a wrapper for callable function API object that mimics Win32::API
|
31
|
-
class API
|
32
|
-
|
33
|
-
# The name of the DLL(s) that export this API function
|
34
|
-
attr_reader :dll_name
|
35
|
-
|
36
|
-
# Ruby namespace (module) where this API function is attached
|
37
|
-
attr_reader :namespace
|
38
|
-
|
39
|
-
# The name of the function passed to the constructor
|
40
|
-
attr_reader :function_name
|
41
|
-
|
42
|
-
# The name of the actual Windows API function. For example, if you passed 'GetUserName' to the
|
43
|
-
# constructor, then the effective function name would be either 'GetUserNameA' or 'GetUserNameW'.
|
44
|
-
attr_accessor :effective_function_name
|
45
|
-
|
46
|
-
# The prototype, returned as an array of FFI types
|
47
|
-
attr_reader :prototype
|
48
|
-
|
49
|
-
# The return type (:void for no return value)
|
50
|
-
attr_reader :return_type
|
51
|
-
|
52
|
-
def initialize( namespace, function_name, effective_function_name, prototype, return_type, dll_name )
|
53
|
-
@namespace = namespace
|
54
|
-
@function_name = function_name
|
55
|
-
@effective_function_name = effective_function_name
|
56
|
-
@prototype = prototype
|
57
|
-
@return_type = return_type
|
58
|
-
@dll_name = dll_name
|
59
|
-
end
|
60
|
-
|
61
|
-
# Calls underlying CamelCase Windows API function with supplied args
|
62
|
-
def call( *args )
|
63
|
-
@namespace.send(@function_name.to_sym, *args)
|
64
|
-
end
|
65
|
-
|
66
|
-
# alias_method :[], :call
|
67
|
-
end
|
68
|
-
|
69
|
-
# Contains class methods (macros) that can be used in any module mixing in Win::Library
|
70
|
-
module ClassMethods
|
71
|
-
|
72
|
-
# Mapping of Windows API types and one-letter shortcuts into FFI types.
|
73
|
-
# Like :ATOM => :ushort, :LPARAM => :long, :c => :char, :i => :int
|
74
|
-
TYPES = {
|
75
|
-
# FFI type shortcuts
|
76
|
-
C: :uchar, #– 8-bit unsigned character (byte)
|
77
|
-
c: :char, # 8-bit character (byte)
|
78
|
-
# :int8 – 8-bit signed integer
|
79
|
-
# :uint8 – 8-bit unsigned integer
|
80
|
-
S: :ushort, # – 16-bit unsigned integer (Win32/API: S used for string params)
|
81
|
-
s: :short, # – 16-bit signed integer
|
82
|
-
# :uint16 – 16-bit unsigned integer
|
83
|
-
# :int16 – 16-bit signed integer
|
84
|
-
I: :uint, # 32-bit unsigned integer
|
85
|
-
i: :int, # 32-bit signed integer
|
86
|
-
# :uint32 – 32-bit unsigned integer
|
87
|
-
# :int32 – 32-bit signed integer
|
88
|
-
L: :ulong, # unsigned long int – platform-specific size
|
89
|
-
l: :long, # long int – platform-specific size. For discussion of platforms, see:
|
90
|
-
# (http://groups.google.com/group/ruby-ffi/browse_thread/thread/4762fc77130339b1)
|
91
|
-
# :int64 – 64-bit signed integer
|
92
|
-
# :uint64 – 64-bit unsigned integer
|
93
|
-
# :long_long – 64-bit signed integer
|
94
|
-
# :ulong_long – 64-bit unsigned integer
|
95
|
-
F: :float, # 32-bit floating point
|
96
|
-
D: :double, # 64-bit floating point (double-precision)
|
97
|
-
P: :pointer, # pointer – platform-specific size
|
98
|
-
p: :string, # C-style (NULL-terminated) character string (Win32API: S)
|
99
|
-
B: :bool, # (?? 1 byte in C++)
|
100
|
-
V: :void, # For functions that return nothing (return type void).
|
101
|
-
v: :void, # For functions that return nothing (return type void).
|
102
|
-
# For function argument type only:
|
103
|
-
# :buffer_in – Similar to :pointer, but optimized for Buffers that the function can only read (not write).
|
104
|
-
# :buffer_out – Similar to :pointer, but optimized for Buffers that the function can only write (not read).
|
105
|
-
# :buffer_inout – Similar to :pointer, but may be optimized for Buffers.
|
106
|
-
# :varargs – Variable arguments
|
107
|
-
# :enum - Enumerable type (should be defined)
|
108
|
-
# :char_array - ??
|
109
|
-
|
110
|
-
# Windows-specific type defs (ms-help://MS.MSDNQTR.v90.en/winprog/winprog/windows_data_types.htm):
|
111
|
-
ATOM: :ushort, # Atom ~= Symbol: Atom table stores strings and corresponding identifiers. Application
|
112
|
-
# places a string in an atom table and receives a 16-bit integer, called an atom, that
|
113
|
-
# can be used to access the string. Placed string is called an atom name.
|
114
|
-
# See: http://msdn.microsoft.com/en-us/library/ms648708%28VS.85%29.aspx
|
115
|
-
BOOL: :bool,
|
116
|
-
BOOLEAN: :bool,
|
117
|
-
BYTE: :uchar, # Byte (8 bits). Declared as unsigned char
|
118
|
-
#CALLBACK: K, # Win32.API gem-specific ?? MSDN: #define CALLBACK __stdcall
|
119
|
-
CHAR: :char, # 8-bit Windows (ANSI) character. See http://msdn.microsoft.com/en-us/library/dd183415%28VS.85%29.aspx
|
120
|
-
COLORREF: :uint32, # Red, green, blue (RGB) color value (32 bits). See COLORREF for more info.
|
121
|
-
DWORD: :uint32, # 32-bit unsigned integer. The range is 0 through 4,294,967,295 decimal.
|
122
|
-
DWORDLONG: :uint64, # 64-bit unsigned integer. The range is 0 through 18,446,744,073,709,551,615 decimal.
|
123
|
-
DWORD_PTR: :ulong, # Unsigned long type for pointer precision. Use when casting a pointer to a long type
|
124
|
-
# to perform pointer arithmetic. (Also commonly used for general 32-bit parameters that have
|
125
|
-
# been extended to 64 bits in 64-bit Windows.) BaseTsd.h: #typedef ULONG_PTR DWORD_PTR;
|
126
|
-
DWORD32: :uint32,
|
127
|
-
DWORD64: :uint64,
|
128
|
-
HALF_PTR: :int, # Half the size of a pointer. Use within a structure that contains a pointer and two small fields.
|
129
|
-
# BaseTsd.h: #ifdef (_WIN64) typedef int HALF_PTR; #else typedef short HALF_PTR;
|
130
|
-
HACCEL: :ulong, # (L) Handle to an accelerator table. WinDef.h: #typedef HANDLE HACCEL;
|
131
|
-
# See http://msdn.microsoft.com/en-us/library/ms645526%28VS.85%29.aspx
|
132
|
-
HANDLE: :ulong, # (L) Handle to an object. WinNT.h: #typedef PVOID HANDLE;
|
133
|
-
# todo: Platform-dependent! Need to change to :uint64 for Win64
|
134
|
-
HBITMAP: :ulong, # (L) Handle to a bitmap: http://msdn.microsoft.com/en-us/library/dd183377%28VS.85%29.aspx
|
135
|
-
HBRUSH: :ulong, # (L) Handle to a brush. http://msdn.microsoft.com/en-us/library/dd183394%28VS.85%29.aspx
|
136
|
-
HCOLORSPACE: :ulong, # (L) Handle to a color space. http://msdn.microsoft.com/en-us/library/ms536546%28VS.85%29.aspx
|
137
|
-
HCURSOR: :ulong, # (L) Handle to a cursor. http://msdn.microsoft.com/en-us/library/ms646970%28VS.85%29.aspx
|
138
|
-
HCONV: :ulong, # (L) Handle to a dynamic data exchange (DDE) conversation.
|
139
|
-
HCONVLIST: :ulong, # (L) Handle to a DDE conversation list. HANDLE - L ?
|
140
|
-
HDDEDATA: :ulong, # (L) Handle to DDE data (structure?)
|
141
|
-
HDC: :ulong, # (L) Handle to a device context (DC). http://msdn.microsoft.com/en-us/library/dd183560%28VS.85%29.aspx
|
142
|
-
HDESK: :ulong, # (L) Handle to a desktop. http://msdn.microsoft.com/en-us/library/ms682573%28VS.85%29.aspx
|
143
|
-
HDROP: :ulong, # (L) Handle to an internal drop structure.
|
144
|
-
HDWP: :ulong, # (L) Handle to a deferred window position structure.
|
145
|
-
HENHMETAFILE: :ulong, #(L) Handle to an enhanced metafile. http://msdn.microsoft.com/en-us/library/dd145051%28VS.85%29.aspx
|
146
|
-
HFILE: :uint, # (I) Special file handle to a file opened by OpenFile, not CreateFile.
|
147
|
-
# WinDef.h: #typedef int HFILE;
|
148
|
-
HFONT: :ulong, # (L) Handle to a font. http://msdn.microsoft.com/en-us/library/dd162470%28VS.85%29.aspx
|
149
|
-
HGDIOBJ: :ulong, # (L) Handle to a GDI object.
|
150
|
-
HGLOBAL: :ulong, # (L) Handle to a global memory block.
|
151
|
-
HHOOK: :ulong, # (L) Handle to a hook. http://msdn.microsoft.com/en-us/library/ms632589%28VS.85%29.aspx
|
152
|
-
HICON: :ulong, # (L) Handle to an icon. http://msdn.microsoft.com/en-us/library/ms646973%28VS.85%29.aspx
|
153
|
-
HINSTANCE: :ulong, # (L) Handle to an instance. This is the base address of the module in memory.
|
154
|
-
# HMODULE and HINSTANCE are the same today, but were different in 16-bit Windows.
|
155
|
-
HKEY: :ulong, # (L) Handle to a registry key.
|
156
|
-
HKL: :ulong, # (L) Input locale identifier.
|
157
|
-
HLOCAL: :ulong, # (L) Handle to a local memory block.
|
158
|
-
HMENU: :ulong, # (L) Handle to a menu. http://msdn.microsoft.com/en-us/library/ms646977%28VS.85%29.aspx
|
159
|
-
HMETAFILE: :ulong, # (L) Handle to a metafile. http://msdn.microsoft.com/en-us/library/dd145051%28VS.85%29.aspx
|
160
|
-
HMODULE: :ulong, # (L) Handle to an instance. Same as HINSTANCE today, but was different in 16-bit Windows.
|
161
|
-
HMONITOR: :ulong, # (L) Рandle to a display monitor. WinDef.h: if(WINVER >= 0x0500) typedef HANDLE HMONITOR;
|
162
|
-
HPALETTE: :ulong, # (L) Handle to a palette.
|
163
|
-
HPEN: :ulong, # (L) Handle to a pen. http://msdn.microsoft.com/en-us/library/dd162786%28VS.85%29.aspx
|
164
|
-
HRESULT: :long, # Return code used by COM interfaces. For more info, Structure of the COM Error Codes.
|
165
|
-
# To test an HRESULT value, use the FAILED and SUCCEEDED macros.
|
166
|
-
HRGN: :ulong, # (L) Handle to a region. http://msdn.microsoft.com/en-us/library/dd162913%28VS.85%29.aspx
|
167
|
-
HRSRC: :ulong, # (L) Handle to a resource.
|
168
|
-
HSZ: :ulong, # (L) Handle to a DDE string.
|
169
|
-
HWINSTA: :ulong, # (L) Handle to a window station. http://msdn.microsoft.com/en-us/library/ms687096%28VS.85%29.aspx
|
170
|
-
HWND: :ulong, # (L) Handle to a window. http://msdn.microsoft.com/en-us/library/ms632595%28VS.85%29.aspx
|
171
|
-
INT: :int, # 32-bit signed integer. The range is -2147483648 through 2147483647 decimal.
|
172
|
-
INT_PTR: :int, # Signed integer type for pointer precision. Use when casting a pointer to an integer
|
173
|
-
# to perform pointer arithmetic. BaseTsd.h:
|
174
|
-
#if defined(_WIN64) typedef __int64 INT_PTR; #else typedef int INT_PTR;
|
175
|
-
INT32: :int32, # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal.
|
176
|
-
INT64: :int64, # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807
|
177
|
-
LANGID: :ushort, # Language identifier. For more information, see Locales. WinNT.h: #typedef WORD LANGID;
|
178
|
-
# See http://msdn.microsoft.com/en-us/library/dd318716%28VS.85%29.aspx
|
179
|
-
LCID: :uint32, # Locale identifier. For more information, see Locales.
|
180
|
-
LCTYPE: :uint32, # Locale information type. For a list, see Locale Information Constants.
|
181
|
-
LGRPID: :uint32, # Language group identifier. For a list, see EnumLanguageGroupLocales.
|
182
|
-
LONG: :long, # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal.
|
183
|
-
LONG32: :int32, # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal.
|
184
|
-
LONG64: :int64, # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807
|
185
|
-
LONGLONG: :int64, # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807
|
186
|
-
LONG_PTR: :long, # Signed long type for pointer precision. Use when casting a pointer to a long to
|
187
|
-
# perform pointer arithmetic. BaseTsd.h:
|
188
|
-
#if defined(_WIN64) typedef __int64 LONG_PTR; #else typedef long LONG_PTR;
|
189
|
-
LPARAM: :long, # Message parameter. WinDef.h as follows: #typedef LONG_PTR LPARAM;
|
190
|
-
LPBOOL: :pointer, # Pointer to a BOOL. WinDef.h as follows: #typedef BOOL far *LPBOOL;
|
191
|
-
LPBYTE: :pointer, # Pointer to a BYTE. WinDef.h as follows: #typedef BYTE far *LPBYTE;
|
192
|
-
LPCOLORREF: :pointer, # Pointer to a COLORREF value. WinDef.h as follows: #typedef DWORD *LPCOLORREF;
|
193
|
-
LPCSTR: :pointer, # Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters.
|
194
|
-
# See Character Sets Used By Fonts. http://msdn.microsoft.com/en-us/library/dd183415%28VS.85%29.aspx
|
195
|
-
LPCTSTR: :pointer, # An LPCWSTR if UNICODE is defined, an LPCSTR otherwise.
|
196
|
-
LPCVOID: :pointer, # Pointer to a constant of any type. WinDef.h as follows: typedef CONST void *LPCVOID;
|
197
|
-
LPCWSTR: :pointer, # Pointer to a constant null-terminated string of 16-bit Unicode characters.
|
198
|
-
LPDWORD: :pointer, # Pointer to a DWORD. WinDef.h as follows: typedef DWORD *LPDWORD;
|
199
|
-
LPHANDLE: :pointer, # Pointer to a HANDLE. WinDef.h as follows: typedef HANDLE *LPHANDLE;
|
200
|
-
LPINT: :pointer, # Pointer to an INT.
|
201
|
-
LPLONG: :pointer, # Pointer to an LONG.
|
202
|
-
LPSTR: :pointer, # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters.
|
203
|
-
LPTSTR: :pointer, # An LPWSTR if UNICODE is defined, an LPSTR otherwise.
|
204
|
-
LPVOID: :pointer, # Pointer to any type.
|
205
|
-
LPWORD: :pointer, # Pointer to a WORD.
|
206
|
-
LPWSTR: :pointer, # Pointer to a null-terminated string of 16-bit Unicode characters.
|
207
|
-
LRESULT: :long, # Signed result of message processing. WinDef.h: typedef LONG_PTR LRESULT;
|
208
|
-
PBOOL: :pointer, # Pointer to a BOOL.
|
209
|
-
PBOOLEAN: :pointer, # Pointer to a BOOL.
|
210
|
-
PBYTE: :pointer, # Pointer to a BYTE.
|
211
|
-
PCHAR: :pointer, # Pointer to a CHAR.
|
212
|
-
PCSTR: :pointer, # Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters.
|
213
|
-
PCTSTR: :pointer, # A PCWSTR if UNICODE is defined, a PCSTR otherwise.
|
214
|
-
PCWSTR: :pointer, # Pointer to a constant null-terminated string of 16-bit Unicode characters.
|
215
|
-
PDWORD: :pointer, # Pointer to a DWORD.
|
216
|
-
PDWORDLONG: :pointer, # Pointer to a DWORDLONG.
|
217
|
-
PDWORD_PTR: :pointer, # Pointer to a DWORD_PTR.
|
218
|
-
PDWORD32: :pointer, # Pointer to a DWORD32.
|
219
|
-
PDWORD64: :pointer, # Pointer to a DWORD64.
|
220
|
-
PFLOAT: :pointer, # Pointer to a FLOAT.
|
221
|
-
PHALF_PTR: :pointer, # Pointer to a HALF_PTR.
|
222
|
-
PHANDLE: :pointer, # Pointer to a HANDLE.
|
223
|
-
PHKEY: :pointer, # Pointer to an HKEY.
|
224
|
-
PINT: :pointer, # Pointer to an INT.
|
225
|
-
PINT_PTR: :pointer, # Pointer to an INT_PTR.
|
226
|
-
PINT32: :pointer, # Pointer to an INT32.
|
227
|
-
PINT64: :pointer, # Pointer to an INT64.
|
228
|
-
PLCID: :pointer, # Pointer to an LCID.
|
229
|
-
PLONG: :pointer, # Pointer to a LONG.
|
230
|
-
PLONGLONG: :pointer, # Pointer to a LONGLONG.
|
231
|
-
PLONG_PTR: :pointer, # Pointer to a LONG_PTR.
|
232
|
-
PLONG32: :pointer, # Pointer to a LONG32.
|
233
|
-
PLONG64: :pointer, # Pointer to a LONG64.
|
234
|
-
POINTER_32: :pointer, # 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer.
|
235
|
-
POINTER_64: :pointer, # 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer.
|
236
|
-
POINTER_SIGNED: :pointer, # A signed pointer.
|
237
|
-
POINTER_UNSIGNED: :pointer, # An unsigned pointer.
|
238
|
-
PSHORT: :pointer, # Pointer to a SHORT.
|
239
|
-
PSIZE_T: :pointer, # Pointer to a SIZE_T.
|
240
|
-
PSSIZE_T: :pointer, # Pointer to a SSIZE_T.
|
241
|
-
PSTR: :pointer, # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.
|
242
|
-
PTBYTE: :pointer, # Pointer to a TBYTE.
|
243
|
-
PTCHAR: :pointer, # Pointer to a TCHAR.
|
244
|
-
PTSTR: :pointer, # A PWSTR if UNICODE is defined, a PSTR otherwise.
|
245
|
-
PUCHAR: :pointer, # Pointer to a UCHAR.
|
246
|
-
PUHALF_PTR: :pointer, # Pointer to a UHALF_PTR.
|
247
|
-
PUINT: :pointer, # Pointer to a UINT.
|
248
|
-
PUINT_PTR: :pointer, # Pointer to a UINT_PTR.
|
249
|
-
PUINT32: :pointer, # Pointer to a UINT32.
|
250
|
-
PUINT64: :pointer, # Pointer to a UINT64.
|
251
|
-
PULONG: :pointer, # Pointer to a ULONG.
|
252
|
-
PULONGLONG: :pointer, # Pointer to a ULONGLONG.
|
253
|
-
PULONG_PTR: :pointer, # Pointer to a ULONG_PTR.
|
254
|
-
PULONG32: :pointer, # Pointer to a ULONG32.
|
255
|
-
PULONG64: :pointer, # Pointer to a ULONG64.
|
256
|
-
PUSHORT: :pointer, # Pointer to a USHORT.
|
257
|
-
PVOID: :pointer, # Pointer to any type.
|
258
|
-
PWCHAR: :pointer, # Pointer to a WCHAR.
|
259
|
-
PWORD: :pointer, # Pointer to a WORD.
|
260
|
-
PWSTR: :pointer, # Pointer to a null- terminated string of 16-bit Unicode characters.
|
261
|
-
# For more information, see Character Sets Used By Fonts.
|
262
|
-
SC_HANDLE: :ulong, # (L) Handle to a service control manager database.
|
263
|
-
# See SCM Handles http://msdn.microsoft.com/en-us/library/ms685104%28VS.85%29.aspx
|
264
|
-
SC_LOCK: :pointer, # Lock to a service control manager database. For more information, see SCM Handles.
|
265
|
-
SERVICE_STATUS_HANDLE: :ulong, # (L) Handle to a service status value. See SCM Handles.
|
266
|
-
SHORT: :short, # A 16-bit integer. The range is –32768 through 32767 decimal.
|
267
|
-
SIZE_T: :ulong, # The maximum number of bytes to which a pointer can point. Use for a count that must span the full range of a pointer.
|
268
|
-
SSIZE_T: :long, # Signed SIZE_T.
|
269
|
-
TBYTE: :short, # A WCHAR if UNICODE is defined, a CHAR otherwise.TCHAR:
|
270
|
-
TCHAR: :short, # A WCHAR if UNICODE is defined, a CHAR otherwise.TCHAR:
|
271
|
-
UCHAR: :uchar, # Unsigned CHAR (8 bit)
|
272
|
-
UHALF_PTR: :uint, # Unsigned HALF_PTR. Use within a structure that contains a pointer and two small fields.
|
273
|
-
UINT: :uint, # Unsigned INT. The range is 0 through 4294967295 decimal.
|
274
|
-
UINT_PTR: :uint, # Unsigned INT_PTR.
|
275
|
-
UINT32: :uint32, # Unsigned INT32. The range is 0 through 4294967295 decimal.
|
276
|
-
UINT64: :uint64, # Unsigned INT64. The range is 0 through 18446744073709551615 decimal.
|
277
|
-
ULONG: :ulong, # Unsigned LONG. The range is 0 through 4294967295 decimal.
|
278
|
-
ULONGLONG: :ulong_long, # 64-bit unsigned integer. The range is 0 through 18446744073709551615 decimal.
|
279
|
-
ULONG_PTR: :ulong, # Unsigned LONG_PTR.
|
280
|
-
ULONG32: :uint32, # Unsigned INT32. The range is 0 through 4294967295 decimal.
|
281
|
-
ULONG64: :uint64, # Unsigned LONG64. The range is 0 through 18446744073709551615 decimal.
|
282
|
-
UNICODE_STRING: :pointer, # Pointer to some string structure??
|
283
|
-
USHORT: :ushort, # Unsigned SHORT. The range is 0 through 65535 decimal.
|
284
|
-
USN: :ulong_long, # Update sequence number (USN).
|
285
|
-
VOID: [], # Any type ? Only use it to indicate no arguments or no return value
|
286
|
-
WCHAR: :ushort, # 16-bit Unicode character. For more information, see Character Sets Used By Fonts.
|
287
|
-
# In WinNT.h: typedef wchar_t WCHAR;
|
288
|
-
#WINAPI: K, # Calling convention for system functions. WinDef.h: define WINAPI __stdcall
|
289
|
-
WORD: :ushort, # 16-bit unsigned integer. The range is 0 through 65535 decimal.
|
290
|
-
WPARAM: :uint # Message parameter. WinDef.h as follows: typedef UINT_PTR WPARAM;
|
291
|
-
}
|
292
|
-
|
293
|
-
##
|
294
|
-
# Defines new method wrappers for Windows API function call:
|
295
|
-
# - Defines method with original (CamelCase) API function name and original signature (matches MSDN description)
|
296
|
-
# - Defines method with snake_case name (converted from CamelCase function name) with enhanced API signature
|
297
|
-
# When defined snake_case method is called, it converts the arguments you provided into ones required by
|
298
|
-
# original API (adding defaults, mute and transitory args as necessary), executes API function call
|
299
|
-
# and (optionally) transforms the result before returning it. If a block is attached to
|
300
|
-
# method invocation, raw result is yielded to this block before final transformation take place
|
301
|
-
# - Defines aliases for enhanced method with more Rubyesque names for getters, setters and tests:
|
302
|
-
# GetWindowText -> window_test, SetWindowText -> window_text=, IsZoomed -> zoomed?
|
303
|
-
# ---
|
304
|
-
# You may modify default behavior of defined method by providing optional *def_block* to function definition.
|
305
|
-
# If you do so, snake_case method is defined based on your *def_block*. It receives callable API
|
306
|
-
# object for function being defined, arguments and (optional) runtime block with which the method
|
307
|
-
# will be called. Results coming from &def_block are then transformed and returned.
|
308
|
-
# So, your *def_block* should specify all the behavior of the method being defined. You can use *def_block* to:
|
309
|
-
# - Change original signature of API function, provide argument defaults, check argument types
|
310
|
-
# - Pack arguments into strings/structs for [in] or [in/out] parameters that expect a pointer
|
311
|
-
# - Allocate buffers/structs for pointers required by API functions [out] parameters
|
312
|
-
# - Unpack [out] and [in/out] parameters returned as pointers
|
313
|
-
# - Explicitly return results of API call that are returned in [out] and [in/out] parameters
|
314
|
-
# - Convert attached runtime blocks into callback functions and stuff them into [in] callback parameters
|
315
|
-
# - do other stuff that you think is appropriate to make Windows API function behavior more Ruby-like...
|
316
|
-
# ---
|
317
|
-
# Accepts following options:
|
318
|
-
# :dll:: Use this dll instead of default 'user32'
|
319
|
-
# :rename:: Use this name instead of standard (conventional) function name
|
320
|
-
# :alias(es):: Provides additional alias(es) for defined method
|
321
|
-
# :boolean:: Forces method to return true/false instead of nonzero/zero
|
322
|
-
# :zeronil:: Forces method to return nil if function result is zero
|
323
|
-
#
|
324
|
-
def function(name, params, returns, options={}, &def_block)
|
325
|
-
snake_name, effective_names, aliases = generate_names(name, options)
|
326
|
-
params, returns = generate_signature(params, returns)
|
327
|
-
libs = ffi_libraries.map(&:name)
|
328
|
-
boolean = options[:boolean]
|
329
|
-
zeronil = options[:zeronil]
|
330
|
-
|
331
|
-
effective_name = effective_names.inject(nil) do |func, effective_name|
|
332
|
-
func || begin
|
333
|
-
# tries to attach basic CamelCase method via FFI
|
334
|
-
attach_function(name, effective_name, params.dup, returns)
|
335
|
-
effective_name
|
336
|
-
rescue FFI::NotFoundError
|
337
|
-
nil
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
raise Win::Errors::NotFoundError.new(name, libs) unless effective_name
|
342
|
-
|
343
|
-
# Create API object that holds information about function names, params, etc
|
344
|
-
api = API.new(namespace, name, effective_name, params, returns, libs)
|
345
|
-
|
346
|
-
# Only define enhanced API if snake_name is different from original name (e.g. keybd_event)
|
347
|
-
unless snake_name.to_s == name.to_s
|
348
|
-
method_body = if def_block
|
349
|
-
if zeronil
|
350
|
-
->(*args, &block){ (res = def_block.(api, *args, &block)) != 0 ? res : nil }
|
351
|
-
elsif boolean
|
352
|
-
->(*args, &block){ def_block.(api, *args, &block) != 0 }
|
353
|
-
else
|
354
|
-
->(*args, &block){ def_block.(api, *args, &block) }
|
355
|
-
end
|
356
|
-
else
|
357
|
-
if zeronil
|
358
|
-
->(*args, &block){ (res = block ? block[api.call(*args)] : api.call(*args)) != 0 ? res : nil }
|
359
|
-
elsif boolean
|
360
|
-
->(*args, &block){ block ? block[api.call(*args)] : api.call(*args) != 0 }
|
361
|
-
else
|
362
|
-
->(*args, &block){ block ? block[api.call(*args)] : api.call(*args) }
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
define_method snake_name, &method_body # define snake_case instance method
|
367
|
-
|
368
|
-
eigenklass = class << self; self; end # Extracting eigenclass
|
369
|
-
eigenklass.class_eval do
|
370
|
-
define_method snake_name, &method_body # define snake_case class method
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
aliases.each {|ali| alias_method ali, snake_name } # define aliases
|
375
|
-
api #return api object from function declaration
|
376
|
-
end
|
377
|
-
|
378
|
-
# Try to define platform-specific function, rescue error, return message
|
379
|
-
#
|
380
|
-
def try_function(name, params, returns, options={}, &def_block)
|
381
|
-
begin
|
382
|
-
function name, params, returns, options={}, &def_block
|
383
|
-
rescue Win::Errors::NotFoundError
|
384
|
-
"This platform does not support function #{name}"
|
385
|
-
end
|
386
|
-
end
|
387
|
-
|
388
|
-
# Generates possible effective names for function in Win32 dll (name+A/W),
|
389
|
-
# Rubyesque name and aliases for method(s) defined based on function name,
|
390
|
-
#
|
391
|
-
def generate_names(name, options={})
|
392
|
-
name = name.to_s
|
393
|
-
effective_names = [name]
|
394
|
-
effective_names += ["#{name}A", "#{name}W"] unless name =~ /[WA]$/
|
395
|
-
aliases = ([options[:alias]] + [options[:aliases]]).flatten.compact
|
396
|
-
snake_name = options[:rename] || name.snake_case
|
397
|
-
case snake_name
|
398
|
-
when /^is_/
|
399
|
-
aliases << snake_name.sub(/^is_/, '') + '?'
|
400
|
-
when /^set_/
|
401
|
-
aliases << snake_name.sub(/^set_/, '')+ '='
|
402
|
-
when /^get_/
|
403
|
-
aliases << snake_name.sub(/^get_/, '')
|
404
|
-
end
|
405
|
-
[snake_name, effective_names, aliases]
|
406
|
-
end
|
407
|
-
|
408
|
-
##
|
409
|
-
# Generates params and returns (signature) containing only FFI-compliant types
|
410
|
-
#
|
411
|
-
def generate_signature(params, returns)
|
412
|
-
params = params.split(//) if params.respond_to?(:split) # Convert params string into array
|
413
|
-
params.map! {|param| TYPES[param.to_sym] || param} # Convert chars into FFI type symbols
|
414
|
-
returns = TYPES[returns.to_sym] || returns # Convert chars into FFI type symbols
|
415
|
-
[params, returns]
|
416
|
-
end
|
417
|
-
|
418
|
-
##
|
419
|
-
# Wrapper for FFI::Library#callback() that converts Win32/shortcut argument types into FFI-compliant types.
|
420
|
-
# This method overrides FFI.callback which must be aliased to FFI.attach_callback
|
421
|
-
#
|
422
|
-
def callback(name, params, returns)
|
423
|
-
params, returns = generate_signature(params, returns)
|
424
|
-
attach_callback name.to_sym, params, returns
|
425
|
-
end
|
426
|
-
|
427
|
-
##
|
428
|
-
# :method: namespace
|
429
|
-
# This method is meta-generated when Win::Library module is included into other module/class.
|
430
|
-
# It returns reference to including (host) class/module for use by Win::Library::API and class methods.
|
431
|
-
|
432
|
-
##
|
433
|
-
# Ensures that args count is equal to params count plus diff
|
434
|
-
#
|
435
|
-
def enforce_count(args, params, diff = 0)
|
436
|
-
num_args = args.size
|
437
|
-
num_params = params.size + diff #params == 'V' ? 0 : params.size + diff
|
438
|
-
if num_args != num_params
|
439
|
-
raise ArgumentError, "wrong number of arguments (#{num_args} for #{num_params})"
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
end
|
444
|
-
|
445
|
-
##
|
446
|
-
# Hook executed when Win::Library is included into class or module. It extends host class/module
|
447
|
-
# with both FFI::Library methods and Win::Library macro methods like 'function'.
|
448
|
-
#
|
449
|
-
def self.included(klass)
|
450
|
-
klass.extend FFI::Library
|
451
|
-
|
452
|
-
eigenklass = class << klass; self; end # Extracting host class's eigenclass
|
453
|
-
eigenklass.class_eval do
|
454
|
-
define_method(:namespace) {klass} # Defining new class method for host pointing to itself
|
455
|
-
alias_method :attach_callback, :callback
|
456
|
-
|
457
|
-
include ClassMethods
|
458
|
-
end
|
459
|
-
|
460
|
-
klass.ffi_lib 'user32', 'kernel32' # Default libraries
|
461
|
-
klass.ffi_convention :stdcall
|
462
|
-
end
|
463
|
-
end
|
1
|
+
require 'ffi'
|
2
|
+
require 'win/extensions'
|
3
|
+
|
4
|
+
# Related Windows API functions are grouped by topic and defined in separate namespaces (modules),
|
5
|
+
# that also contain related constants and convenience methods. For example, Win::Dde module
|
6
|
+
# contains only functions related to DDE protocol such as DdeInitialize() as well as constants
|
7
|
+
# such as DMLERR_NO_ERROR, APPCLASS_STANDARD, etc. So if you need only DDE-related functions,
|
8
|
+
# there is no need to load all the other modules, clogging your namespaces - just <b> require 'win/dde' </b>
|
9
|
+
# and be done with it. Win is just a top level namespace (container) that holds all the other modules.
|
10
|
+
#
|
11
|
+
module Win
|
12
|
+
|
13
|
+
module Errors # :nodoc:
|
14
|
+
class NotFoundError < NameError # :nodoc:
|
15
|
+
def initialize(name=nil, libs=nil)
|
16
|
+
super %Q[Function #{name ? "'#{name}' ": ""}not found#{libs ? " in #{libs}" : ""}"]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# WIN::Library is a module that extends FFI::Library and is used to connect to Windows API functions
|
22
|
+
# and wrap them into Ruby methods using 'function' declaration. If you do not see your favorite Windows
|
23
|
+
# API functions among those already defined, you can easily 'include Win::Library’ into your module
|
24
|
+
# and declare them using ‘function’ class method (macro) - it does a lot of heavy lifting for you and
|
25
|
+
# can be customized with options and code blocks to give you reusable API wrapper methods with the exact
|
26
|
+
# behavior you need.
|
27
|
+
#
|
28
|
+
module Library
|
29
|
+
|
30
|
+
# Win::Library::API is a wrapper for callable function API object that mimics Win32::API
|
31
|
+
class API
|
32
|
+
|
33
|
+
# The name of the DLL(s) that export this API function
|
34
|
+
attr_reader :dll_name
|
35
|
+
|
36
|
+
# Ruby namespace (module) where this API function is attached
|
37
|
+
attr_reader :namespace
|
38
|
+
|
39
|
+
# The name of the function passed to the constructor
|
40
|
+
attr_reader :function_name
|
41
|
+
|
42
|
+
# The name of the actual Windows API function. For example, if you passed 'GetUserName' to the
|
43
|
+
# constructor, then the effective function name would be either 'GetUserNameA' or 'GetUserNameW'.
|
44
|
+
attr_accessor :effective_function_name
|
45
|
+
|
46
|
+
# The prototype, returned as an array of FFI types
|
47
|
+
attr_reader :prototype
|
48
|
+
|
49
|
+
# The return type (:void for no return value)
|
50
|
+
attr_reader :return_type
|
51
|
+
|
52
|
+
def initialize( namespace, function_name, effective_function_name, prototype, return_type, dll_name )
|
53
|
+
@namespace = namespace
|
54
|
+
@function_name = function_name
|
55
|
+
@effective_function_name = effective_function_name
|
56
|
+
@prototype = prototype
|
57
|
+
@return_type = return_type
|
58
|
+
@dll_name = dll_name
|
59
|
+
end
|
60
|
+
|
61
|
+
# Calls underlying CamelCase Windows API function with supplied args
|
62
|
+
def call( *args )
|
63
|
+
@namespace.send(@function_name.to_sym, *args)
|
64
|
+
end
|
65
|
+
|
66
|
+
# alias_method :[], :call
|
67
|
+
end
|
68
|
+
|
69
|
+
# Contains class methods (macros) that can be used in any module mixing in Win::Library
|
70
|
+
module ClassMethods
|
71
|
+
|
72
|
+
# Mapping of Windows API types and one-letter shortcuts into FFI types.
|
73
|
+
# Like :ATOM => :ushort, :LPARAM => :long, :c => :char, :i => :int
|
74
|
+
TYPES = {
|
75
|
+
# FFI type shortcuts
|
76
|
+
C: :uchar, #– 8-bit unsigned character (byte)
|
77
|
+
c: :char, # 8-bit character (byte)
|
78
|
+
# :int8 – 8-bit signed integer
|
79
|
+
# :uint8 – 8-bit unsigned integer
|
80
|
+
S: :ushort, # – 16-bit unsigned integer (Win32/API: S used for string params)
|
81
|
+
s: :short, # – 16-bit signed integer
|
82
|
+
# :uint16 – 16-bit unsigned integer
|
83
|
+
# :int16 – 16-bit signed integer
|
84
|
+
I: :uint, # 32-bit unsigned integer
|
85
|
+
i: :int, # 32-bit signed integer
|
86
|
+
# :uint32 – 32-bit unsigned integer
|
87
|
+
# :int32 – 32-bit signed integer
|
88
|
+
L: :ulong, # unsigned long int – platform-specific size
|
89
|
+
l: :long, # long int – platform-specific size. For discussion of platforms, see:
|
90
|
+
# (http://groups.google.com/group/ruby-ffi/browse_thread/thread/4762fc77130339b1)
|
91
|
+
# :int64 – 64-bit signed integer
|
92
|
+
# :uint64 – 64-bit unsigned integer
|
93
|
+
# :long_long – 64-bit signed integer
|
94
|
+
# :ulong_long – 64-bit unsigned integer
|
95
|
+
F: :float, # 32-bit floating point
|
96
|
+
D: :double, # 64-bit floating point (double-precision)
|
97
|
+
P: :pointer, # pointer – platform-specific size
|
98
|
+
p: :string, # C-style (NULL-terminated) character string (Win32API: S)
|
99
|
+
B: :bool, # (?? 1 byte in C++)
|
100
|
+
V: :void, # For functions that return nothing (return type void).
|
101
|
+
v: :void, # For functions that return nothing (return type void).
|
102
|
+
# For function argument type only:
|
103
|
+
# :buffer_in – Similar to :pointer, but optimized for Buffers that the function can only read (not write).
|
104
|
+
# :buffer_out – Similar to :pointer, but optimized for Buffers that the function can only write (not read).
|
105
|
+
# :buffer_inout – Similar to :pointer, but may be optimized for Buffers.
|
106
|
+
# :varargs – Variable arguments
|
107
|
+
# :enum - Enumerable type (should be defined)
|
108
|
+
# :char_array - ??
|
109
|
+
|
110
|
+
# Windows-specific type defs (ms-help://MS.MSDNQTR.v90.en/winprog/winprog/windows_data_types.htm):
|
111
|
+
ATOM: :ushort, # Atom ~= Symbol: Atom table stores strings and corresponding identifiers. Application
|
112
|
+
# places a string in an atom table and receives a 16-bit integer, called an atom, that
|
113
|
+
# can be used to access the string. Placed string is called an atom name.
|
114
|
+
# See: http://msdn.microsoft.com/en-us/library/ms648708%28VS.85%29.aspx
|
115
|
+
BOOL: :bool,
|
116
|
+
BOOLEAN: :bool,
|
117
|
+
BYTE: :uchar, # Byte (8 bits). Declared as unsigned char
|
118
|
+
#CALLBACK: K, # Win32.API gem-specific ?? MSDN: #define CALLBACK __stdcall
|
119
|
+
CHAR: :char, # 8-bit Windows (ANSI) character. See http://msdn.microsoft.com/en-us/library/dd183415%28VS.85%29.aspx
|
120
|
+
COLORREF: :uint32, # Red, green, blue (RGB) color value (32 bits). See COLORREF for more info.
|
121
|
+
DWORD: :uint32, # 32-bit unsigned integer. The range is 0 through 4,294,967,295 decimal.
|
122
|
+
DWORDLONG: :uint64, # 64-bit unsigned integer. The range is 0 through 18,446,744,073,709,551,615 decimal.
|
123
|
+
DWORD_PTR: :ulong, # Unsigned long type for pointer precision. Use when casting a pointer to a long type
|
124
|
+
# to perform pointer arithmetic. (Also commonly used for general 32-bit parameters that have
|
125
|
+
# been extended to 64 bits in 64-bit Windows.) BaseTsd.h: #typedef ULONG_PTR DWORD_PTR;
|
126
|
+
DWORD32: :uint32,
|
127
|
+
DWORD64: :uint64,
|
128
|
+
HALF_PTR: :int, # Half the size of a pointer. Use within a structure that contains a pointer and two small fields.
|
129
|
+
# BaseTsd.h: #ifdef (_WIN64) typedef int HALF_PTR; #else typedef short HALF_PTR;
|
130
|
+
HACCEL: :ulong, # (L) Handle to an accelerator table. WinDef.h: #typedef HANDLE HACCEL;
|
131
|
+
# See http://msdn.microsoft.com/en-us/library/ms645526%28VS.85%29.aspx
|
132
|
+
HANDLE: :ulong, # (L) Handle to an object. WinNT.h: #typedef PVOID HANDLE;
|
133
|
+
# todo: Platform-dependent! Need to change to :uint64 for Win64
|
134
|
+
HBITMAP: :ulong, # (L) Handle to a bitmap: http://msdn.microsoft.com/en-us/library/dd183377%28VS.85%29.aspx
|
135
|
+
HBRUSH: :ulong, # (L) Handle to a brush. http://msdn.microsoft.com/en-us/library/dd183394%28VS.85%29.aspx
|
136
|
+
HCOLORSPACE: :ulong, # (L) Handle to a color space. http://msdn.microsoft.com/en-us/library/ms536546%28VS.85%29.aspx
|
137
|
+
HCURSOR: :ulong, # (L) Handle to a cursor. http://msdn.microsoft.com/en-us/library/ms646970%28VS.85%29.aspx
|
138
|
+
HCONV: :ulong, # (L) Handle to a dynamic data exchange (DDE) conversation.
|
139
|
+
HCONVLIST: :ulong, # (L) Handle to a DDE conversation list. HANDLE - L ?
|
140
|
+
HDDEDATA: :ulong, # (L) Handle to DDE data (structure?)
|
141
|
+
HDC: :ulong, # (L) Handle to a device context (DC). http://msdn.microsoft.com/en-us/library/dd183560%28VS.85%29.aspx
|
142
|
+
HDESK: :ulong, # (L) Handle to a desktop. http://msdn.microsoft.com/en-us/library/ms682573%28VS.85%29.aspx
|
143
|
+
HDROP: :ulong, # (L) Handle to an internal drop structure.
|
144
|
+
HDWP: :ulong, # (L) Handle to a deferred window position structure.
|
145
|
+
HENHMETAFILE: :ulong, #(L) Handle to an enhanced metafile. http://msdn.microsoft.com/en-us/library/dd145051%28VS.85%29.aspx
|
146
|
+
HFILE: :uint, # (I) Special file handle to a file opened by OpenFile, not CreateFile.
|
147
|
+
# WinDef.h: #typedef int HFILE;
|
148
|
+
HFONT: :ulong, # (L) Handle to a font. http://msdn.microsoft.com/en-us/library/dd162470%28VS.85%29.aspx
|
149
|
+
HGDIOBJ: :ulong, # (L) Handle to a GDI object.
|
150
|
+
HGLOBAL: :ulong, # (L) Handle to a global memory block.
|
151
|
+
HHOOK: :ulong, # (L) Handle to a hook. http://msdn.microsoft.com/en-us/library/ms632589%28VS.85%29.aspx
|
152
|
+
HICON: :ulong, # (L) Handle to an icon. http://msdn.microsoft.com/en-us/library/ms646973%28VS.85%29.aspx
|
153
|
+
HINSTANCE: :ulong, # (L) Handle to an instance. This is the base address of the module in memory.
|
154
|
+
# HMODULE and HINSTANCE are the same today, but were different in 16-bit Windows.
|
155
|
+
HKEY: :ulong, # (L) Handle to a registry key.
|
156
|
+
HKL: :ulong, # (L) Input locale identifier.
|
157
|
+
HLOCAL: :ulong, # (L) Handle to a local memory block.
|
158
|
+
HMENU: :ulong, # (L) Handle to a menu. http://msdn.microsoft.com/en-us/library/ms646977%28VS.85%29.aspx
|
159
|
+
HMETAFILE: :ulong, # (L) Handle to a metafile. http://msdn.microsoft.com/en-us/library/dd145051%28VS.85%29.aspx
|
160
|
+
HMODULE: :ulong, # (L) Handle to an instance. Same as HINSTANCE today, but was different in 16-bit Windows.
|
161
|
+
HMONITOR: :ulong, # (L) Рandle to a display monitor. WinDef.h: if(WINVER >= 0x0500) typedef HANDLE HMONITOR;
|
162
|
+
HPALETTE: :ulong, # (L) Handle to a palette.
|
163
|
+
HPEN: :ulong, # (L) Handle to a pen. http://msdn.microsoft.com/en-us/library/dd162786%28VS.85%29.aspx
|
164
|
+
HRESULT: :long, # Return code used by COM interfaces. For more info, Structure of the COM Error Codes.
|
165
|
+
# To test an HRESULT value, use the FAILED and SUCCEEDED macros.
|
166
|
+
HRGN: :ulong, # (L) Handle to a region. http://msdn.microsoft.com/en-us/library/dd162913%28VS.85%29.aspx
|
167
|
+
HRSRC: :ulong, # (L) Handle to a resource.
|
168
|
+
HSZ: :ulong, # (L) Handle to a DDE string.
|
169
|
+
HWINSTA: :ulong, # (L) Handle to a window station. http://msdn.microsoft.com/en-us/library/ms687096%28VS.85%29.aspx
|
170
|
+
HWND: :ulong, # (L) Handle to a window. http://msdn.microsoft.com/en-us/library/ms632595%28VS.85%29.aspx
|
171
|
+
INT: :int, # 32-bit signed integer. The range is -2147483648 through 2147483647 decimal.
|
172
|
+
INT_PTR: :int, # Signed integer type for pointer precision. Use when casting a pointer to an integer
|
173
|
+
# to perform pointer arithmetic. BaseTsd.h:
|
174
|
+
#if defined(_WIN64) typedef __int64 INT_PTR; #else typedef int INT_PTR;
|
175
|
+
INT32: :int32, # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal.
|
176
|
+
INT64: :int64, # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807
|
177
|
+
LANGID: :ushort, # Language identifier. For more information, see Locales. WinNT.h: #typedef WORD LANGID;
|
178
|
+
# See http://msdn.microsoft.com/en-us/library/dd318716%28VS.85%29.aspx
|
179
|
+
LCID: :uint32, # Locale identifier. For more information, see Locales.
|
180
|
+
LCTYPE: :uint32, # Locale information type. For a list, see Locale Information Constants.
|
181
|
+
LGRPID: :uint32, # Language group identifier. For a list, see EnumLanguageGroupLocales.
|
182
|
+
LONG: :long, # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal.
|
183
|
+
LONG32: :int32, # 32-bit signed integer. The range is -2,147,483,648 through +...647 decimal.
|
184
|
+
LONG64: :int64, # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807
|
185
|
+
LONGLONG: :int64, # 64-bit signed integer. The range is –9,223,372,036,854,775,808 through +...807
|
186
|
+
LONG_PTR: :long, # Signed long type for pointer precision. Use when casting a pointer to a long to
|
187
|
+
# perform pointer arithmetic. BaseTsd.h:
|
188
|
+
#if defined(_WIN64) typedef __int64 LONG_PTR; #else typedef long LONG_PTR;
|
189
|
+
LPARAM: :long, # Message parameter. WinDef.h as follows: #typedef LONG_PTR LPARAM;
|
190
|
+
LPBOOL: :pointer, # Pointer to a BOOL. WinDef.h as follows: #typedef BOOL far *LPBOOL;
|
191
|
+
LPBYTE: :pointer, # Pointer to a BYTE. WinDef.h as follows: #typedef BYTE far *LPBYTE;
|
192
|
+
LPCOLORREF: :pointer, # Pointer to a COLORREF value. WinDef.h as follows: #typedef DWORD *LPCOLORREF;
|
193
|
+
LPCSTR: :pointer, # Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters.
|
194
|
+
# See Character Sets Used By Fonts. http://msdn.microsoft.com/en-us/library/dd183415%28VS.85%29.aspx
|
195
|
+
LPCTSTR: :pointer, # An LPCWSTR if UNICODE is defined, an LPCSTR otherwise.
|
196
|
+
LPCVOID: :pointer, # Pointer to a constant of any type. WinDef.h as follows: typedef CONST void *LPCVOID;
|
197
|
+
LPCWSTR: :pointer, # Pointer to a constant null-terminated string of 16-bit Unicode characters.
|
198
|
+
LPDWORD: :pointer, # Pointer to a DWORD. WinDef.h as follows: typedef DWORD *LPDWORD;
|
199
|
+
LPHANDLE: :pointer, # Pointer to a HANDLE. WinDef.h as follows: typedef HANDLE *LPHANDLE;
|
200
|
+
LPINT: :pointer, # Pointer to an INT.
|
201
|
+
LPLONG: :pointer, # Pointer to an LONG.
|
202
|
+
LPSTR: :pointer, # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters.
|
203
|
+
LPTSTR: :pointer, # An LPWSTR if UNICODE is defined, an LPSTR otherwise.
|
204
|
+
LPVOID: :pointer, # Pointer to any type.
|
205
|
+
LPWORD: :pointer, # Pointer to a WORD.
|
206
|
+
LPWSTR: :pointer, # Pointer to a null-terminated string of 16-bit Unicode characters.
|
207
|
+
LRESULT: :long, # Signed result of message processing. WinDef.h: typedef LONG_PTR LRESULT;
|
208
|
+
PBOOL: :pointer, # Pointer to a BOOL.
|
209
|
+
PBOOLEAN: :pointer, # Pointer to a BOOL.
|
210
|
+
PBYTE: :pointer, # Pointer to a BYTE.
|
211
|
+
PCHAR: :pointer, # Pointer to a CHAR.
|
212
|
+
PCSTR: :pointer, # Pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters.
|
213
|
+
PCTSTR: :pointer, # A PCWSTR if UNICODE is defined, a PCSTR otherwise.
|
214
|
+
PCWSTR: :pointer, # Pointer to a constant null-terminated string of 16-bit Unicode characters.
|
215
|
+
PDWORD: :pointer, # Pointer to a DWORD.
|
216
|
+
PDWORDLONG: :pointer, # Pointer to a DWORDLONG.
|
217
|
+
PDWORD_PTR: :pointer, # Pointer to a DWORD_PTR.
|
218
|
+
PDWORD32: :pointer, # Pointer to a DWORD32.
|
219
|
+
PDWORD64: :pointer, # Pointer to a DWORD64.
|
220
|
+
PFLOAT: :pointer, # Pointer to a FLOAT.
|
221
|
+
PHALF_PTR: :pointer, # Pointer to a HALF_PTR.
|
222
|
+
PHANDLE: :pointer, # Pointer to a HANDLE.
|
223
|
+
PHKEY: :pointer, # Pointer to an HKEY.
|
224
|
+
PINT: :pointer, # Pointer to an INT.
|
225
|
+
PINT_PTR: :pointer, # Pointer to an INT_PTR.
|
226
|
+
PINT32: :pointer, # Pointer to an INT32.
|
227
|
+
PINT64: :pointer, # Pointer to an INT64.
|
228
|
+
PLCID: :pointer, # Pointer to an LCID.
|
229
|
+
PLONG: :pointer, # Pointer to a LONG.
|
230
|
+
PLONGLONG: :pointer, # Pointer to a LONGLONG.
|
231
|
+
PLONG_PTR: :pointer, # Pointer to a LONG_PTR.
|
232
|
+
PLONG32: :pointer, # Pointer to a LONG32.
|
233
|
+
PLONG64: :pointer, # Pointer to a LONG64.
|
234
|
+
POINTER_32: :pointer, # 32-bit pointer. On a 32-bit system, this is a native pointer. On a 64-bit system, this is a truncated 64-bit pointer.
|
235
|
+
POINTER_64: :pointer, # 64-bit pointer. On a 64-bit system, this is a native pointer. On a 32-bit system, this is a sign-extended 32-bit pointer.
|
236
|
+
POINTER_SIGNED: :pointer, # A signed pointer.
|
237
|
+
POINTER_UNSIGNED: :pointer, # An unsigned pointer.
|
238
|
+
PSHORT: :pointer, # Pointer to a SHORT.
|
239
|
+
PSIZE_T: :pointer, # Pointer to a SIZE_T.
|
240
|
+
PSSIZE_T: :pointer, # Pointer to a SSIZE_T.
|
241
|
+
PSTR: :pointer, # Pointer to a null-terminated string of 8-bit Windows (ANSI) characters. For more information, see Character Sets Used By Fonts.
|
242
|
+
PTBYTE: :pointer, # Pointer to a TBYTE.
|
243
|
+
PTCHAR: :pointer, # Pointer to a TCHAR.
|
244
|
+
PTSTR: :pointer, # A PWSTR if UNICODE is defined, a PSTR otherwise.
|
245
|
+
PUCHAR: :pointer, # Pointer to a UCHAR.
|
246
|
+
PUHALF_PTR: :pointer, # Pointer to a UHALF_PTR.
|
247
|
+
PUINT: :pointer, # Pointer to a UINT.
|
248
|
+
PUINT_PTR: :pointer, # Pointer to a UINT_PTR.
|
249
|
+
PUINT32: :pointer, # Pointer to a UINT32.
|
250
|
+
PUINT64: :pointer, # Pointer to a UINT64.
|
251
|
+
PULONG: :pointer, # Pointer to a ULONG.
|
252
|
+
PULONGLONG: :pointer, # Pointer to a ULONGLONG.
|
253
|
+
PULONG_PTR: :pointer, # Pointer to a ULONG_PTR.
|
254
|
+
PULONG32: :pointer, # Pointer to a ULONG32.
|
255
|
+
PULONG64: :pointer, # Pointer to a ULONG64.
|
256
|
+
PUSHORT: :pointer, # Pointer to a USHORT.
|
257
|
+
PVOID: :pointer, # Pointer to any type.
|
258
|
+
PWCHAR: :pointer, # Pointer to a WCHAR.
|
259
|
+
PWORD: :pointer, # Pointer to a WORD.
|
260
|
+
PWSTR: :pointer, # Pointer to a null- terminated string of 16-bit Unicode characters.
|
261
|
+
# For more information, see Character Sets Used By Fonts.
|
262
|
+
SC_HANDLE: :ulong, # (L) Handle to a service control manager database.
|
263
|
+
# See SCM Handles http://msdn.microsoft.com/en-us/library/ms685104%28VS.85%29.aspx
|
264
|
+
SC_LOCK: :pointer, # Lock to a service control manager database. For more information, see SCM Handles.
|
265
|
+
SERVICE_STATUS_HANDLE: :ulong, # (L) Handle to a service status value. See SCM Handles.
|
266
|
+
SHORT: :short, # A 16-bit integer. The range is –32768 through 32767 decimal.
|
267
|
+
SIZE_T: :ulong, # The maximum number of bytes to which a pointer can point. Use for a count that must span the full range of a pointer.
|
268
|
+
SSIZE_T: :long, # Signed SIZE_T.
|
269
|
+
TBYTE: :short, # A WCHAR if UNICODE is defined, a CHAR otherwise.TCHAR:
|
270
|
+
TCHAR: :short, # A WCHAR if UNICODE is defined, a CHAR otherwise.TCHAR:
|
271
|
+
UCHAR: :uchar, # Unsigned CHAR (8 bit)
|
272
|
+
UHALF_PTR: :uint, # Unsigned HALF_PTR. Use within a structure that contains a pointer and two small fields.
|
273
|
+
UINT: :uint, # Unsigned INT. The range is 0 through 4294967295 decimal.
|
274
|
+
UINT_PTR: :uint, # Unsigned INT_PTR.
|
275
|
+
UINT32: :uint32, # Unsigned INT32. The range is 0 through 4294967295 decimal.
|
276
|
+
UINT64: :uint64, # Unsigned INT64. The range is 0 through 18446744073709551615 decimal.
|
277
|
+
ULONG: :ulong, # Unsigned LONG. The range is 0 through 4294967295 decimal.
|
278
|
+
ULONGLONG: :ulong_long, # 64-bit unsigned integer. The range is 0 through 18446744073709551615 decimal.
|
279
|
+
ULONG_PTR: :ulong, # Unsigned LONG_PTR.
|
280
|
+
ULONG32: :uint32, # Unsigned INT32. The range is 0 through 4294967295 decimal.
|
281
|
+
ULONG64: :uint64, # Unsigned LONG64. The range is 0 through 18446744073709551615 decimal.
|
282
|
+
UNICODE_STRING: :pointer, # Pointer to some string structure??
|
283
|
+
USHORT: :ushort, # Unsigned SHORT. The range is 0 through 65535 decimal.
|
284
|
+
USN: :ulong_long, # Update sequence number (USN).
|
285
|
+
VOID: [], # Any type ? Only use it to indicate no arguments or no return value
|
286
|
+
WCHAR: :ushort, # 16-bit Unicode character. For more information, see Character Sets Used By Fonts.
|
287
|
+
# In WinNT.h: typedef wchar_t WCHAR;
|
288
|
+
#WINAPI: K, # Calling convention for system functions. WinDef.h: define WINAPI __stdcall
|
289
|
+
WORD: :ushort, # 16-bit unsigned integer. The range is 0 through 65535 decimal.
|
290
|
+
WPARAM: :uint # Message parameter. WinDef.h as follows: typedef UINT_PTR WPARAM;
|
291
|
+
}
|
292
|
+
|
293
|
+
##
|
294
|
+
# Defines new method wrappers for Windows API function call:
|
295
|
+
# - Defines method with original (CamelCase) API function name and original signature (matches MSDN description)
|
296
|
+
# - Defines method with snake_case name (converted from CamelCase function name) with enhanced API signature
|
297
|
+
# When defined snake_case method is called, it converts the arguments you provided into ones required by
|
298
|
+
# original API (adding defaults, mute and transitory args as necessary), executes API function call
|
299
|
+
# and (optionally) transforms the result before returning it. If a block is attached to
|
300
|
+
# method invocation, raw result is yielded to this block before final transformation take place
|
301
|
+
# - Defines aliases for enhanced method with more Rubyesque names for getters, setters and tests:
|
302
|
+
# GetWindowText -> window_test, SetWindowText -> window_text=, IsZoomed -> zoomed?
|
303
|
+
# ---
|
304
|
+
# You may modify default behavior of defined method by providing optional *def_block* to function definition.
|
305
|
+
# If you do so, snake_case method is defined based on your *def_block*. It receives callable API
|
306
|
+
# object for function being defined, arguments and (optional) runtime block with which the method
|
307
|
+
# will be called. Results coming from &def_block are then transformed and returned.
|
308
|
+
# So, your *def_block* should specify all the behavior of the method being defined. You can use *def_block* to:
|
309
|
+
# - Change original signature of API function, provide argument defaults, check argument types
|
310
|
+
# - Pack arguments into strings/structs for [in] or [in/out] parameters that expect a pointer
|
311
|
+
# - Allocate buffers/structs for pointers required by API functions [out] parameters
|
312
|
+
# - Unpack [out] and [in/out] parameters returned as pointers
|
313
|
+
# - Explicitly return results of API call that are returned in [out] and [in/out] parameters
|
314
|
+
# - Convert attached runtime blocks into callback functions and stuff them into [in] callback parameters
|
315
|
+
# - do other stuff that you think is appropriate to make Windows API function behavior more Ruby-like...
|
316
|
+
# ---
|
317
|
+
# Accepts following options:
|
318
|
+
# :dll:: Use this dll instead of default 'user32'
|
319
|
+
# :rename:: Use this name instead of standard (conventional) function name
|
320
|
+
# :alias(es):: Provides additional alias(es) for defined method
|
321
|
+
# :boolean:: Forces method to return true/false instead of nonzero/zero
|
322
|
+
# :zeronil:: Forces method to return nil if function result is zero
|
323
|
+
#
|
324
|
+
def function(name, params, returns, options={}, &def_block)
|
325
|
+
snake_name, effective_names, aliases = generate_names(name, options)
|
326
|
+
params, returns = generate_signature(params, returns)
|
327
|
+
libs = ffi_libraries.map(&:name)
|
328
|
+
boolean = options[:boolean]
|
329
|
+
zeronil = options[:zeronil]
|
330
|
+
|
331
|
+
effective_name = effective_names.inject(nil) do |func, effective_name|
|
332
|
+
func || begin
|
333
|
+
# tries to attach basic CamelCase method via FFI
|
334
|
+
attach_function(name, effective_name, params.dup, returns)
|
335
|
+
effective_name
|
336
|
+
rescue FFI::NotFoundError
|
337
|
+
nil
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
raise Win::Errors::NotFoundError.new(name, libs) unless effective_name
|
342
|
+
|
343
|
+
# Create API object that holds information about function names, params, etc
|
344
|
+
api = API.new(namespace, name, effective_name, params, returns, libs)
|
345
|
+
|
346
|
+
# Only define enhanced API if snake_name is different from original name (e.g. keybd_event)
|
347
|
+
unless snake_name.to_s == name.to_s
|
348
|
+
method_body = if def_block
|
349
|
+
if zeronil
|
350
|
+
->(*args, &block){ (res = def_block.(api, *args, &block)) != 0 ? res : nil }
|
351
|
+
elsif boolean
|
352
|
+
->(*args, &block){ def_block.(api, *args, &block) != 0 }
|
353
|
+
else
|
354
|
+
->(*args, &block){ def_block.(api, *args, &block) }
|
355
|
+
end
|
356
|
+
else
|
357
|
+
if zeronil
|
358
|
+
->(*args, &block){ (res = block ? block[api.call(*args)] : api.call(*args)) != 0 ? res : nil }
|
359
|
+
elsif boolean
|
360
|
+
->(*args, &block){ block ? block[api.call(*args)] : api.call(*args) != 0 }
|
361
|
+
else
|
362
|
+
->(*args, &block){ block ? block[api.call(*args)] : api.call(*args) }
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
define_method snake_name, &method_body # define snake_case instance method
|
367
|
+
|
368
|
+
eigenklass = class << self; self; end # Extracting eigenclass
|
369
|
+
eigenklass.class_eval do
|
370
|
+
define_method snake_name, &method_body # define snake_case class method
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
aliases.each {|ali| alias_method ali, snake_name } # define aliases
|
375
|
+
api #return api object from function declaration
|
376
|
+
end
|
377
|
+
|
378
|
+
# Try to define platform-specific function, rescue error, return message
|
379
|
+
#
|
380
|
+
def try_function(name, params, returns, options={}, &def_block)
|
381
|
+
begin
|
382
|
+
function name, params, returns, options={}, &def_block
|
383
|
+
rescue Win::Errors::NotFoundError
|
384
|
+
"This platform does not support function #{name}"
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# Generates possible effective names for function in Win32 dll (name+A/W),
|
389
|
+
# Rubyesque name and aliases for method(s) defined based on function name,
|
390
|
+
#
|
391
|
+
def generate_names(name, options={})
|
392
|
+
name = name.to_s
|
393
|
+
effective_names = [name]
|
394
|
+
effective_names += ["#{name}A", "#{name}W"] unless name =~ /[WA]$/
|
395
|
+
aliases = ([options[:alias]] + [options[:aliases]]).flatten.compact
|
396
|
+
snake_name = options[:rename] || name.snake_case
|
397
|
+
case snake_name
|
398
|
+
when /^is_/
|
399
|
+
aliases << snake_name.sub(/^is_/, '') + '?'
|
400
|
+
when /^set_/
|
401
|
+
aliases << snake_name.sub(/^set_/, '')+ '='
|
402
|
+
when /^get_/
|
403
|
+
aliases << snake_name.sub(/^get_/, '')
|
404
|
+
end
|
405
|
+
[snake_name, effective_names, aliases]
|
406
|
+
end
|
407
|
+
|
408
|
+
##
|
409
|
+
# Generates params and returns (signature) containing only FFI-compliant types
|
410
|
+
#
|
411
|
+
def generate_signature(params, returns)
|
412
|
+
params = params.split(//) if params.respond_to?(:split) # Convert params string into array
|
413
|
+
params.map! {|param| TYPES[param.to_sym] || param} # Convert chars into FFI type symbols
|
414
|
+
returns = TYPES[returns.to_sym] || returns # Convert chars into FFI type symbols
|
415
|
+
[params, returns]
|
416
|
+
end
|
417
|
+
|
418
|
+
##
|
419
|
+
# Wrapper for FFI::Library#callback() that converts Win32/shortcut argument types into FFI-compliant types.
|
420
|
+
# This method overrides FFI.callback which must be aliased to FFI.attach_callback
|
421
|
+
#
|
422
|
+
def callback(name, params, returns)
|
423
|
+
params, returns = generate_signature(params, returns)
|
424
|
+
attach_callback name.to_sym, params, returns
|
425
|
+
end
|
426
|
+
|
427
|
+
##
|
428
|
+
# :method: namespace
|
429
|
+
# This method is meta-generated when Win::Library module is included into other module/class.
|
430
|
+
# It returns reference to including (host) class/module for use by Win::Library::API and class methods.
|
431
|
+
|
432
|
+
##
|
433
|
+
# Ensures that args count is equal to params count plus diff
|
434
|
+
#
|
435
|
+
def enforce_count(args, params, diff = 0)
|
436
|
+
num_args = args.size
|
437
|
+
num_params = params.size + diff #params == 'V' ? 0 : params.size + diff
|
438
|
+
if num_args != num_params
|
439
|
+
raise ArgumentError, "wrong number of arguments (#{num_args} for #{num_params})"
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
end
|
444
|
+
|
445
|
+
##
|
446
|
+
# Hook executed when Win::Library is included into class or module. It extends host class/module
|
447
|
+
# with both FFI::Library methods and Win::Library macro methods like 'function'.
|
448
|
+
#
|
449
|
+
def self.included(klass)
|
450
|
+
klass.extend FFI::Library
|
451
|
+
|
452
|
+
eigenklass = class << klass; self; end # Extracting host class's eigenclass
|
453
|
+
eigenklass.class_eval do
|
454
|
+
define_method(:namespace) {klass} # Defining new class method for host pointing to itself
|
455
|
+
alias_method :attach_callback, :callback
|
456
|
+
|
457
|
+
include ClassMethods
|
458
|
+
end
|
459
|
+
|
460
|
+
klass.ffi_lib 'user32', 'kernel32' # Default libraries
|
461
|
+
klass.ffi_convention :stdcall
|
462
|
+
end
|
463
|
+
end
|
464
464
|
end
|