windows_com 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: '0194380637c6543160a0be00e072f4806e0cdd65'
4
+ data.tar.gz: 935c162da6720ad0ba281f0bc7d8d6573f82fcca
5
+ SHA512:
6
+ metadata.gz: ed3ab8238d527d4fd4b6770a70b39d0cf6690c1036ba4702d162ef230954bf293051bab645200dd0e6e69c5f091a45aec62e903a0c8d699c32f96294e952e1bb
7
+ data.tar.gz: 0e6994e3718acc2292accf0dca730484428dd2c22816580d07169c1d7926311108b209b192196b773af6de539647f629f6fdefc74789d790829e6b7e658ff6a2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2017 Radoslav Peev <rpeev@ymail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # windows_com
2
+
3
+ Ruby FFI (x86) bindings to essential COM related Windows APIs
4
+
5
+ ## Install
6
+
7
+ gem install windows_com
8
+
9
+ ## Use
10
+
11
+ See examples folder
data/RELNOTES.md ADDED
@@ -0,0 +1,9 @@
1
+ # Release Notes
2
+
3
+ ## 1.0.0
4
+
5
+ Rename library to windows_com and ensure it works with recent ruby
6
+
7
+ ## 0.2.2
8
+
9
+ Recover source from gem
@@ -0,0 +1,21 @@
1
+ require 'windows_com'
2
+
3
+ include WindowsCOM
4
+
5
+ IDesktopGadget = COMInterface[IUnknown,
6
+ 'c1646bc4-f298-4f91-a204-eb2dd1709d1a',
7
+
8
+ RunGadget: [[:buffer_in], :long]
9
+ ]
10
+
11
+ DesktopGadget = COMFactory[IDesktopGadget, '924ccc1b-6562-4c85-8657-d177925222b6']
12
+
13
+ dg = DesktopGadget.new
14
+
15
+ begin
16
+ dg.RunGadget(
17
+ "#{ENV['ProgramFiles']}\\Windows Sidebar\\Gadgets\\Clock.Gadget\0".encode('utf-16le')
18
+ )
19
+ ensure
20
+ dg.Release
21
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'windows_com/common'
2
+ require_relative 'windows_com/libc'
3
+ require_relative 'windows_com/ole'
4
+ require_relative 'windows_com/oleaut'
@@ -0,0 +1,175 @@
1
+ require 'ffi'
2
+
3
+ WINDOWS_COM_VERSION = '1.0.0'
4
+
5
+ WINDOWS_COM_OLE_INIT = true unless defined?(WINDOWS_COM_OLE_INIT)
6
+
7
+ module WindowsCOM
8
+ extend FFI::Library
9
+
10
+ def DetonateHresult(name, *args)
11
+ hresult = send(name, *args)
12
+ failed = FAILED(hresult)
13
+
14
+ raise "#{name} failed (hresult: #{format('%#08x', hresult)})" if failed
15
+
16
+ hresult
17
+ ensure
18
+ yield hresult if failed && block_given?
19
+ end
20
+
21
+ module_function \
22
+ :DetonateHresult
23
+
24
+ S_OK = 0
25
+ S_FALSE = 1
26
+
27
+ E_UNEXPECTED = 0x8000FFFF - 0x1_0000_0000
28
+ E_NOTIMPL = 0x80004001 - 0x1_0000_0000
29
+ E_OUTOFMEMORY = 0x8007000E - 0x1_0000_0000
30
+ E_INVALIDARG = 0x80070057 - 0x1_0000_0000
31
+ E_NOINTERFACE = 0x80004002 - 0x1_0000_0000
32
+ E_POINTER = 0x80004003 - 0x1_0000_0000
33
+ E_HANDLE = 0x80070006 - 0x1_0000_0000
34
+ E_ABORT = 0x80004004 - 0x1_0000_0000
35
+ E_FAIL = 0x80004005 - 0x1_0000_0000
36
+ E_ACCESSDENIED = 0x80070005 - 0x1_0000_0000
37
+ E_PENDING = 0x8000000A - 0x1_0000_0000
38
+
39
+ FACILITY_WIN32 = 7
40
+
41
+ ERROR_CANCELLED = 1223
42
+
43
+ def SUCCEEDED(hr)
44
+ hr >= 0
45
+ end
46
+
47
+ def FAILED(hr)
48
+ hr < 0
49
+ end
50
+
51
+ def HRESULT_FROM_WIN32(x)
52
+ (x <= 0) ?
53
+ x :
54
+ (x & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000
55
+ end
56
+
57
+ module_function \
58
+ :SUCCEEDED,
59
+ :FAILED,
60
+ :HRESULT_FROM_WIN32
61
+
62
+ class GUID < FFI::Struct
63
+ layout \
64
+ :Data1, :ulong,
65
+ :Data2, :ushort,
66
+ :Data3, :ushort,
67
+ :Data4, [:uchar, 8]
68
+ end
69
+
70
+ def GUIDFromString(str)
71
+ raise 'Bad GUID format' unless str =~ /^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/i
72
+
73
+ guid = GUID.new
74
+
75
+ guid[:Data1] = str[0, 8].to_i(16)
76
+ guid[:Data2] = str[9, 4].to_i(16)
77
+ guid[:Data3] = str[14, 4].to_i(16)
78
+ guid[:Data4][0] = str[19, 2].to_i(16)
79
+ guid[:Data4][1] = str[21, 2].to_i(16)
80
+ str[24, 12].split('').each_slice(2).with_index { |a, i|
81
+ guid[:Data4][i + 2] = a.join('').to_i(16)
82
+ }
83
+
84
+ guid
85
+ end
86
+
87
+ def GUIDEqual(guid1, guid2)
88
+ windows_com_memcmp(guid1, guid2, GUID.size) == 0
89
+ end
90
+
91
+ module_function \
92
+ :GUIDFromString,
93
+ :GUIDEqual
94
+
95
+ class COMVptr_ < FFI::Struct
96
+ layout \
97
+ :lpVtbl, :pointer
98
+ end
99
+
100
+ module COMVtbl_
101
+ def self.[](parent_vtbl, spec)
102
+ spec.each { |name, sig|
103
+ sig[0].unshift(:pointer) # prepend *this* pointer
104
+ }
105
+
106
+ Class.new(FFI::Struct) {
107
+ const_set :ParentVtbl, parent_vtbl
108
+
109
+ const_set :Spec, {}
110
+ self::Spec.merge!(self::ParentVtbl::Spec) if self::ParentVtbl
111
+ self::Spec.merge!(spec)
112
+
113
+ layout_args = self::Spec.map { |name, sig|
114
+ params, ret = sig
115
+ [name, callback(params, ret)]
116
+ }
117
+ layout_args.flatten!
118
+ layout(*layout_args)
119
+ }
120
+ end
121
+ end
122
+
123
+ module COMInterface_
124
+ def self.[](vtbl, siid)
125
+ Class.new {
126
+ const_set :Vtbl, vtbl
127
+ const_set :IID, WindowsCOM::GUIDFromString(siid)
128
+
129
+ def initialize(pointer)
130
+ @vptr = COMVptr_.new(pointer)
131
+ @vtbl = self.class::Vtbl.new(@vptr[:lpVtbl])
132
+ end
133
+
134
+ attr_reader :vptr, :vtbl
135
+
136
+ self::Vtbl.members.each { |name, sig|
137
+ define_method(name) { |*args|
138
+ hresult = @vtbl[name].call(@vptr, *args)
139
+
140
+ raise "#{self}.#{name} failed (hresult: #{format('%#08x', hresult)})" if
141
+ WindowsCOM::FAILED(hresult)
142
+
143
+ hresult
144
+ }
145
+ }
146
+ }
147
+ end
148
+ end
149
+
150
+ module COMInterface
151
+ def self.[](parent_iface, siid, spec)
152
+ vtbl = COMVtbl_[(parent_iface) ? parent_iface::Vtbl : nil, spec]
153
+
154
+ COMInterface_[vtbl, siid]
155
+ end
156
+ end
157
+
158
+ module COMFactory
159
+ def self.[](iface, sclsid)
160
+ Class.new(iface) {
161
+ const_set :CLSID, WindowsCOM::GUIDFromString(sclsid)
162
+
163
+ def initialize(clsctx = CLSCTX_INPROC)
164
+ FFI::MemoryPointer.new(:pointer) { |ppv|
165
+ DetonateHresult(:CoCreateInstance,
166
+ self.class::CLSID, nil, clsctx, self.class::IID, ppv
167
+ )
168
+
169
+ super(ppv.read_pointer)
170
+ }
171
+ end
172
+ }
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,173 @@
1
+ __END__
2
+ module COMHelpers
3
+ def QueryInstance(klass)
4
+ instance = nil
5
+
6
+ FFI::MemoryPointer.new(:pointer) { |ppv|
7
+ QueryInterface(klass::IID, ppv)
8
+
9
+ instance = klass.new(ppv.read_pointer)
10
+ }
11
+
12
+ begin
13
+ yield instance; return self
14
+ ensure
15
+ instance.Release
16
+ end if block_given?
17
+
18
+ instance
19
+ end
20
+
21
+ def UseInstance(klass, name, *args)
22
+ instance = nil
23
+
24
+ FFI::MemoryPointer.new(:pointer) { |ppv|
25
+ send(name, *args, klass::IID, ppv)
26
+
27
+ yield instance = klass.new(ppv.read_pointer)
28
+ }
29
+
30
+ self
31
+ ensure
32
+ instance.Release if instance
33
+ end
34
+ end
35
+
36
+ module COMCallback
37
+ def self.[](iface)
38
+ Class.new(FFI::Struct) {
39
+ send(:include, COMHelpers)
40
+
41
+ layout \
42
+ :lpVtbl, :pointer
43
+
44
+ def initialize(opts = {})
45
+ @vtbl, @refc = iface::VTBL.new, 1
46
+
47
+ @vtbl.members.each { |name|
48
+ @vtbl[name] = instance_variable_set("@fn#{name}",
49
+ FFI::Function.new(*@vtbl.class::SPEC[name].reverse, convention: :stdcall) { |*args|
50
+ send(name, *args[1..-1])
51
+ }
52
+ )
53
+ }
54
+
55
+ self[:lpVtbl] = @vtbl
56
+
57
+ begin
58
+ yield self
59
+ ensure
60
+ Release()
61
+ end if block_given?
62
+ end
63
+
64
+ attr_reader :vtbl, :refc
65
+
66
+ def QueryInterface(riid, ppv)
67
+ if [IUnknown::IID, iface::IID].any? { |iid| windows_com_memcmp(riid, iid, iid.size) == 0 }
68
+ ppv.write_pointer(self)
69
+ else
70
+ ppv.write_pointer(0); return E_NOINTERFACE
71
+ end
72
+
73
+ AddRef(); S_OK
74
+ end
75
+
76
+ def AddRef
77
+ @refc += 1
78
+ end
79
+
80
+ def Release
81
+ @refc -= 1
82
+ end
83
+
84
+ (iface::VTBL.members - IUnknown::VTBL.members).each { |name|
85
+ define_method(name) { |*args|
86
+ E_NOTIMPL
87
+ }
88
+ }
89
+ }
90
+ end
91
+ end
92
+
93
+ module AnonymousFFIStructSupport
94
+ def [](k)
95
+ if members.include?(k)
96
+ super
97
+ elsif self[:_].members.include?(k)
98
+ self[:_][k]
99
+ else
100
+ self[:_][:_][k]
101
+ end
102
+ end
103
+
104
+ def []=(k, v)
105
+ if members.include?(k)
106
+ super
107
+ elsif self[:_].members.include?(k)
108
+ self[:_][k] = v
109
+ else
110
+ self[:_][:_][k] = v
111
+ end
112
+ end
113
+ end
114
+
115
+ # PROPERTYKEY
116
+ def self.[](type, index)
117
+ new.tap { |key|
118
+ key[:fmtid].tap { |guid|
119
+ guid[:Data1] = 0x00000000 + index
120
+ guid[:Data2] = 0x7363
121
+ guid[:Data3] = 0x696e
122
+ [0x84, 0x41, 0x79, 0x8a, 0xcf, 0x5a, 0xeb, 0xb7].each_with_index { |part, i|
123
+ guid[:Data4][i] = part
124
+ }
125
+ }
126
+
127
+ key[:pid] = type
128
+ }
129
+ end
130
+
131
+ # PROPVARIANT
132
+ def ==(other) windows_com_memcmp(other, self, size) == 0 end
133
+
134
+ def self.[](t, *v) new.tap { |var| var.send("#{t}=", *v) } end
135
+
136
+ def bool; raise 'Wrong type tag.' unless self[:vt] == VT_BOOL; self[:boolVal] != 0 end
137
+ def bool=(bool) self[:vt] = VT_BOOL; self[:boolVal] = (bool) ? -1 : 0 end
138
+
139
+ def int; raise 'Wrong type tag.' unless self[:vt] == VT_I4; self[:intVal] end
140
+ def int=(int) self[:vt] = VT_I4; self[:intVal] = int end
141
+
142
+ def uint; raise 'Wrong type tag.' unless self[:vt] == VT_UI4; self[:uintVal] end
143
+ def uint=(uint) self[:vt] = VT_UI4; self[:uintVal] = uint end
144
+
145
+ def unknown
146
+ raise 'Wrong type tag.' unless self[:vt] == VT_UNKNOWN
147
+
148
+ yield Unknown.new(self[:punkVal])
149
+ ensure
150
+ Windows.PropVariantClear(self)
151
+ end
152
+
153
+ def unknown=(unknown) self[:vt] = VT_UNKNOWN; self[:punkVal] = unknown.pointer; unknown.AddRef end
154
+
155
+ def wstring; raise 'Wrong type tag.' unless self[:vt] == VT_LPWSTR; Windows.WCSTOMBS(self[:pwszVal]) end
156
+
157
+ def wstring=(string)
158
+ self[:vt] = VT_LPWSTR
159
+
160
+ FFI::MemoryPointer.new(:pointer) { |p|
161
+ Windows.DetonateHresult(:SHStrDup, string, p)
162
+
163
+ self[:pwszVal] = p.read_pointer
164
+ }
165
+ end
166
+
167
+ def decimal
168
+ raise 'Wrong type tag.' unless self[:vt] == VT_DECIMAL
169
+
170
+ Rational(self[:decVal][:Lo64], 10 ** self[:decVal][:scale]) + self[:decVal][:Hi32]
171
+ end
172
+
173
+ def decimal=(decimal) self[:vt] = VT_DECIMAL; self[:decVal][:Lo64] = decimal end
@@ -0,0 +1,14 @@
1
+ if __FILE__ == $0
2
+ require_relative 'common'
3
+ end
4
+
5
+ module WindowsCOM
6
+ ffi_lib FFI::Library::LIBC
7
+ ffi_convention :cdecl
8
+
9
+ attach_function :windows_com_memcmp, :memcmp, [
10
+ :pointer,
11
+ :pointer,
12
+ :size_t
13
+ ], :int
14
+ end
@@ -0,0 +1,367 @@
1
+ if __FILE__ == $0
2
+ require_relative 'common'
3
+ require_relative 'libc'
4
+ end
5
+
6
+ module WindowsCOM
7
+ ffi_lib 'ole32'
8
+ ffi_convention :stdcall
9
+
10
+ attach_function :OleInitialize, [:pointer], :long
11
+ attach_function :OleUninitialize, [], :void
12
+
13
+ def InitializeOle
14
+ DetonateHresult(:OleInitialize, nil)
15
+
16
+ STDERR.puts "OLE initialized" if $DEBUG
17
+
18
+ at_exit {
19
+ OleUninitialize()
20
+
21
+ STDERR.puts "OLE uninitialized" if $DEBUG
22
+ }
23
+ end
24
+
25
+ module_function \
26
+ :InitializeOle
27
+
28
+ InitializeOle() if WINDOWS_COM_OLE_INIT
29
+
30
+ attach_function :CoTaskMemAlloc, [:ulong], :pointer
31
+ attach_function :CoTaskMemFree, [:pointer], :void
32
+
33
+ class LARGE_INTEGER < FFI::Union
34
+ layout \
35
+ :_, Class.new(FFI::Struct) {
36
+ layout \
37
+ :LowPart, :ulong,
38
+ :HighPart, :long
39
+ },
40
+
41
+ :QuadPart, :long_long
42
+ end
43
+
44
+ class ULARGE_INTEGER < FFI::Union
45
+ layout \
46
+ :_, Class.new(FFI::Struct) {
47
+ layout \
48
+ :LowPart, :ulong,
49
+ :HighPart, :ulong
50
+ },
51
+
52
+ :QuadPart, :ulong_long
53
+ end
54
+
55
+ class DECIMAL < FFI::Struct
56
+ layout \
57
+ :wReserved, :ushort,
58
+ :scale, :uchar,
59
+ :sign, :uchar,
60
+ :Hi32, :ulong,
61
+ :Lo64, :ulong_long
62
+ end
63
+
64
+ class BLOB < FFI::Struct
65
+ layout \
66
+ :cbSize, :ulong,
67
+ :pBlobData, :pointer
68
+ end
69
+
70
+ class BSTRBLOB < FFI::Struct
71
+ layout \
72
+ :cbSize, :ulong,
73
+ :pData, :pointer
74
+ end
75
+
76
+ class FILETIME < FFI::Struct
77
+ layout \
78
+ :dwLowDateTime, :ulong,
79
+ :dwHighDateTime, :ulong
80
+ end
81
+
82
+ class CA < FFI::Struct
83
+ layout \
84
+ :cElems, :ulong,
85
+ :pElems, :pointer
86
+ end
87
+
88
+ VT_EMPTY = 0
89
+ VT_NULL = 1
90
+ VT_I2 = 2
91
+ VT_I4 = 3
92
+ VT_R4 = 4
93
+ VT_R8 = 5
94
+ VT_CY = 6
95
+ VT_DATE = 7
96
+ VT_BSTR = 8
97
+ VT_DISPATCH = 9
98
+ VT_ERROR = 10
99
+ VT_BOOL = 11
100
+ VT_VARIANT = 12
101
+ VT_UNKNOWN = 13
102
+ VT_DECIMAL = 14
103
+ VT_I1 = 16
104
+ VT_UI1 = 17
105
+ VT_UI2 = 18
106
+ VT_UI4 = 19
107
+ VT_I8 = 20
108
+ VT_UI8 = 21
109
+ VT_INT = 22
110
+ VT_UINT = 23
111
+ VT_VOID = 24
112
+ VT_HRESULT = 25
113
+ VT_PTR = 26
114
+ VT_SAFEARRAY = 27
115
+ VT_CARRAY = 28
116
+ VT_USERDEFINED = 29
117
+ VT_LPSTR = 30
118
+ VT_LPWSTR = 31
119
+ VT_FILETIME = 64
120
+ VT_BLOB = 65
121
+ VT_STREAM = 66
122
+ VT_STORAGE = 67
123
+ VT_STREAMED_OBJECT = 68
124
+ VT_STORED_OBJECT = 69
125
+ VT_BLOB_OBJECT = 70
126
+ VT_CF = 71
127
+ VT_CLSID = 72
128
+ VT_VECTOR = 0x1000
129
+ VT_ARRAY = 0x2000
130
+ VT_BYREF = 0x4000
131
+ VT_RESERVED = 0x8000
132
+ VT_ILLEGAL = 0xffff
133
+ VT_ILLEGALMASKED = 0xfff
134
+ VT_TYPEMASK = 0xff
135
+
136
+ class VARIANT < FFI::Union
137
+ layout \
138
+ :_, Class.new(FFI::Struct) {
139
+ layout \
140
+ :vt, :ushort,
141
+ :wReserved1, :ushort,
142
+ :wReserved2, :ushort,
143
+ :wReserved3, :ushort,
144
+ :_, Class.new(FFI::Union) {
145
+ layout \
146
+ :llVal, :long_long,
147
+ :lVal, :long,
148
+ :bVal, :uchar,
149
+ :iVal, :short,
150
+ :fltVal, :float,
151
+ :dblVal, :double,
152
+ :boolVal, :short,
153
+ :bool, :short,
154
+ :scode, :long,
155
+ :cyVal, :ulong_long,
156
+ :date, :double,
157
+ :bstrVal, :pointer,
158
+ :punkVal, :pointer,
159
+ :pdispVal, :pointer,
160
+ :parray, :pointer,
161
+ :pbVal, :pointer,
162
+ :piVal, :pointer,
163
+ :plVal, :pointer,
164
+ :pllVal, :pointer,
165
+ :pfltVal, :pointer,
166
+ :pdblVal, :pointer,
167
+ :pboolVal, :pointer,
168
+ :pbool, :pointer,
169
+ :pscode, :pointer,
170
+ :pcyVal, :pointer,
171
+ :pdate, :pointer,
172
+ :pbstrVal, :pointer,
173
+ :ppunkVal, :pointer,
174
+ :ppdispVal, :pointer,
175
+ :pparrayv, :pointer,
176
+ :pvarVal, :pointer,
177
+ :byref, :pointer,
178
+ :cVal, :char,
179
+ :uiVal, :ushort,
180
+ :ulVal, :ulong,
181
+ :ullVal, :ulong_long,
182
+ :intVal, :int,
183
+ :uintVal, :uint,
184
+ :pdecVal, :pointer,
185
+ :pcVal, :pointer,
186
+ :puiVal, :pointer,
187
+ :pulVal, :pointer,
188
+ :pullVal, :pointer,
189
+ :pintVal, :pointer,
190
+ :puintVal, :pointer,
191
+ :BRECORD, Class.new(FFI::Struct) {
192
+ layout \
193
+ :pvRecord, :pointer,
194
+ :pRecInfo, :pointer
195
+ }
196
+ }
197
+ },
198
+
199
+ :decVal, DECIMAL
200
+ end
201
+
202
+ class PROPERTYKEY < FFI::Struct
203
+ layout \
204
+ :fmtid, GUID,
205
+ :pid, :ulong
206
+ end
207
+
208
+ class PROPVARIANT < FFI::Union
209
+ layout \
210
+ :_, Class.new(FFI::Struct) {
211
+ layout \
212
+ :vt, :ushort,
213
+ :wReserved1, :ushort,
214
+ :wReserved2, :ushort,
215
+ :wReserved3, :ushort,
216
+ :_, Class.new(FFI::Union) {
217
+ layout \
218
+ :cVal, :char,
219
+ :bVal, :uchar,
220
+ :iVal, :short,
221
+ :uiVal, :ushort,
222
+ :lVal, :long,
223
+ :ulVal, :ulong,
224
+ :intVal, :int,
225
+ :uintVal, :uint,
226
+ :hVal, LARGE_INTEGER,
227
+ :uhVal, ULARGE_INTEGER,
228
+ :fltVal, :float,
229
+ :dblVal, :double,
230
+ :boolVal, :short,
231
+ :bool, :short,
232
+ :scode, :long,
233
+ :cyVal, :long_long,
234
+ :date, :double,
235
+ :filetime, FILETIME,
236
+ :puuid, :pointer,
237
+ :pclipdata, :pointer,
238
+ :bstrVal, :pointer,
239
+ :bstrblobVal, BSTRBLOB,
240
+ :blob, BLOB,
241
+ :pszVal, :pointer,
242
+ :pwszVal, :pointer,
243
+ :punkVal, :pointer,
244
+ :pdispVal, :pointer,
245
+ :pStream, :pointer,
246
+ :pStorage, :pointer,
247
+ :pVersionedStream, :pointer,
248
+ :parray, :pointer,
249
+ :cac, CA,
250
+ :caub, CA,
251
+ :cai, CA,
252
+ :caui, CA,
253
+ :cal, CA,
254
+ :caul, CA,
255
+ :cah, CA,
256
+ :cauh, CA,
257
+ :caflt, CA,
258
+ :cadbl, CA,
259
+ :cabool, CA,
260
+ :cascode, CA,
261
+ :cacy, CA,
262
+ :cadate, CA,
263
+ :cafiletime, CA,
264
+ :cauuid, CA,
265
+ :caclipdata, CA,
266
+ :cabstr, CA,
267
+ :cabstrblob, CA,
268
+ :calpstr, CA,
269
+ :calpwstr, CA,
270
+ :capropvar, CA,
271
+ :pcVal, :pointer,
272
+ :pbVal, :pointer,
273
+ :piVal, :pointer,
274
+ :puiVal, :pointer,
275
+ :plVal, :pointer,
276
+ :pulVal, :pointer,
277
+ :pintVal, :pointer,
278
+ :puintVal, :pointer,
279
+ :pfltVal, :pointer,
280
+ :pdblVal, :pointer,
281
+ :pboolVal, :pointer,
282
+ :pdecVal, :pointer,
283
+ :pscode, :pointer,
284
+ :pcyVal, :pointer,
285
+ :pdate, :pointer,
286
+ :pbstrVal, :pointer,
287
+ :ppunkVal, :pointer,
288
+ :ppdispVal, :pointer,
289
+ :pparray, :pointer,
290
+ :pvarVal, :pointer
291
+ }
292
+ },
293
+
294
+ :decVal, DECIMAL
295
+ end
296
+
297
+ attach_function :PropVariantClear, [:pointer], :long
298
+
299
+ CLSCTX_INPROC_SERVER = 0x1
300
+ CLSCTX_INPROC_HANDLER = 0x2
301
+ CLSCTX_LOCAL_SERVER = 0x4
302
+ CLSCTX_INPROC_SERVER16 = 0x8
303
+ CLSCTX_REMOTE_SERVER = 0x10
304
+ CLSCTX_INPROC_HANDLER16 = 0x20
305
+ CLSCTX_RESERVED1 = 0x40
306
+ CLSCTX_RESERVED2 = 0x80
307
+ CLSCTX_RESERVED3 = 0x100
308
+ CLSCTX_RESERVED4 = 0x200
309
+ CLSCTX_NO_CODE_DOWNLOAD = 0x400
310
+ CLSCTX_RESERVED5 = 0x800
311
+ CLSCTX_NO_CUSTOM_MARSHAL = 0x1000
312
+ CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000
313
+ CLSCTX_NO_FAILURE_LOG = 0x4000
314
+ CLSCTX_DISABLE_AAA = 0x8000
315
+ CLSCTX_ENABLE_AAA = 0x10000
316
+ CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000
317
+ CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000
318
+ CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000
319
+ CLSCTX_ENABLE_CLOAKING = 0x100000
320
+ CLSCTX_PS_DLL = -0x80000000
321
+ CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER
322
+ CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
323
+ CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
324
+
325
+ attach_function :CoCreateInstance, [:pointer, :pointer, :ulong, :pointer, :pointer], :long
326
+
327
+ IUnknown = COMInterface[nil,
328
+ '00000000-0000-0000-C000-000000000046',
329
+
330
+ QueryInterface: [[:pointer, :pointer], :long],
331
+ AddRef: [[], :ulong],
332
+ Release: [[], :ulong]
333
+ ]
334
+
335
+ IDispatch = COMInterface[IUnknown,
336
+ '00020400-0000-0000-C000-000000000046',
337
+
338
+ GetTypeInfoCount: [[:pointer], :long],
339
+ GetTypeInfo: [[:uint, :ulong, :pointer], :long],
340
+ GetIDsOfNames: [[:pointer, :pointer, :uint, :ulong, :pointer], :long],
341
+ Invoke: [[:long, :pointer, :ulong, :ushort, :pointer, :pointer, :pointer, :pointer], :long]
342
+ ]
343
+
344
+ IConnectionPointContainer = COMInterface[IUnknown,
345
+ 'B196B284-BAB4-101A-B69C-00AA00341D07',
346
+
347
+ EnumConnectionPoints: [[:pointer], :long],
348
+ FindConnectionPoint: [[:pointer, :pointer], :long]
349
+ ]
350
+
351
+ IConnectionPoint = COMInterface[IUnknown,
352
+ 'B196B286-BAB4-101A-B69C-00AA00341D07',
353
+
354
+ GetConnectionInterface: [[:pointer], :long],
355
+ GetConnectionPointContainer: [[:pointer], :long],
356
+ Advise: [[:pointer, :pointer], :long],
357
+ Unadvise: [[:ulong], :long],
358
+ EnumConnections: [[:pointer], :long]
359
+ ]
360
+
361
+ IObjectWithSite = COMInterface[IUnknown,
362
+ 'FC4801A3-2BA9-11CF-A229-00AA003D7352',
363
+
364
+ SetSite: [[:pointer], :long],
365
+ GetSite: [[:pointer, :pointer], :long]
366
+ ]
367
+ end
@@ -0,0 +1,204 @@
1
+ if __FILE__ == $0
2
+ require_relative 'common'
3
+ require_relative 'libc'
4
+ require_relative 'ole'
5
+ end
6
+
7
+ module WindowsCOM
8
+ ffi_lib 'oleaut32'
9
+ ffi_convention :stdcall
10
+
11
+ attach_function :SysAllocString, [:buffer_in], :pointer
12
+ attach_function :SysFreeString, [:pointer], :void
13
+ attach_function :SysStringLen, [:pointer], :uint
14
+
15
+ class SAFEARRAYBOUND < FFI::Struct
16
+ layout \
17
+ :cElements, :ulong,
18
+ :lLbound, :long
19
+ end
20
+
21
+ class SAFEARRAY < FFI::Struct
22
+ layout \
23
+ :cDims, :ushort,
24
+ :fFeatures, :ushort,
25
+ :cbElements, :ulong,
26
+ :cLocks, :ulong,
27
+ :pvData, :pointer,
28
+ :rgsabound, [SAFEARRAYBOUND, 1]
29
+ end
30
+
31
+ attach_function :SafeArrayCreateVector, [:ushort, :long, :uint], :pointer
32
+ attach_function :SafeArrayDestroy, [:pointer], :long
33
+ attach_function :SafeArrayAccessData, [:pointer, :pointer], :long
34
+ attach_function :SafeArrayUnaccessData, [:pointer], :long
35
+
36
+ OLEIVERB_PRIMARY = 0
37
+ OLEIVERB_SHOW = -1
38
+ OLEIVERB_OPEN = -2
39
+ OLEIVERB_HIDE = -3
40
+ OLEIVERB_UIACTIVATE = -4
41
+ OLEIVERB_INPLACEACTIVATE = -5
42
+ OLEIVERB_DISCARDUNDOSTATE = -6
43
+
44
+ IOleWindow = COMInterface[IUnknown,
45
+ '00000114-0000-0000-C000-000000000046',
46
+
47
+ GetWindow: [[:pointer], :long],
48
+ ContextSensitiveHelp: [[:int], :long]
49
+ ]
50
+
51
+ IOleInPlaceObject = COMInterface[IOleWindow,
52
+ '00000113-0000-0000-C000-000000000046',
53
+
54
+ InPlaceDeactivate: [[], :long],
55
+ UIDeactivate: [[], :long],
56
+ SetObjectRects: [[:pointer, :pointer], :long],
57
+ ReactivateAndUndo: [[], :long]
58
+ ]
59
+
60
+ IOleInPlaceSite = COMInterface[IOleWindow,
61
+ '00000119-0000-0000-C000-000000000046',
62
+
63
+ CanInPlaceActivate: [[], :long],
64
+ OnInPlaceActivate: [[], :long],
65
+ OnUIActivate: [[], :long],
66
+ GetWindowContext: [[:pointer, :pointer, :pointer, :pointer, :pointer], :long],
67
+ Scroll: [[:long_long], :long],
68
+ OnUIDeactivate: [[:int], :long],
69
+ OnInPlaceDeactivate: [[], :long],
70
+ DiscardUndoState: [[], :long],
71
+ DeactivateAndUndo: [[], :long],
72
+ OnPosRectChange: [[:pointer], :long]
73
+ ]
74
+
75
+ IOleClientSite = COMInterface[IUnknown,
76
+ '00000118-0000-0000-C000-000000000046',
77
+
78
+ SaveObject: [[], :long],
79
+ GetMoniker: [[:ulong, :ulong, :pointer], :long],
80
+ GetContainer: [[:pointer], :long],
81
+ ShowObject: [[], :long],
82
+ OnShowWindow: [[:int], :long],
83
+ RequestNewObjectLayout: [[], :long]
84
+ ]
85
+
86
+ OLEGETMONIKER_ONLYIFTHERE = 1
87
+ OLEGETMONIKER_FORCEASSIGN = 2
88
+ OLEGETMONIKER_UNASSIGN = 3
89
+ OLEGETMONIKER_TEMPFORUSER = 4
90
+
91
+ OLEWHICHMK_CONTAINER = 1
92
+ OLEWHICHMK_OBJREL = 2
93
+ OLEWHICHMK_OBJFULL = 3
94
+
95
+ USERCLASSTYPE_FULL = 1
96
+ USERCLASSTYPE_SHORT = 2
97
+ USERCLASSTYPE_APPNAME = 3
98
+
99
+ OLEMISC_RECOMPOSEONRESIZE = 0x00000001
100
+ OLEMISC_ONLYICONIC = 0x00000002
101
+ OLEMISC_INSERTNOTREPLACE = 0x00000004
102
+ OLEMISC_STATIC = 0x00000008
103
+ OLEMISC_CANTLINKINSIDE = 0x00000010
104
+ OLEMISC_CANLINKBYOLE1 = 0x00000020
105
+ OLEMISC_ISLINKOBJECT = 0x00000040
106
+ OLEMISC_INSIDEOUT = 0x00000080
107
+ OLEMISC_ACTIVATEWHENVISIBLE = 0x00000100
108
+ OLEMISC_RENDERINGISDEVICEINDEPENDENT = 0x00000200
109
+ OLEMISC_INVISIBLEATRUNTIME = 0x00000400
110
+ OLEMISC_ALWAYSRUN = 0x00000800
111
+ OLEMISC_ACTSLIKEBUTTON = 0x00001000
112
+ OLEMISC_ACTSLIKELABEL = 0x00002000
113
+ OLEMISC_NOUIACTIVATE = 0x00004000
114
+ OLEMISC_ALIGNABLE = 0x00008000
115
+ OLEMISC_SIMPLEFRAME = 0x00010000
116
+ OLEMISC_SETCLIENTSITEFIRST = 0x00020000
117
+ OLEMISC_IMEMODE = 0x00040000
118
+ OLEMISC_IGNOREACTIVATEWHENVISIBLE = 0x00080000
119
+ OLEMISC_WANTSTOMENUMERGE = 0x00100000
120
+ OLEMISC_SUPPORTSMULTILEVELUNDO = 0x00200000
121
+
122
+ OLECLOSE_SAVEIFDIRTY = 0
123
+ OLECLOSE_NOSAVE = 1
124
+ OLECLOSE_PROMPTSAVE = 2
125
+
126
+ IOleObject = COMInterface[IUnknown,
127
+ '00000112-0000-0000-C000-000000000046',
128
+
129
+ SetClientSite: [[:pointer], :long],
130
+ GetClientSite: [[:pointer], :long],
131
+ SetHostNames: [[:pointer, :pointer], :long],
132
+ Close: [[:ulong], :long],
133
+ SetMoniker: [[:ulong, :pointer], :long],
134
+ GetMoniker: [[:ulong, :ulong, :pointer], :long],
135
+ InitFromData: [[:pointer, :int, :ulong], :long],
136
+ GetClipboardData: [[:ulong, :pointer], :long],
137
+ DoVerb: [[:long, :pointer, :pointer, :long, :pointer, :pointer], :long],
138
+ EnumVerbs: [[:pointer], :long],
139
+ Update: [[], :long],
140
+ IsUpToDate: [[], :long],
141
+ GetUserClassID: [[:pointer], :long],
142
+ GetUserType: [[:ulong, :pointer], :long],
143
+ SetExtent: [[:ulong, :pointer], :long],
144
+ GetExtent: [[:ulong, :pointer], :long],
145
+ Advise: [[:pointer, :pointer], :long],
146
+ Unadvise: [[:ulong], :long],
147
+ EnumAdvise: [[:pointer], :long],
148
+ GetMiscStatus: [[:ulong, :pointer], :long],
149
+ SetColorScheme: [[:pointer], :long]
150
+ ]
151
+
152
+ class PARAMDATA < FFI::Struct
153
+ layout \
154
+ :szName, :pointer,
155
+ :vt, :ushort
156
+ end
157
+
158
+ CC_FASTCALL = 0
159
+ CC_CDECL = 1
160
+ CC_MSCPASCAL = CC_CDECL + 1
161
+ CC_PASCAL = CC_MSCPASCAL
162
+ CC_MACPASCAL = CC_PASCAL + 1
163
+ CC_STDCALL = CC_MACPASCAL + 1
164
+ CC_FPFASTCALL = CC_STDCALL + 1
165
+ CC_SYSCALL = CC_FPFASTCALL + 1
166
+ CC_MPWCDECL = CC_SYSCALL + 1
167
+ CC_MPWPASCAL = CC_MPWCDECL + 1
168
+ CC_MAX = CC_MPWPASCAL + 1
169
+
170
+ DISPATCH_METHOD = 0x1
171
+ DISPATCH_PROPERTYGET = 0x2
172
+ DISPATCH_PROPERTYPUT = 0x4
173
+ DISPATCH_PROPERTYPUTREF = 0x8
174
+
175
+ class METHODDATA < FFI::Struct
176
+ layout \
177
+ :szName, :pointer,
178
+ :ppdata, :pointer,
179
+ :dispid, :long,
180
+ :iMeth, :uint,
181
+ :cc, :uint,
182
+ :cArgs, :uint,
183
+ :wFlags, :ushort,
184
+ :vtReturn, :ushort
185
+ end
186
+
187
+ class INTERFACEDATA < FFI::Struct
188
+ layout \
189
+ :pmethdata, :pointer,
190
+ :cMembers, :uint
191
+ end
192
+
193
+ attach_function :CreateDispTypeInfo, [:pointer, :ulong, :pointer], :long
194
+
195
+ class DISPPARAMS < FFI::Struct
196
+ layout \
197
+ :rgvarg, :pointer,
198
+ :rgdispidNamedArgs, :pointer,
199
+ :cArgs, :uint,
200
+ :cNamedArgs, :uint
201
+ end
202
+
203
+ attach_function :DispInvoke, [:pointer, :pointer, :long, :ushort, :pointer, :pointer, :pointer, :pointer], :long
204
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: windows_com
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Radoslav Peev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ description: Ruby FFI (x86) bindings to essential COM related Windows APIs
28
+ email:
29
+ - rpeev@ymail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE
35
+ - README.md
36
+ - RELNOTES.md
37
+ - examples/DesktopGadget.rbw
38
+ - lib/windows_com.rb
39
+ - lib/windows_com/common.rb
40
+ - lib/windows_com/cruft.rb
41
+ - lib/windows_com/libc.rb
42
+ - lib/windows_com/ole.rb
43
+ - lib/windows_com/oleaut.rb
44
+ homepage: https://github.com/rpeev/windows_com
45
+ licenses:
46
+ - MIT
47
+ metadata: {}
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 2.5.2
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: Ruby FFI (x86) bindings to essential COM related Windows APIs
68
+ test_files: []