win32ole-ffi 0.1.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/BSDL +22 -0
- data/CHANGELOG.md +10 -0
- data/COPYING +56 -0
- data/README.md +49 -0
- data/lib/win32ole/ffi/array.rb +312 -0
- data/lib/win32ole/ffi/dispatch.rb +125 -0
- data/lib/win32ole/ffi/event.rb +800 -0
- data/lib/win32ole/ffi/fiddle_compat.rb +49 -0
- data/lib/win32ole/ffi/method.rb +237 -0
- data/lib/win32ole/ffi/param.rb +111 -0
- data/lib/win32ole/ffi/record.rb +289 -0
- data/lib/win32ole/ffi/type.rb +337 -0
- data/lib/win32ole/ffi/typeinfo.rb +488 -0
- data/lib/win32ole/ffi/typelib.rb +384 -0
- data/lib/win32ole/ffi/variable.rb +117 -0
- data/lib/win32ole/ffi/variant.rb +351 -0
- data/lib/win32ole/ffi/version.rb +5 -0
- data/lib/win32ole/ffi/win32.rb +907 -0
- data/lib/win32ole/ffi/win32ole.rb +827 -0
- data/lib/win32ole/ffi.rb +48 -0
- data/sig/win32ole/ffi.rbs +308 -0
- metadata +81 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fiddle'
|
|
4
|
+
require 'fiddle/import'
|
|
5
|
+
require 'win32ole/ffi/win32'
|
|
6
|
+
|
|
7
|
+
class WIN32OLE
|
|
8
|
+
module TypeInfo
|
|
9
|
+
extend Fiddle::Importer
|
|
10
|
+
|
|
11
|
+
# Each struct's [types, members], for layout_offsetof: Ruby 2.6/2.7's
|
|
12
|
+
# fiddle struct classes don't keep them.
|
|
13
|
+
LAYOUTS = {}
|
|
14
|
+
private_constant :LAYOUTS
|
|
15
|
+
|
|
16
|
+
def self.struct(signature)
|
|
17
|
+
super.tap { |klass| LAYOUTS[klass] = parse_struct_signature(signature, type_alias) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
GUID = struct([
|
|
21
|
+
'unsigned int Data1', 'unsigned short Data2', 'unsigned short Data3',
|
|
22
|
+
'unsigned char Data4[8]'
|
|
23
|
+
])
|
|
24
|
+
|
|
25
|
+
TYPEDESC = struct([
|
|
26
|
+
'void *union_ptr', # lptdesc / lpadesc / hreftype share this slot;
|
|
27
|
+
# caller's context determines which interpretation applies
|
|
28
|
+
'unsigned short vt'
|
|
29
|
+
])
|
|
30
|
+
|
|
31
|
+
ELEMDESC = struct([
|
|
32
|
+
'void *tdesc_union_ptr', 'unsigned short tdesc_vt', # TYPEDESC tdesc, inlined
|
|
33
|
+
'void *paramdescex_ptr', 'unsigned short wParamFlags' # PARAMDESC/IDLDESC union
|
|
34
|
+
])
|
|
35
|
+
|
|
36
|
+
FUNCDESC = struct([
|
|
37
|
+
'int memid', 'char _pad1[4]', # memid + padding to align lprgscode
|
|
38
|
+
'void *lprgscode', 'void *lprgelemdescParam',
|
|
39
|
+
'int funckind', 'int invkind', 'int callconv',
|
|
40
|
+
'short cParams', 'short cParamsOpt', 'short oVft', 'short cScodes',
|
|
41
|
+
'char _pad2[4]', # padding to align elemdescFunc
|
|
42
|
+
# elemdescFunc (ELEMDESC, inlined) — same 4-field shape as ELEMDESC above
|
|
43
|
+
'void *ret_tdesc_union_ptr', 'unsigned short ret_tdesc_vt', 'char _pad3[6]',
|
|
44
|
+
'void *ret_paramdescex_ptr', 'unsigned short ret_wParamFlags', 'char _pad4[6]',
|
|
45
|
+
'unsigned short wFuncFlags', 'char _pad5[6]'
|
|
46
|
+
])
|
|
47
|
+
|
|
48
|
+
VARDESC = struct([
|
|
49
|
+
'int memid', 'char _pad1[4]', # memid + padding to align lpstrSchema
|
|
50
|
+
'void *lpstrSchema', 'void *union_oInst_or_lpvarValue',
|
|
51
|
+
# elemdescVar (ELEMDESC, inlined) — full 32-byte block: TYPEDESC (16) + PARAMDESC/IDLDESC (16)
|
|
52
|
+
'void *tdesc_union_ptr', 'unsigned short tdesc_vt', 'char _pad2[6]', # TYPEDESC: 8+2+6=16
|
|
53
|
+
'void *paramdescex_ptr', 'unsigned short wParamFlags', 'char _pad3[6]', # PARAMDESC/IDLDESC: 8+2+6=16
|
|
54
|
+
'unsigned short wVarFlags', 'int varkind'
|
|
55
|
+
])
|
|
56
|
+
|
|
57
|
+
TYPEATTR = struct([
|
|
58
|
+
'unsigned int guid_Data1', 'unsigned short guid_Data2',
|
|
59
|
+
'unsigned short guid_Data3', 'unsigned char guid_Data4[8]',
|
|
60
|
+
'unsigned int lcid', 'unsigned int dwReserved',
|
|
61
|
+
'int memidConstructor', 'int memidDestructor',
|
|
62
|
+
'void *lpstrSchema', 'unsigned int cbSizeInstance',
|
|
63
|
+
'int typekind', 'unsigned short cFuncs', 'unsigned short cVars',
|
|
64
|
+
'unsigned short cImplTypes', 'unsigned short cbSizeVft',
|
|
65
|
+
'unsigned short cbAlignment', 'unsigned short wTypeFlags',
|
|
66
|
+
'unsigned short wMajorVerNum', 'unsigned short wMinorVerNum',
|
|
67
|
+
# tdescAlias (TYPEDESC, inlined) — complete 16-byte block with trailing padding
|
|
68
|
+
'void *tdescAlias_union_ptr', 'unsigned short tdescAlias_vt', 'char _pad1[6]',
|
|
69
|
+
# idldescType (IDLDESC: ULONG_PTR dwReserved + USHORT wIDLFlags)
|
|
70
|
+
'void *idldescType_dwReserved', 'unsigned short idldescType_wIDLFlags'
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
ITYPEINFO_VTBL = {
|
|
74
|
+
GetTypeAttr: 3, GetFuncDesc: 5, GetVarDesc: 6, GetNames: 7,
|
|
75
|
+
GetRefTypeOfImplType: 8, GetImplTypeFlags: 9, GetIDsOfNames: 10,
|
|
76
|
+
Invoke: 11, GetDocumentation: 12, GetDllEntry: 13, GetRefTypeInfo: 14,
|
|
77
|
+
AddressOfMember: 15, CreateInstance: 16, GetMops: 17,
|
|
78
|
+
GetContainingTypeLib: 18, ReleaseTypeAttr: 19, ReleaseFuncDesc: 20,
|
|
79
|
+
ReleaseVarDesc: 21
|
|
80
|
+
}.freeze
|
|
81
|
+
|
|
82
|
+
ITYPELIB_VTBL = {
|
|
83
|
+
GetTypeInfoCount: 3, GetTypeInfo: 4, GetTypeInfoType: 5,
|
|
84
|
+
GetTypeInfoOfGuid: 6, GetLibAttr: 7, GetTypeComp: 8,
|
|
85
|
+
GetDocumentation: 9, IsName: 10, FindName: 11, ReleaseTLibAttr: 12
|
|
86
|
+
}.freeze
|
|
87
|
+
|
|
88
|
+
# Fiddle::CStruct.offsetof is fiddle 1.1+; Ruby 2.6-3.0's fiddle (1.0.x)
|
|
89
|
+
# lacks it. JRuby's (1.1.4+) has it.
|
|
90
|
+
def self.offsetof(struct, name)
|
|
91
|
+
struct.respond_to?(:offsetof) ? struct.offsetof(name) : layout_offsetof(struct, name)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Lays the members out as Fiddle::CStructEntity#set_ctypes does.
|
|
95
|
+
def self.layout_offsetof(struct, name)
|
|
96
|
+
offset = 0
|
|
97
|
+
types, members = LAYOUTS.fetch(struct)
|
|
98
|
+
types.zip(members) do |(type, count), member|
|
|
99
|
+
offset = Fiddle::PackInfo.align(offset, Fiddle::PackInfo::ALIGN_MAP[type])
|
|
100
|
+
return offset if member == name
|
|
101
|
+
|
|
102
|
+
offset += Fiddle::PackInfo::SIZE_MAP[type] * (count || 1)
|
|
103
|
+
end
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
TYPEKIND_NAMES = {
|
|
108
|
+
0 => 'Enum', 1 => 'Record', 2 => 'Module', 3 => 'Interface',
|
|
109
|
+
4 => 'Dispatch', 5 => 'Class', 6 => 'Alias', 7 => 'Union', 8 => 'Max'
|
|
110
|
+
}.freeze
|
|
111
|
+
|
|
112
|
+
VARKIND_NAMES = {
|
|
113
|
+
0 => 'PERINSTANCE', 1 => 'STATIC', 2 => 'CONSTANT', 3 => 'DISPATCH'
|
|
114
|
+
}.freeze
|
|
115
|
+
|
|
116
|
+
# Transcribed from MRI's ole_typedesc2val (ext/win32ole/win32ole.c) —
|
|
117
|
+
# introspection type names, distinct from Win32.variant_ruby_type's much
|
|
118
|
+
# smaller table (which maps the few VARTYPEs the marshaling code
|
|
119
|
+
# actually needs to send/receive, not the full set a real type library
|
|
120
|
+
# can describe). VT_DISPATCH(9) and VT_UNKNOWN(13) are genuinely
|
|
121
|
+
# different values with genuinely different names — do not conflate them.
|
|
122
|
+
VARTYPE_NAMES = {
|
|
123
|
+
0 => 'EMPTY', 1 => 'NULL', 2 => 'I2', 3 => 'I4', 4 => 'R4', 5 => 'R8',
|
|
124
|
+
6 => 'CY', 7 => 'DATE', 8 => 'BSTR', 9 => 'DISPATCH', 10 => 'ERROR',
|
|
125
|
+
11 => 'BOOL', 12 => 'VARIANT', 13 => 'UNKNOWN', 14 => 'DECIMAL',
|
|
126
|
+
16 => 'I1', 17 => 'UI1', 18 => 'UI2', 19 => 'UI4', 20 => 'I8', 21 => 'UI8',
|
|
127
|
+
22 => 'INT', 23 => 'UINT', 24 => 'VOID', 25 => 'HRESULT', 26 => 'PTR',
|
|
128
|
+
27 => 'SAFEARRAY', 28 => 'CARRAY', 29 => 'USERDEFINED', 30 => 'LPSTR',
|
|
129
|
+
31 => 'LPWSTR', 36 => 'RECORD'
|
|
130
|
+
}.freeze
|
|
131
|
+
|
|
132
|
+
INVOKE_FUNC = 0x1
|
|
133
|
+
INVOKE_PROPERTYGET = 0x2
|
|
134
|
+
INVOKE_PROPERTYPUT = 0x4
|
|
135
|
+
INVOKE_PROPERTYPUTREF = 0x8
|
|
136
|
+
|
|
137
|
+
module_function
|
|
138
|
+
|
|
139
|
+
def vartype_name(vt)
|
|
140
|
+
VARTYPE_NAMES.fetch(vt) { "Unknown Type #{vt}" }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
VT_PTR = 26
|
|
144
|
+
VT_SAFEARRAY = 27
|
|
145
|
+
VT_USERDEFINED = 29
|
|
146
|
+
MEMBERID_NIL = -1
|
|
147
|
+
|
|
148
|
+
# Mirrors ext/win32ole/win32ole.c's ole_typedesc2val: the type-detail
|
|
149
|
+
# chain for the TYPEDESC at tdesc_addr, e.g. ["PTR", "USERDEFINED",
|
|
150
|
+
# "Folder"]. Its last element is what return_type/ole_type report.
|
|
151
|
+
# The union is read as raw bytes, not through a struct's `void *`
|
|
152
|
+
# accessor: for VT_USERDEFINED only its low 4 bytes (the HREFTYPE) are
|
|
153
|
+
# meaningful and the rest can be garbage that overflows a pointer.
|
|
154
|
+
def typedesc_details(itypeinfo_ptr, tdesc_addr, details = [])
|
|
155
|
+
tdesc = Fiddle::Pointer.new(tdesc_addr)
|
|
156
|
+
union = tdesc[0, W::PTR_SIZE].unpack1(W::PACK_PTR)
|
|
157
|
+
vt = tdesc[W::PTR_SIZE, 2].unpack1('S')
|
|
158
|
+
details << vartype_name(vt)
|
|
159
|
+
case vt
|
|
160
|
+
when VT_PTR, VT_SAFEARRAY
|
|
161
|
+
typedesc_details(itypeinfo_ptr, union, details)
|
|
162
|
+
when VT_USERDEFINED
|
|
163
|
+
name = ref_type_name(itypeinfo_ptr, union & 0xFFFFFFFF)
|
|
164
|
+
details << name if name
|
|
165
|
+
details
|
|
166
|
+
else
|
|
167
|
+
details
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def ref_type_name(itypeinfo_ptr, hreftype)
|
|
172
|
+
ref_out = ("\x00" * W::PTR_SIZE).b
|
|
173
|
+
return nil if W.failed?(ref_type_info_fn(itypeinfo_ptr).call(itypeinfo_ptr, hreftype, ref_out))
|
|
174
|
+
|
|
175
|
+
ref_ptr = ref_out.unpack1(W::PACK_PTR)
|
|
176
|
+
begin
|
|
177
|
+
type_name(ref_ptr)
|
|
178
|
+
ensure
|
|
179
|
+
release(ref_ptr)
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# The type's own name (GetDocumentation(MEMBERID_NIL)), or nil.
|
|
184
|
+
def type_name(itypeinfo_ptr)
|
|
185
|
+
member_name(itypeinfo_ptr, MEMBERID_NIL)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def member_name(itypeinfo_ptr, memid)
|
|
189
|
+
name_out = ("\x00" * W::PTR_SIZE).b
|
|
190
|
+
hr = documentation_fn_for_typeinfo(itypeinfo_ptr).call(itypeinfo_ptr, memid, name_out, nil, nil, nil)
|
|
191
|
+
return nil if W.failed?(hr)
|
|
192
|
+
|
|
193
|
+
bstr = name_out.unpack1(W::PACK_PTR)
|
|
194
|
+
name = W.bstr_to_s(bstr)
|
|
195
|
+
W.sys_free_string.call(bstr) unless bstr.zero?
|
|
196
|
+
name
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def release(iunknown_ptr)
|
|
200
|
+
W.vtable_function(iunknown_ptr, 2, [W::VOIDP], W::DWORD).call(iunknown_ptr)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
TKIND_COCLASS = 5
|
|
204
|
+
IMPLTYPEFLAG_FDEFAULT = 0x1
|
|
205
|
+
IMPLTYPEFLAG_FSOURCE = 0x2
|
|
206
|
+
|
|
207
|
+
# Reads one TYPEATTR field (:typekind, :cFuncs, :cVars, :cImplTypes...),
|
|
208
|
+
# or nil if GetTypeAttr fails.
|
|
209
|
+
def type_attr_value(itypeinfo_ptr, field)
|
|
210
|
+
attr_out = ("\x00" * W::PTR_SIZE).b
|
|
211
|
+
return nil if W.failed?(type_attr_fn(itypeinfo_ptr).call(itypeinfo_ptr, attr_out))
|
|
212
|
+
|
|
213
|
+
attr_ptr = attr_out.unpack1(W::PACK_PTR)
|
|
214
|
+
value = TYPEATTR.new(attr_ptr).send(field)
|
|
215
|
+
release_type_attr_fn(itypeinfo_ptr).call(itypeinfo_ptr, attr_ptr)
|
|
216
|
+
value
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Yields [impl_type_flags, ref_itypeinfo_ptr] for each implemented type
|
|
220
|
+
# of itypeinfo_ptr, skipping ones whose flags or ITypeInfo can't be
|
|
221
|
+
# read, the same loop ole_type_impl_ole_types / ole_methods_from_typeinfo
|
|
222
|
+
# use. The block owns ref_itypeinfo_ptr: it must release it or hand
|
|
223
|
+
# it to something that will.
|
|
224
|
+
def each_impl_type(itypeinfo_ptr)
|
|
225
|
+
(type_attr_value(itypeinfo_ptr, :cImplTypes) || 0).times do |i|
|
|
226
|
+
flags_out = ("\x00" * 4).b
|
|
227
|
+
next if W.failed?(impl_type_flags_fn(itypeinfo_ptr).call(itypeinfo_ptr, i, flags_out))
|
|
228
|
+
|
|
229
|
+
href_out = ("\x00" * 4).b
|
|
230
|
+
next if W.failed?(ref_type_of_impl_type_fn(itypeinfo_ptr).call(itypeinfo_ptr, i, href_out))
|
|
231
|
+
|
|
232
|
+
ref_out = ("\x00" * W::PTR_SIZE).b
|
|
233
|
+
next if W.failed?(ref_type_info_fn(itypeinfo_ptr).call(itypeinfo_ptr, href_out.unpack1('L'), ref_out))
|
|
234
|
+
|
|
235
|
+
yield flags_out.unpack1('l'), ref_out.unpack1(W::PACK_PTR)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# ext/win32ole/win32ole_method.c's ole_method_event: true if owner_ptr
|
|
240
|
+
# is a coclass and one of its source interfaces has, at method_index, a
|
|
241
|
+
# function named method_name.
|
|
242
|
+
def method_event?(owner_ptr, method_index, method_name)
|
|
243
|
+
return false unless type_attr_value(owner_ptr, :typekind) == TKIND_COCLASS
|
|
244
|
+
|
|
245
|
+
each_impl_type(owner_ptr) do |flags, ref_ptr|
|
|
246
|
+
begin
|
|
247
|
+
next if (flags & IMPLTYPEFLAG_FSOURCE).zero?
|
|
248
|
+
|
|
249
|
+
funcdesc_out = ("\x00" * W::PTR_SIZE).b
|
|
250
|
+
next if W.failed?(func_desc_fn(ref_ptr).call(ref_ptr, method_index, funcdesc_out))
|
|
251
|
+
|
|
252
|
+
funcdesc_ptr = funcdesc_out.unpack1(W::PACK_PTR)
|
|
253
|
+
memid = FUNCDESC.new(funcdesc_ptr).memid
|
|
254
|
+
release_func_desc_fn(ref_ptr).call(ref_ptr, funcdesc_ptr)
|
|
255
|
+
return true if member_name(ref_ptr, memid) == method_name
|
|
256
|
+
ensure
|
|
257
|
+
release(ref_ptr)
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
false
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def invoke_kind_name(invkind)
|
|
264
|
+
if (invkind & INVOKE_PROPERTYGET != 0) && (invkind & INVOKE_PROPERTYPUT != 0)
|
|
265
|
+
'PROPERTY'
|
|
266
|
+
elsif invkind & INVOKE_PROPERTYGET != 0
|
|
267
|
+
'PROPERTYGET'
|
|
268
|
+
elsif invkind & INVOKE_PROPERTYPUT != 0
|
|
269
|
+
'PROPERTYPUT'
|
|
270
|
+
elsif invkind & INVOKE_PROPERTYPUTREF != 0
|
|
271
|
+
'PROPERTYPUTREF'
|
|
272
|
+
elsif invkind & INVOKE_FUNC != 0
|
|
273
|
+
'FUNC'
|
|
274
|
+
else
|
|
275
|
+
'UNKNOWN'
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
W = Win32
|
|
280
|
+
private_constant :W
|
|
281
|
+
|
|
282
|
+
# Every *_fn method below memoizes a resolved Fiddle::Function keyed by
|
|
283
|
+
# the object's VTABLE address (W.vtable_address), not the object's own
|
|
284
|
+
# address: after a COM object is released, its heap address can be
|
|
285
|
+
# reused by an unrelated object with a different vtable, so keying by
|
|
286
|
+
# object address risks resolving a function pointer from the wrong
|
|
287
|
+
# vtable. Keying by vtable address is both correct (it's the actual
|
|
288
|
+
# implementation identity) and bounded (one entry per distinct
|
|
289
|
+
# implementation, not per live object).
|
|
290
|
+
|
|
291
|
+
def get_type_info_fn(idispatch_ptr)
|
|
292
|
+
@get_type_info_fns ||= {}
|
|
293
|
+
@get_type_info_fns[W.vtable_address(idispatch_ptr)] ||= W.vtable_function(
|
|
294
|
+
idispatch_ptr, 4, [W::VOIDP, W::DWORD, W::DWORD, W::VOIDP], W::LONG
|
|
295
|
+
)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def type_attr_fn(itypeinfo_ptr)
|
|
299
|
+
@type_attr_fns ||= {}
|
|
300
|
+
@type_attr_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
301
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetTypeAttr], [W::VOIDP, W::VOIDP], W::LONG
|
|
302
|
+
)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def func_desc_fn(itypeinfo_ptr)
|
|
306
|
+
@func_desc_fns ||= {}
|
|
307
|
+
@func_desc_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
308
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetFuncDesc], [W::VOIDP, W::DWORD, W::VOIDP], W::LONG
|
|
309
|
+
)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def var_desc_fn(itypeinfo_ptr)
|
|
313
|
+
@var_desc_fns ||= {}
|
|
314
|
+
@var_desc_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
315
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetVarDesc], [W::VOIDP, W::DWORD, W::VOIDP], W::LONG
|
|
316
|
+
)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def documentation_fn_for_typeinfo(itypeinfo_ptr)
|
|
320
|
+
@documentation_fns ||= {}
|
|
321
|
+
@documentation_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
322
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetDocumentation],
|
|
323
|
+
[W::VOIDP, W::LONG, W::VOIDP, W::VOIDP, W::VOIDP, W::VOIDP], W::LONG
|
|
324
|
+
)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def containing_typelib_fn(itypeinfo_ptr)
|
|
328
|
+
@containing_typelib_fns ||= {}
|
|
329
|
+
@containing_typelib_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
330
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetContainingTypeLib], [W::VOIDP, W::VOIDP, W::VOIDP], W::LONG
|
|
331
|
+
)
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def release_type_attr_fn(itypeinfo_ptr)
|
|
335
|
+
@release_type_attr_fns ||= {}
|
|
336
|
+
@release_type_attr_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
337
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:ReleaseTypeAttr], [W::VOIDP, W::VOIDP], W::VOID
|
|
338
|
+
)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def release_func_desc_fn(itypeinfo_ptr)
|
|
342
|
+
@release_func_desc_fns ||= {}
|
|
343
|
+
@release_func_desc_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
344
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:ReleaseFuncDesc], [W::VOIDP, W::VOIDP], W::VOID
|
|
345
|
+
)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def release_var_desc_fn(itypeinfo_ptr)
|
|
349
|
+
@release_var_desc_fns ||= {}
|
|
350
|
+
@release_var_desc_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
351
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:ReleaseVarDesc], [W::VOIDP, W::VOIDP], W::VOID
|
|
352
|
+
)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def ref_type_info_fn(itypeinfo_ptr)
|
|
356
|
+
@ref_type_info_fns ||= {}
|
|
357
|
+
@ref_type_info_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
358
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetRefTypeInfo], [W::VOIDP, W::DWORD, W::VOIDP], W::LONG
|
|
359
|
+
)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def type_info_count_fn(itypelib_ptr)
|
|
363
|
+
@type_info_count_fns ||= {}
|
|
364
|
+
@type_info_count_fns[W.vtable_address(itypelib_ptr)] ||= W.vtable_function(
|
|
365
|
+
itypelib_ptr, ITYPELIB_VTBL[:GetTypeInfoCount], [W::VOIDP], W::DWORD
|
|
366
|
+
)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def type_info_fn(itypelib_ptr)
|
|
370
|
+
@type_info_fns ||= {}
|
|
371
|
+
@type_info_fns[W.vtable_address(itypelib_ptr)] ||= W.vtable_function(
|
|
372
|
+
itypelib_ptr, ITYPELIB_VTBL[:GetTypeInfo], [W::VOIDP, W::DWORD, W::VOIDP], W::LONG
|
|
373
|
+
)
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def lib_attr_fn(itypelib_ptr)
|
|
377
|
+
@lib_attr_fns ||= {}
|
|
378
|
+
@lib_attr_fns[W.vtable_address(itypelib_ptr)] ||= W.vtable_function(
|
|
379
|
+
itypelib_ptr, ITYPELIB_VTBL[:GetLibAttr], [W::VOIDP, W::VOIDP], W::LONG
|
|
380
|
+
)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def documentation_fn_for_typelib(itypelib_ptr)
|
|
384
|
+
@typelib_documentation_fns ||= {}
|
|
385
|
+
@typelib_documentation_fns[W.vtable_address(itypelib_ptr)] ||= W.vtable_function(
|
|
386
|
+
itypelib_ptr, ITYPELIB_VTBL[:GetDocumentation],
|
|
387
|
+
[W::VOIDP, W::LONG, W::VOIDP, W::VOIDP, W::VOIDP, W::VOIDP], W::LONG
|
|
388
|
+
)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def release_tlib_attr_fn(itypelib_ptr)
|
|
392
|
+
@release_tlib_attr_fns ||= {}
|
|
393
|
+
@release_tlib_attr_fns[W.vtable_address(itypelib_ptr)] ||= W.vtable_function(
|
|
394
|
+
itypelib_ptr, ITYPELIB_VTBL[:ReleaseTLibAttr], [W::VOIDP, W::VOIDP], W::VOID
|
|
395
|
+
)
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
def impl_type_flags_fn(itypeinfo_ptr)
|
|
399
|
+
@impl_type_flags_fns ||= {}
|
|
400
|
+
@impl_type_flags_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
401
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetImplTypeFlags], [W::VOIDP, W::DWORD, W::VOIDP], W::LONG
|
|
402
|
+
)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def ref_type_of_impl_type_fn(itypeinfo_ptr)
|
|
406
|
+
@ref_type_of_impl_type_fns ||= {}
|
|
407
|
+
@ref_type_of_impl_type_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
408
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetRefTypeOfImplType], [W::VOIDP, W::DWORD, W::VOIDP], W::LONG
|
|
409
|
+
)
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def get_names_fn(itypeinfo_ptr)
|
|
413
|
+
@get_names_fns ||= {}
|
|
414
|
+
@get_names_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
415
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetNames], [W::VOIDP, W::LONG, W::VOIDP, W::DWORD, W::VOIDP], W::LONG
|
|
416
|
+
)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def get_ids_of_names_fn(itypeinfo_ptr)
|
|
420
|
+
@get_ids_of_names_fns ||= {}
|
|
421
|
+
@get_ids_of_names_fns[W.vtable_address(itypeinfo_ptr)] ||= W.vtable_function(
|
|
422
|
+
itypeinfo_ptr, ITYPEINFO_VTBL[:GetIDsOfNames], [W::VOIDP, W::VOIDP, W::DWORD, W::VOIDP], W::LONG
|
|
423
|
+
)
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
def type_info_of_guid_fn(itypelib_ptr)
|
|
427
|
+
@type_info_of_guid_fns ||= {}
|
|
428
|
+
@type_info_of_guid_fns[W.vtable_address(itypelib_ptr)] ||= W.vtable_function(
|
|
429
|
+
itypelib_ptr, ITYPELIB_VTBL[:GetTypeInfoOfGuid], [W::VOIDP, W::VOIDP, W::VOIDP], W::LONG
|
|
430
|
+
)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
HKEY_CLASSES_ROOT = 0x80000000
|
|
434
|
+
KEY_READ = 0x20019
|
|
435
|
+
REG_SZ = 1
|
|
436
|
+
REG_EXPAND_SZ = 2
|
|
437
|
+
|
|
438
|
+
def advapi32
|
|
439
|
+
@advapi32 ||= Fiddle.dlopen('advapi32')
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def reg_open_key_ex
|
|
443
|
+
@reg_open_key_ex ||= Fiddle::Function.new(
|
|
444
|
+
advapi32['RegOpenKeyExW'], [W::VOIDP, W::VOIDP, W::DWORD, W::DWORD, W::VOIDP], W::LONG, W::STDCALL
|
|
445
|
+
)
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
def reg_query_value_ex
|
|
449
|
+
@reg_query_value_ex ||= Fiddle::Function.new(
|
|
450
|
+
advapi32['RegQueryValueExW'],
|
|
451
|
+
[W::VOIDP, W::VOIDP, W::VOIDP, W::VOIDP, W::VOIDP, W::VOIDP], W::LONG, W::STDCALL
|
|
452
|
+
)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def reg_close_key
|
|
456
|
+
@reg_close_key ||= Fiddle::Function.new(advapi32['RegCloseKey'], [W::VOIDP], W::LONG, W::STDCALL)
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
REG_ENUM_MAX_NAME = 256 # WCHARs; a registry key name is capped at 255 chars (MAX_KEY_LENGTH)
|
|
460
|
+
|
|
461
|
+
def reg_enum_key_ex
|
|
462
|
+
@reg_enum_key_ex ||= Fiddle::Function.new(
|
|
463
|
+
advapi32['RegEnumKeyExW'],
|
|
464
|
+
[W::VOIDP, W::DWORD, W::VOIDP, W::VOIDP, W::VOIDP, W::VOIDP, W::VOIDP, W::VOIDP], W::LONG, W::STDCALL
|
|
465
|
+
)
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
# Mirrors ext/win32ole/win32ole.c's reg_enum_key: returns the name of
|
|
469
|
+
# the index-th direct subkey of hkey, or nil once the index runs past
|
|
470
|
+
# the last one (RegEnumKeyExW returns ERROR_NO_MORE_ITEMS).
|
|
471
|
+
def reg_enum_key(hkey, index)
|
|
472
|
+
name_out = ("\x00" * (REG_ENUM_MAX_NAME * 2)).b
|
|
473
|
+
size_out = [REG_ENUM_MAX_NAME].pack('L')
|
|
474
|
+
err = reg_enum_key_ex.call(hkey, index, name_out, size_out, nil, nil, nil, nil)
|
|
475
|
+
return nil unless err.zero?
|
|
476
|
+
|
|
477
|
+
name_out[0, size_out.unpack1('L') * 2].force_encoding('UTF-16LE').encode('UTF-8')
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
REGKIND_NONE = 2
|
|
481
|
+
|
|
482
|
+
def load_type_lib_ex
|
|
483
|
+
@load_type_lib_ex ||= Fiddle::Function.new(
|
|
484
|
+
W.oleaut32['LoadTypeLibEx'], [W::VOIDP, W::LONG, W::VOIDP], W::LONG, W::STDCALL
|
|
485
|
+
)
|
|
486
|
+
end
|
|
487
|
+
end
|
|
488
|
+
end
|