fzeet 0.4.2 → 0.5.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.
Files changed (63) hide show
  1. data/examples/Dialog/FileDialog.rbw +34 -0
  2. data/examples/Raw/UIRibbon/Command.dll +0 -0
  3. data/examples/Raw/UIRibbon/Command.rb +22 -0
  4. data/examples/Raw/UIRibbon/Command.rbw +51 -0
  5. data/examples/Raw/UIRibbon/Command.xml +65 -0
  6. data/examples/Raw/UIRibbon/Minimal.dll +0 -0
  7. data/examples/Raw/UIRibbon/Minimal.rb +16 -0
  8. data/examples/Raw/UIRibbon/Minimal.rbw +39 -0
  9. data/examples/Raw/UIRibbon/Minimal.xml +55 -0
  10. data/examples/UIRibbon/Command.dll +0 -0
  11. data/examples/UIRibbon/Command.rb +22 -0
  12. data/examples/UIRibbon/Command.rbw +20 -0
  13. data/examples/UIRibbon/Command.xml +65 -0
  14. data/examples/UIRibbon/Minimal.dll +0 -0
  15. data/examples/UIRibbon/Minimal.rb +16 -0
  16. data/examples/UIRibbon/Minimal.rbw +8 -0
  17. data/examples/UIRibbon/Minimal.xml +55 -0
  18. data/examples/UIRibbon/Viewer.rbw +9 -0
  19. data/examples/res/go-next-small.bmp +0 -0
  20. data/examples/res/go-next.bmp +0 -0
  21. data/examples/res/go-previous-small.bmp +0 -0
  22. data/examples/res/go-previous.bmp +0 -0
  23. data/lib/fzeet/Control.rb +1 -89
  24. data/lib/fzeet/ControlButton.rb +28 -0
  25. data/lib/fzeet/ControlCommon.rb +64 -0
  26. data/lib/fzeet/Dialog.rb +1 -0
  27. data/lib/fzeet/DialogCommon.rb +5 -0
  28. data/lib/fzeet/DialogFileDialog.rb +116 -0
  29. data/lib/fzeet/UIRibbon.rb +99 -0
  30. data/lib/fzeet/Window.rb +2 -336
  31. data/lib/fzeet/WindowCommon.rb +256 -0
  32. data/lib/fzeet/WindowDialog.rb +73 -0
  33. data/lib/fzeet/WindowWindow.rb +13 -0
  34. data/lib/fzeet/common.rb +2 -0
  35. data/lib/fzeet/windows/com.rb +186 -0
  36. data/lib/fzeet/windows/comctl.rb +1 -59
  37. data/lib/fzeet/windows/comctlbutton.rb +30 -0
  38. data/lib/fzeet/windows/comctlcommon.rb +34 -0
  39. data/lib/fzeet/windows/comdlg.rb +1 -0
  40. data/lib/fzeet/windows/comdlgcommon.rb +9 -0
  41. data/lib/fzeet/windows/comdlgofn.rb +70 -0
  42. data/lib/fzeet/windows/common.rb +18 -0
  43. data/lib/fzeet/windows/kernel.rb +3 -0
  44. data/lib/fzeet/windows/libc.rb +1 -0
  45. data/lib/fzeet/windows/ole.rb +213 -0
  46. data/lib/fzeet/windows/shell.rb +43 -0
  47. data/lib/fzeet/windows/uiribbon.rb +111 -0
  48. data/lib/fzeet/windows/user.rb +7 -438
  49. data/lib/fzeet/windows/usercommon.rb +8 -0
  50. data/lib/fzeet/windows/userctl.rb +1 -68
  51. data/lib/fzeet/windows/userctlbutton.rb +56 -0
  52. data/lib/fzeet/windows/userctlcommon.rb +12 -0
  53. data/lib/fzeet/windows/userkbd.rb +20 -0
  54. data/lib/fzeet/windows/usermbox.rb +62 -0
  55. data/lib/fzeet/windows/usermenu.rb +50 -0
  56. data/lib/fzeet/windows/usermsg.rb +1 -6
  57. data/lib/fzeet/windows/userspi.rb +29 -0
  58. data/lib/fzeet/windows/userwnd.rb +276 -0
  59. data/lib/fzeet/windows.rb +24 -4
  60. data/lib/fzeet.rb +2 -0
  61. metadata +54 -6
  62. /data/examples/{Dialog.rbw → Dialog/Dialog.rbw} +0 -0
  63. /data/examples/{DialogApplication.rbw → Dialog/DialogApplication.rbw} +0 -0
