windows_com 1.0.0

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 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: []