@@ -0,0 +1,256 @@
1
+ require_relative 'WindowMethods'
2
+
3
+ module Fzeet
4
+ class BasicWindow < Handle
5
+ include WindowMethods
6
+
7
+ Prefix = {
8
+ xstyle: [:ws_ex_],
9
+ style: [:ws_, :ds_],
10
+ message: [:wm_],
11
+ notification: []
12
+ }
13
+
14
+ WindowProc = FFI::Function.new(:long, [:pointer, :uint, :uint, :long], convention: :stdcall) { |hwnd, uMsg, wParam, lParam|
15
+ begin
16
+ if uMsg == Windows::WM_NCCREATE
17
+ @@instances[hwnd.to_i] = ObjectSpace._id2ref(
18
+ Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))[:lpCreateParams].to_i
19
+ )
20
+
21
+ @@instances[hwnd.to_i].instance_variable_set(:@handle, hwnd)
22
+ end
23
+
24
+ result = @@instances[hwnd.to_i].windowProc(hwnd, uMsg, wParam, lParam) if @@instances[hwnd.to_i]
25
+ rescue
26
+ answer = Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, buttons: [:abort, :retry, :ignore], icon: :error
27
+
28
+ Application.quit if answer.abort?
29
+ ensure
30
+ if uMsg == Windows::WM_NCDESTROY
31
+ @@instances[hwnd.to_i].dialog = false
32
+
33
+ @@instances.delete(hwnd.to_i)
34
+ end
35
+ end
36
+
37
+ result || Windows.DefWindowProc(hwnd, uMsg, wParam, lParam)
38
+ }
39
+
40
+ DialogProc = FFI::Function.new(:int, [:pointer, :uint, :uint, :long], convention: :stdcall) { |hwnd, uMsg, wParam, lParam|
41
+ begin
42
+ if uMsg == Windows::WM_INITDIALOG
43
+ @@instances[hwnd.to_i] = ObjectSpace._id2ref(lParam)
44
+
45
+ @@instances[hwnd.to_i].instance_variable_set(:@handle, hwnd)
46
+ end
47
+
48
+ result = @@instances[hwnd.to_i].windowProc(hwnd, uMsg, wParam, lParam) if @@instances[hwnd.to_i]
49
+ rescue
50
+ answer = Fzeet.message %Q{#{$!}\n\n#{$!.backtrace.join("\n")}}, buttons: [:abort, :retry, :ignore], icon: :error
51
+
52
+ Application.quit if answer.abort?
53
+ ensure
54
+ if uMsg == Windows::WM_NCDESTROY
55
+ @@instances[hwnd.to_i].dialog = false
56
+
57
+ @@instances.delete(hwnd.to_i)
58
+ end
59
+ end
60
+
61
+ (result.nil?) ? 0 : 1
62
+ }
63
+
64
+ WindowClass = Fzeet::WindowClass.new(nil, 'Fzeet.BasicWindow')
65
+
66
+ def self.[](name, opts = {})
67
+ Class.new(self) { |klass|
68
+ klass.const_set(:WindowClass, Fzeet::WindowClass.new(self::WindowClass, name, opts))
69
+ }
70
+ end
71
+
72
+ def self.crackMessage(hwnd, uMsg, wParam, lParam)
73
+ window = @@instances[hwnd.to_i]
74
+
75
+ args = {
76
+ hwnd: hwnd,
77
+ uMsg: uMsg,
78
+ wParam: wParam,
79
+ lParam: lParam,
80
+ result: (window.kind_of?(Dialog)) ? 1 : 0,
81
+ window: window,
82
+ sender: window
83
+ }
84
+
85
+ case uMsg
86
+ when Windows::WM_CREATE
87
+ args[:cs] = Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))
88
+ when Windows::WM_NCCREATE
89
+ args[:result] = 1
90
+ args[:cs] = Windows::CREATESTRUCT.new(FFI::Pointer.new(lParam))
91
+ when Windows::WM_COMMAND
92
+ args[:command], args[:notification], args[:hctl] = Windows.LOWORD(wParam), Windows.HIWORD(wParam), FFI::Pointer.new(lParam)
93
+ args[:sender] = @@instances[args[:hctl].to_i] unless args[:hctl].null?
94
+ when Windows::WM_NOTIFY
95
+ args[:nmh] = Windows::NMHDR.new(FFI::Pointer.new(lParam))
96
+ args[:command], args[:notification], args[:hctl] = args[:nmh][:idFrom], args[:nmh][:code], args[:nmh][:hwndFrom]
97
+ (args[:sender] = @@instances[args[:hctl].to_i]).class.crackNotification(args)
98
+ when \
99
+ Windows::WM_MOUSEMOVE,
100
+ Windows::WM_LBUTTONDOWN, Windows::WM_LBUTTONUP, Windows::WM_LBUTTONDBLCLK,
101
+ Windows::WM_RBUTTONDOWN, Windows::WM_RBUTTONUP, Windows::WM_RBUTTONDBLCLK,
102
+ Windows::WM_MBUTTONDOWN, Windows::WM_MBUTTONUP, Windows::WM_MBUTTONDBLCLK,
103
+ Windows::WM_CONTEXTMENU
104
+
105
+ args[:x], args[:y] = Windows.GET_X_LPARAM(lParam), Windows.GET_Y_LPARAM(lParam)
106
+
107
+ if uMsg == Windows::WM_CONTEXTMENU && args[:x] == -1
108
+ Windows.DetonateLastError(0, :GetCursorPos, pt = Point.new)
109
+
110
+ args[:keyboard], args[:x], args[:y] = true, pt[:x], pt[:y]
111
+ end
112
+ end
113
+
114
+ args
115
+ end
116
+
117
+ def initialize(opts = {})
118
+ _opts = {
119
+ xstyle: [],
120
+ caption: Application.name,
121
+ style: [],
122
+ x: Windows::CW_USEDEFAULT,
123
+ y: Windows::CW_USEDEFAULT,
124
+ width: Windows::CW_USEDEFAULT,
125
+ height: Windows::CW_USEDEFAULT,
126
+ parent: nil,
127
+ menu: nil
128
+ }
129
+ badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
130
+ _opts.merge!(opts)
131
+
132
+ yield self, _opts if block_given?
133
+
134
+ _opts[:xstyle] = Fzeet.flags(_opts[:xstyle], *self.class::Prefix[:xstyle])
135
+ _opts[:caption] = _opts[:caption].to_s
136
+ _opts[:style] = Fzeet.flags(_opts[:style], *self.class::Prefix[:style])
137
+
138
+ @messages ||= {}
139
+ @commands ||= {}
140
+ @notifies ||= {}
141
+
142
+ @processed = [0, 0]
143
+
144
+ @handle = Windows.CreateWindowEx(
145
+ _opts[:xstyle], self.class::WindowClass.name, _opts[:caption], _opts[:style],
146
+ _opts[:x], _opts[:y], _opts[:width], _opts[:height],
147
+ _opts[:parent] && _opts[:parent].handle, nil, Windows.GetModuleHandle(nil), FFI::Pointer.new(object_id)
148
+ )
149
+
150
+ if @handle.null?
151
+ raise "CreateWindowEx failed (last error #{Windows.GetLastError()})." unless [
152
+ [Windows::WM_NCCREATE, 0], [Windows::WM_CREATE, -1],
153
+ [Windows::WM_DESTROY, 0], [Windows::WM_NCDESTROY, 0]
154
+ ].include?(@processed)
155
+ else
156
+ @parent = _opts[:parent]
157
+ self.menu = _opts[:menu] if _opts[:menu]
158
+
159
+ on(:destroy) {
160
+ menu.rdetach if self.menu
161
+
162
+ eachChild(&:dispose)
163
+ }
164
+ end
165
+ end
166
+
167
+ attr_reader :parent
168
+
169
+ def dispose; Windows.DestroyWindow(@handle) end
170
+
171
+ def windowProc(hwnd, uMsg, wParam, lParam)
172
+ args, result = nil, nil
173
+
174
+ if (handlers = @messages[uMsg])
175
+ args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
176
+
177
+ handlers.each { |handler|
178
+ (handler.arity == 0) ? handler.call : handler.call(args)
179
+
180
+ result = args[:result]; @processed[0], @processed[1] = uMsg, result
181
+ }
182
+ end
183
+
184
+ if uMsg == Windows::WM_COMMAND && (handlers = @commands[Windows.LOWORD(wParam)])
185
+ args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
186
+
187
+ handlers[:all].each { |handler|
188
+ (handler.arity == 0) ? handler.call : handler.call(args)
189
+
190
+ result = args[:result]; @processed[0], @processed[1] = uMsg, result
191
+ } if handlers[:all]
192
+
193
+ handlers[Windows.HIWORD(wParam)].each { |handler|
194
+ (handler.arity == 0) ? handler.call : handler.call(args)
195
+
196
+ result = args[:result]; @processed[0], @processed[1] = uMsg, result
197
+ } if handlers[Windows.HIWORD(wParam)]
198
+ end
199
+
200
+ if uMsg == Windows::WM_NOTIFY && (handlers = @notifies[(nmh = Windows::NMHDR.new(FFI::Pointer.new(lParam)))[:idFrom]])
201
+ args ||= self.class.crackMessage(hwnd, uMsg, wParam, lParam)
202
+
203
+ handlers[:all].each { |handler|
204
+ (handler.arity == 0) ? handler.call : handler.call(args)
205
+
206
+ result = args[:result]; @processed[0], @processed[1] = uMsg, result
207
+ } if handlers[:all]
208
+
209
+ handlers[nmh[:code]].each { |handler|
210
+ (handler.arity == 0) ? handler.call : handler.call(args)
211
+
212
+ result = args[:result]; @processed[0], @processed[1] = uMsg, result
213
+ } if handlers[nmh[:code]]
214
+ end
215
+
216
+ result
217
+ end
218
+
219
+ def onMessage(msg, &block)
220
+ ((@messages ||= {})[Fzeet.constant(msg, :wm_)] ||= []) << block
221
+
222
+ self
223
+ end
224
+
225
+ def onCommand(cmd, notification = :all, &block)
226
+ notification = Fzeet.constant(notification, *self[cmd].class::Prefix[:notification]) unless
227
+ notification.kind_of?(Integer) || notification == :all
228
+
229
+ (((@commands ||= {})[Command[cmd]] ||= {})[notification] ||= []) << block
230
+
231
+ self
232
+ end
233
+
234
+ def onNotify(cmd, notification = :all, &block)
235
+ notification = Fzeet.constant(notification, *self[cmd].class::Prefix[:notification]) unless
236
+ notification.kind_of?(Integer) || notification == :all
237
+
238
+ (((@notifies ||= {})[Command[cmd]] ||= {})[notification] ||= []) << block
239
+
240
+ self
241
+ end
242
+
243
+ def on(*args, &block)
244
+ case args.length
245
+ when 1; onMessage(*args, &block)
246
+ when 2, 3
247
+ case Fzeet.constant(args.shift, :wm_)
248
+ when Windows::WM_COMMAND; onCommand(*args, &block)
249
+ when Windows::WM_NOTIFY; onNotify(*args, &block)
250
+ else raise ArgumentError
251
+ end
252
+ else raise ArgumentError
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,73 @@
1
+ require_relative 'WindowCommon'
2
+
3
+ module Fzeet
4
+ Dialog = BasicWindow['Fzeet.Dialog',
5
+ wndProc: BasicWindow::DialogProc
6
+ ]
7
+
8
+ class Dialog
9
+ def initialize(parent, opts = {}, &block)
10
+ @parent = parent
11
+
12
+ _opts = {
13
+ xstyle: [:noparentnotify],
14
+ caption: Application.name,
15
+ style: [:sysmenu, :visible],
16
+ x: 0,
17
+ y: 0,
18
+ width: 200,
19
+ height: 150,
20
+ modal: false
21
+ }
22
+ badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
23
+ _opts.merge!(opts)
24
+
25
+ _opts[:xstyle] = Fzeet.flags(_opts[:xstyle], *self.class::Prefix[:xstyle])
26
+ _opts[:caption] = _opts[:caption].to_s
27
+ _opts[:style] = Fzeet.flags(_opts[:style], *self.class::Prefix[:style])
28
+
29
+ @messages ||= {}
30
+ @commands ||= {}
31
+ @notifies ||= {}
32
+
33
+ @processed = [0, 0]
34
+
35
+ dt = Windows::DLGTEMPLATE.new
36
+
37
+ dt[:style] = _opts[:style]
38
+ dt[:dwExtendedStyle] = _opts[:xstyle]
39
+ dt[:x] = _opts[:x]
40
+ dt[:y] = _opts[:y]
41
+ dt[:cx] = _opts[:width]
42
+ dt[:cy] = _opts[:height]
43
+
44
+ on(:initdialog) { self.text = _opts[:caption] }
45
+
46
+ on(:initdialog, &block) if block
47
+
48
+ if _opts[:modal]
49
+ @result = Windows.DetonateLastError([-1, 0], :DialogBoxIndirectParam,
50
+ Windows.GetModuleHandle(nil),
51
+ dt,
52
+ @parent && @parent.handle,
53
+ BasicWindow::DialogProc,
54
+ object_id
55
+ )
56
+ else
57
+ @handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateDialogIndirectParam,
58
+ Windows.GetModuleHandle(nil),
59
+ dt,
60
+ @parent && @parent.handle,
61
+ BasicWindow::DialogProc,
62
+ object_id
63
+ )
64
+
65
+ self.dialog = true
66
+ end
67
+ end
68
+
69
+ def end(result) Windows.DetonateLastError(0, :EndDialog, @handle, Command[result]); self end
70
+
71
+ def result; DialogResult.new(@result) end
72
+ end
73
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'WindowCommon'
2
+
3
+ module Fzeet
4
+ Window = BasicWindow['Fzeet.Window']
5
+
6
+ class Window
7
+ def initialize(opts = {})
8
+ (opts[:style] ||= []) << :overlappedwindow << :clipchildren
9
+
10
+ super
11
+ end
12
+ end
13
+ end
data/lib/fzeet/common.rb CHANGED
@@ -16,6 +16,8 @@ module Fzeet
16
16
 
17
17
  Windows.EnableVisualStyles
18
18
 
19
+ Windows.InitializeOle
20
+
19
21
  def constant(c, *prefixes)
20
22
  return c if c.kind_of?(Integer) || c.kind_of?(FFI::Pointer)
21
23
 
@@ -0,0 +1,186 @@
1
+ require_relative 'common'
2
+
3
+ module Fzeet
4
+ module Windows
5
+ ffi_lib 'ole32'
6
+ ffi_convention :stdcall
7
+
8
+ S_OK = 0
9
+
10
+ E_NOTIMPL = 0x80004001 - 0x1_0000_0000
11
+ E_NOINTERFACE = 0x80004002 - 0x1_0000_0000
12
+
13
+ def SUCCEEDED(hr) hr >= 0 end
14
+ def FAILED(hr) hr < 0 end
15
+
16
+ module_function \
17
+ :SUCCEEDED,
18
+ :FAILED
19
+
20
+ class GUID < FFI::Struct
21
+ layout \
22
+ :Data1, :ulong,
23
+ :Data2, :ushort,
24
+ :Data3, :ushort,
25
+ :Data4, [:uchar, 8]
26
+
27
+ def self.[](s)
28
+ raise 'Bad GUID format.' unless s =~ /^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/i
29
+
30
+ new.tap { |guid|
31
+ guid[:Data1] = s[0, 8].to_i(16)
32
+ guid[:Data2] = s[9, 4].to_i(16)
33
+ guid[:Data3] = s[14, 4].to_i(16)
34
+ guid[:Data4][0] = s[19, 2].to_i(16)
35
+ guid[:Data4][1] = s[21, 2].to_i(16)
36
+ s[24, 12].split('').each_slice(2).with_index { |a, i|
37
+ guid[:Data4][i + 2] = a.join('').to_i(16)
38
+ }
39
+ }
40
+ end
41
+ end
42
+
43
+ CLSCTX_INPROC_SERVER = 0x1
44
+
45
+ attach_function :CoCreateInstance, [:pointer, :pointer, :ulong, :pointer, :pointer], :long
46
+
47
+ module COM
48
+ module Interface
49
+ def self.[](*args)
50
+ spec, iid, *ifaces = args.reverse
51
+
52
+ spec.each { |name, signature| signature[0].unshift(:pointer) }
53
+
54
+ Class.new(FFI::Struct) { |iface|
55
+ iface.const_set(:IID, iid)
56
+
57
+ iface.const_set(:VTBL, Class.new(FFI::Struct) { |vtbl|
58
+ vtbl.const_set(:SPEC, Hash[(ifaces.map { |iface| iface::VTBL::SPEC.to_a } << spec.to_a).flatten(1)])
59
+
60
+ vtbl.layout \
61
+ *vtbl::SPEC.map { |name, signature| [name, callback(*signature)] }.flatten
62
+ })
63
+
64
+ iface.layout \
65
+ :lpVtbl, :pointer
66
+ }
67
+ end
68
+ end
69
+
70
+ module Instance
71
+ def self.[](iface)
72
+ Class.new(iface) { |klass|
73
+ def initialize(pointer)
74
+ self.pointer = pointer
75
+
76
+ @vtbl = self.class::VTBL.new(self[:lpVtbl])
77
+ end
78
+
79
+ attr_reader :vtbl
80
+
81
+ VTBL.members.each { |name|
82
+ define_method(name) { |*args|
83
+ raise "#{self}.#{name} failed." if Windows.FAILED(result = @vtbl[name].call(self, *args)); result
84
+ }
85
+ }
86
+ }
87
+ end
88
+ end
89
+
90
+ module Factory
91
+ def self.[](iface, clsid)
92
+ Class.new(iface) { |klass|
93
+ klass.const_set(:CLSID, clsid)
94
+
95
+ def initialize(opts = {})
96
+ @opts = opts
97
+
98
+ @opts[:clsctx] ||= CLSCTX_INPROC_SERVER
99
+
100
+ FFI::MemoryPointer.new(:pointer) { |ppv|
101
+ raise "CoCreateInstance failed (#{self.class})." if
102
+ Windows.FAILED(Windows.CoCreateInstance(self.class::CLSID, nil, @opts[:clsctx], self.class::IID, ppv))
103
+
104
+ self.pointer = ppv.read_pointer
105
+ }
106
+
107
+ @vtbl = self.class::VTBL.new(self[:lpVtbl])
108
+ end
109
+
110
+ attr_reader :vtbl
111
+
112
+ VTBL.members.each { |name|
113
+ define_method(name) { |*args|
114
+ raise "#{self}.#{name} failed." if Windows.FAILED(result = @vtbl[name].call(self, *args)); result
115
+ }
116
+ }
117
+ }
118
+ end
119
+ end
120
+
121
+ module Callback
122
+ def self.[](iface)
123
+ Class.new(iface) { |klass|
124
+ def initialize(opts = {})
125
+ @vtbl, @refc = self.class::VTBL.new, 1
126
+
127
+ @vtbl.members.each { |name|
128
+ @vtbl[name] = instance_variable_set("@fn#{name}",
129
+ FFI::Function.new(*@vtbl.class::SPEC[name].reverse, convention: :stdcall) { |*args|
130
+ send(name, *args[1..-1])
131
+ }
132
+ )
133
+ }
134
+
135
+ self[:lpVtbl] = @vtbl
136
+
137
+ begin
138
+ yield self
139
+ ensure
140
+ Release()
141
+ end if block_given?
142
+ end
143
+
144
+ attr_reader :vtbl, :refc
145
+
146
+ def QueryInterface(riid, ppv)
147
+ if [IID_IUnknown, self.class::IID].any? { |iid| Windows.memcmp(riid, iid, iid.size) == 0 }
148
+ ppv.write_pointer(self)
149
+ else
150
+ ppv.write_pointer(0); return E_NOINTERFACE
151
+ end
152
+
153
+ AddRef(); S_OK
154
+ end
155
+
156
+ def AddRef
157
+ @refc += 1
158
+ end
159
+
160
+ def Release
161
+ @refc -= 1
162
+ end
163
+
164
+ (VTBL.members - IUnknown::VTBL.members).each { |name|
165
+ define_method(name) { |*args|
166
+ E_NOTIMPL
167
+ }
168
+ }
169
+ }
170
+ end
171
+ end
172
+ end
173
+
174
+ IID_IUnknown = GUID['00000000-0000-0000-C000-000000000046']
175
+
176
+ IUnknown = COM::Interface[
177
+ IID_IUnknown,
178
+
179
+ QueryInterface: [[:pointer, :pointer], :long],
180
+ AddRef: [[], :ulong],
181
+ Release: [[], :ulong]
182
+ ]
183
+
184
+ Unknown = COM::Instance[IUnknown]
185
+ end
186
+ end
@@ -1,59 +1 @@
1
- require_relative 'common'
2
-
3
- module Fzeet
4
- module Windows
5
- ffi_lib 'comctl32'
6
- ffi_convention :stdcall
7
-
8
- ICC_LISTVIEW_CLASSES = 0x00000001
9
- ICC_TREEVIEW_CLASSES = 0x00000002
10
- ICC_BAR_CLASSES = 0x00000004
11
- ICC_TAB_CLASSES = 0x00000008
12
- ICC_UPDOWN_CLASS = 0x00000010
13
- ICC_PROGRESS_CLASS = 0x00000020
14
- ICC_HOTKEY_CLASS = 0x00000040
15
- ICC_ANIMATE_CLASS = 0x00000080
16
- ICC_WIN95_CLASSES = 0x000000FF
17
- ICC_DATE_CLASSES = 0x00000100
18
- ICC_USEREX_CLASSES = 0x00000200
19
- ICC_COOL_CLASSES = 0x00000400
20
- ICC_INTERNET_CLASSES = 0x00000800
21
- ICC_PAGESCROLLER_CLASS = 0x00001000
22
- ICC_NATIVEFNTCTL_CLASS = 0x00002000
23
- ICC_STANDARD_CLASSES = 0x00004000
24
- ICC_LINK_CLASS = 0x00008000
25
-
26
- class INITCOMMONCONTROLSEX < FFI::Struct
27
- layout \
28
- :dwSize, :ulong,
29
- :dwICC, :ulong
30
- end
31
-
32
- attach_function :InitCommonControlsEx, [:pointer], :int
33
-
34
- BS_SPLITBUTTON = 0x0000000C
35
- BS_DEFSPLITBUTTON = 0x0000000D
36
- BS_COMMANDLINK = 0x0000000E
37
- BS_DEFCOMMANDLINK = 0x0000000F
38
-
39
- BCM_FIRST = 0x1600
40
- BCM_GETIDEALSIZE = BCM_FIRST + 0x0001
41
- BCM_SETIMAGELIST = BCM_FIRST + 0x0002
42
- BCM_GETIMAGELIST = BCM_FIRST + 0x0003
43
- BCM_SETTEXTMARGIN = BCM_FIRST + 0x0004
44
- BCM_GETTEXTMARGIN = BCM_FIRST + 0x0005
45
- BCM_SETDROPDOWNSTATE = BCM_FIRST + 0x0006
46
- BCM_SETSPLITINFO = BCM_FIRST + 0x0007
47
- BCM_GETSPLITINFO = BCM_FIRST + 0x0008
48
- BCM_SETNOTE = BCM_FIRST + 0x0009
49
- BCM_GETNOTE = BCM_FIRST + 0x000A
50
- BCM_GETNOTELENGTH = BCM_FIRST + 0x000B
51
- BCM_SETSHIELD = BCM_FIRST + 0x000C
52
-
53
- BCN_FIRST = 0x1_0000_0000 - 1250
54
- BCN_LAST = 0x1_0000_0000 - 1350
55
- BCN_HOTITEMCHANGE = BCN_FIRST + 0x0001
56
- BCN_DROPDOWN = BCN_FIRST + 0x0002
57
- NM_GETCUSTOMSPLITRECT = BCN_FIRST + 0x0003
58
- end
59
- end
1
+ require_relative 'comctlbutton'
@@ -0,0 +1,30 @@
1
+ require_relative 'comctlcommon'
2
+
3
+ module Fzeet
4
+ module Windows
5
+ BS_SPLITBUTTON = 0x0000000C
6
+ BS_DEFSPLITBUTTON = 0x0000000D
7
+ BS_COMMANDLINK = 0x0000000E
8
+ BS_DEFCOMMANDLINK = 0x0000000F
9
+
10
+ BCM_FIRST = 0x1600
11
+ BCM_GETIDEALSIZE = BCM_FIRST + 0x0001
12
+ BCM_SETIMAGELIST = BCM_FIRST + 0x0002
13
+ BCM_GETIMAGELIST = BCM_FIRST + 0x0003
14
+ BCM_SETTEXTMARGIN = BCM_FIRST + 0x0004
15
+ BCM_GETTEXTMARGIN = BCM_FIRST + 0x0005
16
+ BCM_SETDROPDOWNSTATE = BCM_FIRST + 0x0006
17
+ BCM_SETSPLITINFO = BCM_FIRST + 0x0007
18
+ BCM_GETSPLITINFO = BCM_FIRST + 0x0008
19
+ BCM_SETNOTE = BCM_FIRST + 0x0009
20
+ BCM_GETNOTE = BCM_FIRST + 0x000A
21
+ BCM_GETNOTELENGTH = BCM_FIRST + 0x000B
22
+ BCM_SETSHIELD = BCM_FIRST + 0x000C
23
+
24
+ BCN_FIRST = 0x1_0000_0000 - 1250
25
+ BCN_LAST = 0x1_0000_0000 - 1350
26
+ BCN_HOTITEMCHANGE = BCN_FIRST + 0x0001
27
+ BCN_DROPDOWN = BCN_FIRST + 0x0002
28
+ NM_GETCUSTOMSPLITRECT = BCN_FIRST + 0x0003
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ require_relative 'common'
2
+
3
+ module Fzeet
4
+ module Windows
5
+ ffi_lib 'comctl32'
6
+ ffi_convention :stdcall
7
+
8
+ ICC_LISTVIEW_CLASSES = 0x00000001
9
+ ICC_TREEVIEW_CLASSES = 0x00000002
10
+ ICC_BAR_CLASSES = 0x00000004
11
+ ICC_TAB_CLASSES = 0x00000008
12
+ ICC_UPDOWN_CLASS = 0x00000010
13
+ ICC_PROGRESS_CLASS = 0x00000020
14
+ ICC_HOTKEY_CLASS = 0x00000040
15
+ ICC_ANIMATE_CLASS = 0x00000080
16
+ ICC_WIN95_CLASSES = 0x000000FF
17
+ ICC_DATE_CLASSES = 0x00000100
18
+ ICC_USEREX_CLASSES = 0x00000200
19
+ ICC_COOL_CLASSES = 0x00000400
20
+ ICC_INTERNET_CLASSES = 0x00000800
21
+ ICC_PAGESCROLLER_CLASS = 0x00001000
22
+ ICC_NATIVEFNTCTL_CLASS = 0x00002000
23
+ ICC_STANDARD_CLASSES = 0x00004000
24
+ ICC_LINK_CLASS = 0x00008000
25
+
26
+ class INITCOMMONCONTROLSEX < FFI::Struct
27
+ layout \
28
+ :dwSize, :ulong,
29
+ :dwICC, :ulong
30
+ end
31
+
32
+ attach_function :InitCommonControlsEx, [:pointer], :int
33
+ end
34
+ end
@@ -0,0 +1 @@
1
+ require_relative 'comdlgofn'
@@ -0,0 +1,9 @@
1
+ require_relative 'common'
2
+
3
+ module Fzeet
4
+ module Windows
5
+ ffi_lib 'comdlg32'
6
+ ffi_convention :stdcall
7
+
8
+ end
9
+ end