fzeet 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/examples/Dialog/Dialog.rbw +2 -2
  2. data/examples/Raw/UIRibbon/Command.dll +0 -0
  3. data/examples/Raw/UIRibbon/Command.rb +17 -11
  4. data/examples/Raw/UIRibbon/Command.xml +6 -0
  5. data/examples/Raw/UIRibbon/Minimal.dll +0 -0
  6. data/examples/Raw/UIRibbon/Minimal.rb +10 -6
  7. data/examples/Raw/UIRibbon/Minimal.xml +4 -0
  8. data/examples/UIRibbon/Color.rbw +12 -0
  9. data/examples/UIRibbon/Command.dll +0 -0
  10. data/examples/UIRibbon/Command.rb +17 -11
  11. data/examples/UIRibbon/Command.xml +6 -0
  12. data/examples/UIRibbon/ContextPopup.dll +0 -0
  13. data/examples/UIRibbon/ContextPopup.rb +23 -0
  14. data/examples/UIRibbon/ContextPopup.rbw +12 -0
  15. data/examples/UIRibbon/ContextPopup.xml +83 -0
  16. data/examples/UIRibbon/Minimal.dll +0 -0
  17. data/examples/UIRibbon/Minimal.rb +10 -6
  18. data/examples/UIRibbon/Minimal.xml +4 -0
  19. data/examples/Version.rbw +5 -0
  20. data/examples/res/go-next-big.bmp +0 -0
  21. data/examples/res/go-previous-big.bmp +0 -0
  22. data/lib/fzeet/Accelerator.rb +23 -3
  23. data/lib/fzeet/Application.rb +1 -1
  24. data/lib/fzeet/{common.rb → Common.rb} +2 -50
  25. data/lib/fzeet/{ControlButton.rb → Control/Button.rb} +1 -1
  26. data/lib/fzeet/{ControlCommon.rb → Control/Common.rb} +1 -1
  27. data/lib/fzeet/Control.rb +1 -1
  28. data/lib/fzeet/Dialog/Common.rb +5 -0
  29. data/lib/fzeet/{DialogFileDialog.rb → Dialog/FileDialog.rb} +1 -43
  30. data/lib/fzeet/Dialog/FolderDialog.rb +45 -0
  31. data/lib/fzeet/Dialog.rb +2 -1
  32. data/lib/fzeet/Menu.rb +77 -77
  33. data/lib/fzeet/UIRibbon.rb +86 -1
  34. data/lib/fzeet/{WindowCommon.rb → Window/Common.rb} +52 -2
  35. data/lib/fzeet/{WindowDialog.rb → Window/Dialog.rb} +6 -6
  36. data/lib/fzeet/{WindowWindow.rb → Window/Window.rb} +1 -1
  37. data/lib/fzeet/{WindowMethods.rb → Window/WindowMethods.rb} +49 -43
  38. data/lib/fzeet/Window.rb +2 -2
  39. data/lib/fzeet/windows/com.rb +97 -15
  40. data/lib/fzeet/windows/{comctlbutton.rb → comctl/Button.rb} +1 -1
  41. data/lib/fzeet/windows/{comctlcommon.rb → comctl/Common.rb} +1 -1
  42. data/lib/fzeet/windows/comctl.rb +1 -1
  43. data/lib/fzeet/windows/{comdlgcommon.rb → comdlg/Common.rb} +1 -1
  44. data/lib/fzeet/windows/{comdlgofn.rb → comdlg/FileDialog.rb} +1 -1
  45. data/lib/fzeet/windows/comdlg.rb +1 -1
  46. data/lib/fzeet/windows/common.rb +80 -5
  47. data/lib/fzeet/windows/gdi.rb +30 -0
  48. data/lib/fzeet/windows/kernel.rb +74 -21
  49. data/lib/fzeet/windows/ole.rb +60 -0
  50. data/lib/fzeet/windows/propsys.rb +40 -0
  51. data/lib/fzeet/windows/shell/Common.rb +10 -0
  52. data/lib/fzeet/windows/shell/FolderDialog.rb +39 -0
  53. data/lib/fzeet/windows/shell.rb +1 -43
  54. data/lib/fzeet/windows/uiribbon.rb +275 -18
  55. data/lib/fzeet/windows/user/Accelerator.rb +182 -0
  56. data/lib/fzeet/windows/user/Common.rb +33 -0
  57. data/lib/fzeet/windows/{userctlbutton.rb → user/Control/Button.rb} +1 -1
  58. data/lib/fzeet/windows/{userctlcommon.rb → user/Control/Common.rb} +1 -1
  59. data/lib/fzeet/windows/user/Control.rb +1 -0
  60. data/lib/fzeet/windows/user/Menu.rb +115 -0
  61. data/lib/fzeet/windows/{usermsg.rb → user/Message.rb} +1 -3
  62. data/lib/fzeet/windows/{usermbox.rb → user/MessageBox.rb} +1 -5
  63. data/lib/fzeet/windows/user/SystemParametersInfo.rb +244 -0
  64. data/lib/fzeet/windows/{userwnd.rb → user/Window.rb} +70 -38
  65. data/lib/fzeet/windows/user.rb +7 -7
  66. data/lib/fzeet/windows.rb +2 -73
  67. data/lib/fzeet.rb +1 -1
  68. metadata +39 -27
  69. data/lib/fzeet/DialogCommon.rb +0 -5
  70. data/lib/fzeet/windows/usercommon.rb +0 -8
  71. data/lib/fzeet/windows/userctl.rb +0 -1
  72. data/lib/fzeet/windows/userkbd.rb +0 -20
  73. data/lib/fzeet/windows/usermenu.rb +0 -50
  74. data/lib/fzeet/windows/userspi.rb +0 -29
  75. /data/examples/Dialog/{FileDialog.rbw → FileAndFolderDialog.rbw} +0 -0
data/lib/fzeet/Menu.rb CHANGED
@@ -1,86 +1,86 @@
1
- require_relative 'common'
1
+ require_relative 'Common'
2
2
 
3
3
  module Fzeet
4
- class MenuItem
5
- include Toggle
6
-
7
- def initialize(menu, id) @menu, @id = menu, Command[id] end
8
-
9
- attr_reader :menu, :id
10
-
11
- def enabled?
12
- flags = Windows.DetonateLastError(-1, :GetMenuState, @menu.handle, @id, 0)
13
-
14
- (flags & Windows::MF_GRAYED) != Windows::MF_GRAYED
15
- end
16
-
17
- def enabled=(enabled)
18
- Windows.DetonateLastError(-1, :EnableMenuItem,
19
- @menu.handle,
20
- @id,
21
- (enabled) ? Windows::MF_ENABLED : Windows::MF_GRAYED
22
- )
23
- end
24
-
25
- def checked?
26
- flags = Windows.DetonateLastError(-1, :GetMenuState, @menu.handle, @id, 0)
27
-
28
- (flags & Windows::MF_CHECKED) == Windows::MF_CHECKED
29
- end
30
-
31
- def checked=(checked)
32
- Windows.DetonateLastError(-1, :CheckMenuItem,
33
- @menu.handle,
34
- @id,
35
- (checked) ? Windows::MF_CHECKED : Windows::MF_UNCHECKED
36
- )
37
- end
38
-
39
- def select(first, last)
40
- Windows.DetonateLastError(0, :CheckMenuRadioItem,
41
- @menu.handle, Command[first], Command[last], @id, 0
42
- )
43
-
44
- self
45
- end
4
+ module MenuMethods
5
+ def rdetach; submenus.each(&:rdetach); detach end
46
6
 
47
- def info(mask)
48
- Windows.DetonateLastError(0, :GetMenuItemInfo,
49
- @menu.handle,
50
- @id,
51
- 0,
52
- info = Windows::MENUITEMINFO.new.tap { |mii|
53
- mii[:cbSize] = mii.size
54
- mii[:fMask] = Fzeet.constant(mask, :miim_)
7
+ class Item
8
+ include Toggle
9
+
10
+ def initialize(menu, id) @menu, @id = menu, Command[id] end
11
+
12
+ attr_reader :menu, :id
13
+
14
+ def enabled?
15
+ flags = Windows.DetonateLastError(-1, :GetMenuState, @menu.handle, @id, 0)
16
+
17
+ (flags & Windows::MF_GRAYED) != Windows::MF_GRAYED
18
+ end
19
+
20
+ def enabled=(enabled)
21
+ Windows.DetonateLastError(-1, :EnableMenuItem,
22
+ @menu.handle,
23
+ @id,
24
+ (enabled) ? Windows::MF_ENABLED : Windows::MF_GRAYED
25
+ )
26
+ end
27
+
28
+ def checked?
29
+ flags = Windows.DetonateLastError(-1, :GetMenuState, @menu.handle, @id, 0)
30
+
31
+ (flags & Windows::MF_CHECKED) == Windows::MF_CHECKED
32
+ end
33
+
34
+ def checked=(checked)
35
+ Windows.DetonateLastError(-1, :CheckMenuItem,
36
+ @menu.handle,
37
+ @id,
38
+ (checked) ? Windows::MF_CHECKED : Windows::MF_UNCHECKED
39
+ )
40
+ end
41
+
42
+ def select(first, last)
43
+ Windows.DetonateLastError(0, :CheckMenuRadioItem,
44
+ @menu.handle, Command[first], Command[last], @id, 0
45
+ )
46
+
47
+ self
48
+ end
49
+
50
+ def info(mask)
51
+ Windows.DetonateLastError(0, :GetMenuItemInfo,
52
+ @menu.handle,
53
+ @id,
54
+ 0,
55
+ info = Windows::MENUITEMINFO.new.tap { |mii|
56
+ mii[:cbSize] = mii.size
57
+ mii[:fMask] = Fzeet.constant(mask, :miim_)
58
+ }
59
+ )
60
+
61
+ info
62
+ end
63
+
64
+ def info=(mii)
65
+ Windows.DetonateLastError(0, :SetMenuItemInfo,
66
+ @menu.handle,
67
+ @id,
68
+ 0,
69
+ mii.tap { mii[:cbSize] = mii.size }
70
+ )
71
+ end
72
+
73
+ def image; (Handle.instance?(handle = info(:bitmap)[:hbmpItem])) ? Handle.instance(handle) : nil end
74
+
75
+ def image=(image)
76
+ self.info = Windows::MENUITEMINFO.new.tap { |mii|
77
+ mii[:fMask] = Windows::MIIM_BITMAP
78
+ mii[:hbmpItem] = image.handle
55
79
  }
56
- )
57
-
58
- info
59
- end
60
-
61
- def info=(mii)
62
- Windows.DetonateLastError(0, :SetMenuItemInfo,
63
- @menu.handle,
64
- @id,
65
- 0,
66
- mii.tap { mii[:cbSize] = mii.size }
67
- )
68
- end
69
-
70
- def image; (Handle.instance?(handle = info(:bitmap)[:hbmpItem])) ? Handle.instance(handle) : nil end
71
-
72
- def image=(image)
73
- self.info = Windows::MENUITEMINFO.new.tap { |mii|
74
- mii[:fMask] = Windows::MIIM_BITMAP
75
- mii[:hbmpItem] = image.handle
76
- }
80
+ end
77
81
  end
78
- end
79
-
80
- module MenuMethods
81
- def rdetach; submenus.each(&:rdetach); detach end
82
82
 
83
- def [](id) MenuItem.new(self, id) end
83
+ def [](id) Item.new(self, id) end
84
84
 
85
85
  def append(flags, item = nil, id = 0)
86
86
  Windows.DetonateLastError(0, :AppendMenu,
@@ -1,6 +1,14 @@
1
- require_relative 'WindowCommon'
1
+ require_relative 'Common'
2
2
 
3
3
  module Fzeet
4
+ class Windows::PropertyStore
5
+ def uiprop(*args)
6
+ args[0] = Windows.const_get("UI_PKEY_#{args[0]}")
7
+
8
+ prop(*args)
9
+ end
10
+ end
11
+
4
12
  class UIRibbon
5
13
  class Command
6
14
  include Toggle
@@ -20,6 +28,77 @@ module Fzeet
20
28
 
21
29
  def [](id) Command.new(self, id) end
22
30
 
31
+ module Color
32
+ def self.enhance(hsb, ribbon, method)
33
+ hsb.instance_variable_set(:@ribbon, ribbon)
34
+ hsb.instance_variable_set(:@method, method)
35
+
36
+ class << hsb
37
+ attr_reader :ribbon, :method
38
+
39
+ include Color
40
+ end
41
+
42
+ hsb
43
+ end
44
+
45
+ def darken(amount) self[2] -= amount; ribbon.send("#{method}=", self); self end
46
+ def lighten(amount) self[2] += amount; ribbon.send("#{method}=", self); self end
47
+
48
+ def saturate(amount) self[1] += amount; ribbon.send("#{method}=", self); self end
49
+ def bleach(amount) self[1] -= amount; ribbon.send("#{method}=", self); self end
50
+
51
+ def shift(amount) self[0] += amount; ribbon.send("#{method}=", self); self end
52
+ end
53
+
54
+ def background
55
+ hsb = nil
56
+
57
+ uif.QueryInstance(Windows::PropertyStore) { |ps|
58
+ hsb = ps.uiprop(:GlobalBackgroundColor).uint
59
+ }
60
+
61
+ Color.enhance([Windows::UI_GetHValue(hsb), Windows::UI_GetSValue(hsb), Windows::UI_GetBValue(hsb)], self, __method__)
62
+ end
63
+
64
+ def background=(hsb)
65
+ uif.QueryInstance(Windows::PropertyStore) { |ps|
66
+ ps.uiprop(:GlobalBackgroundColor, Windows::PROPVARIANT[:uint, Windows::UI_HSB(*hsb)]).commit
67
+ }
68
+ end
69
+
70
+ def color
71
+ hsb = nil
72
+
73
+ uif.QueryInstance(Windows::PropertyStore) { |ps|
74
+ hsb = ps.uiprop(:GlobalTextColor).uint
75
+ }
76
+
77
+ Color.enhance([Windows::UI_GetHValue(hsb), Windows::UI_GetSValue(hsb), Windows::UI_GetBValue(hsb)], self, __method__)
78
+ end
79
+
80
+ def color=(hsb)
81
+ uif.QueryInstance(Windows::PropertyStore) { |ps|
82
+ ps.uiprop(:GlobalTextColor, Windows::PROPVARIANT[:uint, Windows::UI_HSB(*hsb)]).commit
83
+ }
84
+ end
85
+
86
+ def highlight
87
+ hsb = nil
88
+
89
+ uif.QueryInstance(Windows::PropertyStore) { |ps|
90
+ hsb = ps.uiprop(:GlobalHighlightColor).uint
91
+ }
92
+
93
+ Color.enhance([Windows::UI_GetHValue(hsb), Windows::UI_GetSValue(hsb), Windows::UI_GetBValue(hsb)], self, __method__)
94
+ end
95
+
96
+ def highlight=(hsb)
97
+ uif.QueryInstance(Windows::PropertyStore) { |ps|
98
+ ps.uiprop(:GlobalHighlightColor, Windows::PROPVARIANT[:uint, Windows::UI_HSB(*hsb)]).commit
99
+ }
100
+ end
101
+
23
102
  def initialize(window, name = Application.name, resname = 'APPLICATION_RIBBON')
24
103
  @executesAllVerbs = {}
25
104
 
@@ -101,5 +180,11 @@ module Fzeet
101
180
 
102
181
  self
103
182
  end
183
+
184
+ def contextualUI(id, x, y)
185
+ uif.UseInstance(Windows::UIContextualUI, :GetView, id) { |view|
186
+ view.ShowAtLocation(x, y)
187
+ }
188
+ end
104
189
  end
105
190
  end
@@ -1,6 +1,56 @@
1
1
  require_relative 'WindowMethods'
2
2
 
3
3
  module Fzeet
4
+ class WindowClass < Windows::WNDCLASSEX
5
+ def initialize(prototype, name, opts = {})
6
+ @prototype = prototype
7
+ @name = name
8
+ className = FFI::MemoryPointer.from_string(@name)
9
+
10
+ _opts = {
11
+ style: [],
12
+ wndProc: BasicWindow::WindowProc,
13
+ clsExtra: 0,
14
+ wndExtra: 0,
15
+ icon: SystemIcon.new(:application),
16
+ cursor: SystemCursor.new(:arrow),
17
+ background: SystemBrush.new(:window),
18
+ iconSm: nil
19
+ }
20
+ badopts = opts.keys - _opts.keys; raise "Bad option(s): #{badopts.join(', ')}." unless badopts.empty?
21
+
22
+ self[:cbSize] = Windows::WNDCLASSEX.size
23
+ self[:hInstance] = Windows.GetModuleHandle(nil)
24
+ self[:lpszClassName] = className
25
+
26
+ if @prototype
27
+ self[:style] = Fzeet.flags(opts[:style] || [], :cs_) | @prototype[:style]
28
+ self[:lpfnWndProc] = opts[:wndProc] || @prototype[:lpfnWndProc]
29
+ self[:cbClsExtra] = (opts[:clsExtra] || 0) + @prototype[:cbClsExtra]
30
+ self[:cbWndExtra] = (opts[:wndExtra] || 0) + @prototype[:cbWndExtra]
31
+ self[:hIcon] = (opts[:icon] && opts[:icon].handle) || @prototype[:hIcon]
32
+ self[:hCursor] = (opts[:cursor] && opts[:cursor].handle) || @prototype[:hCursor]
33
+ self[:hbrBackground] = (opts[:background] && opts[:background].handle) || @prototype[:hbrBackground]
34
+ self[:hIconSm] = (opts[:iconSm] && _opts[:iconSm].handle) || @prototype[:hIconSm]
35
+ else
36
+ _opts.merge(opts)
37
+
38
+ self[:style] = Fzeet.flags(_opts[:style], :cs_)
39
+ self[:lpfnWndProc] = _opts[:wndProc]
40
+ self[:cbClsExtra] = _opts[:clsExtra]
41
+ self[:cbWndExtra] = _opts[:wndExtra]
42
+ self[:hIcon] = _opts[:icon].handle
43
+ self[:hCursor] = _opts[:cursor].handle
44
+ self[:hbrBackground] = _opts[:background].handle
45
+ self[:hIconSm] = _opts[:iconSm] && _opts[:iconSm].handle
46
+ end
47
+
48
+ Windows.DetonateLastError(0, :RegisterClassEx, self) { className.free }
49
+ end
50
+
51
+ attr_reader :prototype, :name
52
+ end
53
+
4
54
  class BasicWindow < Handle
5
55
  include WindowMethods
6
56
 
@@ -64,8 +114,8 @@ module Fzeet
64
114
  WindowClass = Fzeet::WindowClass.new(nil, 'Fzeet.BasicWindow')
65
115
 
66
116
  def self.[](name, opts = {})
67
- Class.new(self) { |klass|
68
- klass.const_set(:WindowClass, Fzeet::WindowClass.new(self::WindowClass, name, opts))
117
+ Class.new(self) {
118
+ const_set(:WindowClass, Fzeet::WindowClass.new(self::WindowClass, name, opts))
69
119
  }
70
120
  end
71
121
 
@@ -1,4 +1,4 @@
1
- require_relative 'WindowCommon'
1
+ require_relative 'Common'
2
2
 
3
3
  module Fzeet
4
4
  Dialog = BasicWindow['Fzeet.Dialog',
@@ -45,24 +45,24 @@ module Fzeet
45
45
 
46
46
  on(:initdialog, &block) if block
47
47
 
48
- if _opts[:modal]
49
- @result = Windows.DetonateLastError([-1, 0], :DialogBoxIndirectParam,
48
+ unless _opts[:modal]
49
+ @handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateDialogIndirectParam,
50
50
  Windows.GetModuleHandle(nil),
51
51
  dt,
52
52
  @parent && @parent.handle,
53
53
  BasicWindow::DialogProc,
54
54
  object_id
55
55
  )
56
+
57
+ self.dialog = true
56
58
  else
57
- @handle = Windows.DetonateLastError(FFI::Pointer::NULL, :CreateDialogIndirectParam,
59
+ @result = Windows.DetonateLastError([-1, 0], :DialogBoxIndirectParam,
58
60
  Windows.GetModuleHandle(nil),
59
61
  dt,
60
62
  @parent && @parent.handle,
61
63
  BasicWindow::DialogProc,
62
64
  object_id
63
65
  )
64
-
65
- self.dialog = true
66
66
  end
67
67
  end
68
68
 
@@ -1,4 +1,4 @@
1
- require_relative 'WindowCommon'
1
+ require_relative 'Common'
2
2
 
3
3
  module Fzeet
4
4
  Window = BasicWindow['Fzeet.Window']
@@ -1,9 +1,44 @@
1
- require_relative 'common'
1
+ require_relative '../Common'
2
2
 
3
3
  module Fzeet
4
4
  module WindowMethods
5
5
  include Toggle
6
6
 
7
+ def message(message, opts = {window: self}) Fzeet.message(message, opts) end
8
+ def question(message, opts = {window: self}) Fzeet.question(message, opts) end
9
+
10
+ def sendmsg(msg, wParam = 0, lParam = 0)
11
+ Windows.SendMessage(
12
+ @handle,
13
+ Fzeet.constant(msg, *self.class::Prefix[:message]),
14
+ wParam.to_i,
15
+ ((lparam = lParam.to_i) > 0x7fff_ffff) ? lparam - 0x1_0000_0000 : lparam
16
+ )
17
+ end
18
+
19
+ def postmsg(msg, wParam = 0, lParam = 0)
20
+ Windows.DetonateLastError(0, :PostMessage,
21
+ @handle,
22
+ Fzeet.constant(msg, *self.class::Prefix[:message]),
23
+ wParam.to_i,
24
+ ((lparam = lParam.to_i) > 0x7fff_ffff) ? lparam - 0x1_0000_0000 : lparam
25
+ )
26
+
27
+ self
28
+ end
29
+
30
+ def dialog?; Application.dialogs.include?(self) end
31
+
32
+ def dialog=(dialog)
33
+ if dialog
34
+ Application.dialogs << self unless dialog?
35
+ else
36
+ Application.dialogs.delete(self)
37
+ end
38
+ end
39
+
40
+ def dlgmsg?(msg) Windows.IsDialogMessage(@handle, msg) != 0 end
41
+
7
42
  class Long
8
43
  def initialize(window) @window = window end
9
44
 
@@ -61,7 +96,14 @@ module Fzeet
61
96
  )
62
97
  end
63
98
 
99
+ def enabled?; Windows.IsWindowEnabled(@handle) != 0 end
100
+ def enabled=(enabled) Windows.EnableWindow(@handle, (enabled) ? 1 : 0) end
101
+
102
+ def visible?; Windows.IsWindowVisible(@handle) != 0 end
103
+ def visible=(visible) show((visible) ? Windows::SW_SHOWNORMAL : Windows::SW_HIDE) end
104
+
64
105
  def show(cmdShow = :shownormal) Windows.ShowWindow(@handle, Fzeet.constant(cmdShow, :sw_)); self end
106
+
65
107
  def update; Windows.DetonateLastError(0, :UpdateWindow, @handle); self end
66
108
 
67
109
  def textlen; Windows.GetWindowTextLength(@handle) end
@@ -80,9 +122,6 @@ module Fzeet
80
122
 
81
123
  def text=(text) Windows.DetonateLastError(0, :SetWindowText, @handle, text) end
82
124
 
83
- def enabled?; Windows.IsWindowEnabled(@handle) != 0 end
84
- def enabled=(enabled) Windows.EnableWindow(@handle, (enabled) ? 1 : 0) end
85
-
86
125
  def rect; Windows.DetonateLastError(0, :GetClientRect, @handle, r = Rect.new); r end
87
126
 
88
127
  def position; Windows.DetonateLastError(0, :GetWindowRect, @handle, r = Rect.new); r end
@@ -108,14 +147,6 @@ module Fzeet
108
147
  def capture?; Windows.GetCapture().to_i == @handle.to_i end
109
148
  def capture=(capture) (capture) ? Windows.SetCapture(@handle) : Windows.DetonateLastError(0, :ReleaseCapture) end
110
149
 
111
- def [](id) Handle.instance(Windows.DetonateLastError(FFI::Pointer::NULL, :GetDlgItem, @handle, Command[id])) end
112
-
113
- EnumChildProc = FFI::Function.new(:int, [:pointer, :long], convention: :stdcall) { |hwnd, lParam|
114
- ObjectSpace._id2ref(lParam).call(Handle.instance(hwnd)) if Handle.instance?(hwnd); 1
115
- }
116
-
117
- def eachChild(&block) Windows.EnumChildWindows(@handle, EnumChildProc, block.object_id); self end
118
-
119
150
  def menu; (Handle.instance?(handle = Windows.GetMenu(@handle))) ? Handle.instance(handle) : nil end
120
151
 
121
152
  def menu=(menu)
@@ -124,39 +155,14 @@ module Fzeet
124
155
  Windows.DetonateLastError(0, :SetMenu, @handle, menu.handle) if menu
125
156
  end
126
157
 
127
- def sendmsg(msg, wParam = 0, lParam = 0)
128
- Windows.SendMessage(
129
- @handle,
130
- Fzeet.constant(msg, *self.class::Prefix[:message]),
131
- wParam.to_i,
132
- ((lparam = lParam.to_i) > 0x7fff_ffff) ? lparam - 0x1_0000_0000 : lparam
133
- )
134
- end
158
+ def drawMenuBar; Windows.DetonateLastError(0, :DrawMenuBar, @handle); self end
135
159
 
136
- def postmsg(msg, wParam = 0, lParam = 0)
137
- Windows.DetonateLastError(0, :PostMessage,
138
- @handle,
139
- Fzeet.constant(msg, *self.class::Prefix[:message]),
140
- wParam.to_i,
141
- ((lparam = lParam.to_i) > 0x7fff_ffff) ? lparam - 0x1_0000_0000 : lparam
142
- )
143
-
144
- self
145
- end
146
-
147
- def dlgmsg?(msg) Windows.IsDialogMessage(@handle, msg) != 0 end
148
-
149
- def dialog?; Application.dialogs.include?(self) end
160
+ def [](id) Handle.instance(Windows.DetonateLastError(FFI::Pointer::NULL, :GetDlgItem, @handle, Command[id])) end
150
161
 
151
- def dialog=(dialog)
152
- if dialog
153
- Application.dialogs << self unless dialog?
154
- else
155
- Application.dialogs.delete(self)
156
- end
157
- end
162
+ EnumChildProc = FFI::Function.new(:int, [:pointer, :long], convention: :stdcall) { |hwnd, lParam|
163
+ ObjectSpace._id2ref(lParam).call(Handle.instance(hwnd)) if Handle.instance?(hwnd); 1
164
+ }
158
165
 
159
- def message(message, opts = {window: self}) Fzeet.message(message, opts) end
160
- def question(message, opts = {window: self}) Fzeet.question(message, opts) end
166
+ def eachChild(&block) Windows.EnumChildWindows(@handle, EnumChildProc, block.object_id); self end
161
167
  end
162
168
  end
data/lib/fzeet/Window.rb CHANGED
@@ -1,2 +1,2 @@
1
- require_relative 'WindowWindow'
2
- require_relative 'WindowDialog'
1
+ require_relative 'Window/Window'
2
+ require_relative 'Window/Dialog'
@@ -6,9 +6,19 @@ module Fzeet
6
6
  ffi_convention :stdcall
7
7
 
8
8
  S_OK = 0
9
+ S_FALSE = 1
9
10
 
11
+ E_UNEXPECTED = 0x8000FFFF - 0x1_0000_0000
10
12
  E_NOTIMPL = 0x80004001 - 0x1_0000_0000
13
+ E_OUTOFMEMORY = 0x8007000E - 0x1_0000_0000
14
+ E_INVALIDARG = 0x80070057 - 0x1_0000_0000
11
15
  E_NOINTERFACE = 0x80004002 - 0x1_0000_0000
16
+ E_POINTER = 0x80004003 - 0x1_0000_0000
17
+ E_HANDLE = 0x80070006 - 0x1_0000_0000
18
+ E_ABORT = 0x80004004 - 0x1_0000_0000
19
+ E_FAIL = 0x80004005 - 0x1_0000_0000
20
+ E_ACCESSDENIED = 0x80070005 - 0x1_0000_0000
21
+ E_PENDING = 0x8000000A - 0x1_0000_0000
12
22
 
13
23
  def SUCCEEDED(hr) hr >= 0 end
14
24
  def FAILED(hr) hr < 0 end
@@ -17,6 +27,16 @@ module Fzeet
17
27
  :SUCCEEDED,
18
28
  :FAILED
19
29
 
30
+ def DetonateHresult(name, *args)
31
+ failed = FAILED(result = send(name, *args)) and raise "#{name} failed (hresult #{format('%#08x', result)})."
32
+
33
+ result
34
+ ensure
35
+ yield failed if block_given?
36
+ end
37
+
38
+ module_function :DetonateHresult
39
+
20
40
  class GUID < FFI::Struct
21
41
  layout \
22
42
  :Data1, :ulong,
@@ -41,6 +61,30 @@ module Fzeet
41
61
  end
42
62
 
43
63
  CLSCTX_INPROC_SERVER = 0x1
64
+ CLSCTX_INPROC_HANDLER = 0x2
65
+ CLSCTX_LOCAL_SERVER = 0x4
66
+ CLSCTX_INPROC_SERVER16 = 0x8
67
+ CLSCTX_REMOTE_SERVER = 0x10
68
+ CLSCTX_INPROC_HANDLER16 = 0x20
69
+ CLSCTX_RESERVED1 = 0x40
70
+ CLSCTX_RESERVED2 = 0x80
71
+ CLSCTX_RESERVED3 = 0x100
72
+ CLSCTX_RESERVED4 = 0x200
73
+ CLSCTX_NO_CODE_DOWNLOAD = 0x400
74
+ CLSCTX_RESERVED5 = 0x800
75
+ CLSCTX_NO_CUSTOM_MARSHAL = 0x1000
76
+ CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000
77
+ CLSCTX_NO_FAILURE_LOG = 0x4000
78
+ CLSCTX_DISABLE_AAA = 0x8000
79
+ CLSCTX_ENABLE_AAA = 0x10000
80
+ CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000
81
+ CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000
82
+ CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000
83
+ CLSCTX_ENABLE_CLOAKING = 0x100000
84
+ CLSCTX_PS_DLL = -0x80000000
85
+ CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER
86
+ CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
87
+ CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
44
88
 
45
89
  attach_function :CoCreateInstance, [:pointer, :pointer, :ulong, :pointer, :pointer], :long
46
90
 
@@ -51,25 +95,61 @@ module Fzeet
51
95
 
52
96
  spec.each { |name, signature| signature[0].unshift(:pointer) }
53
97
 
54
- Class.new(FFI::Struct) { |iface|
55
- iface.const_set(:IID, iid)
98
+ Class.new(FFI::Struct) {
99
+ const_set(:IID, iid)
56
100
 
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)])
101
+ const_set(:VTBL, Class.new(FFI::Struct) {
102
+ const_set(:SPEC, Hash[(ifaces.map { |iface| iface::VTBL::SPEC.to_a } << spec.to_a).flatten(1)])
59
103
 
60
- vtbl.layout \
61
- *vtbl::SPEC.map { |name, signature| [name, callback(*signature)] }.flatten
104
+ layout \
105
+ *self::SPEC.map { |name, signature| [name, callback(*signature)] }.flatten
62
106
  })
63
107
 
64
- iface.layout \
108
+ layout \
65
109
  :lpVtbl, :pointer
66
110
  }
67
111
  end
68
112
  end
69
113
 
114
+ module Helpers
115
+ def QueryInstance(klass)
116
+ instance = nil
117
+
118
+ FFI::MemoryPointer.new(:pointer) { |ppv|
119
+ QueryInterface(klass::IID, ppv)
120
+
121
+ instance = klass.new(ppv.read_pointer)
122
+ }
123
+
124
+ begin
125
+ yield instance; return self
126
+ ensure
127
+ instance.Release
128
+ end if block_given?
129
+
130
+ instance
131
+ end
132
+
133
+ def UseInstance(klass, name, *args)
134
+ instance = nil
135
+
136
+ FFI::MemoryPointer.new(:pointer) { |ppv|
137
+ send(name, *args, klass::IID, ppv)
138
+
139
+ yield instance = klass.new(ppv.read_pointer)
140
+ }
141
+
142
+ self
143
+ ensure
144
+ instance.Release if instance
145
+ end
146
+ end
147
+
70
148
  module Instance
71
149
  def self.[](iface)
72
- Class.new(iface) { |klass|
150
+ Class.new(iface) {
151
+ send(:include, Helpers)
152
+
73
153
  def initialize(pointer)
74
154
  self.pointer = pointer
75
155
 
@@ -89,8 +169,10 @@ module Fzeet
89
169
 
90
170
  module Factory
91
171
  def self.[](iface, clsid)
92
- Class.new(iface) { |klass|
93
- klass.const_set(:CLSID, clsid)
172
+ Class.new(iface) {
173
+ send(:include, Helpers)
174
+
175
+ const_set(:CLSID, clsid)
94
176
 
95
177
  def initialize(opts = {})
96
178
  @opts = opts
@@ -120,7 +202,9 @@ module Fzeet
120
202
 
121
203
  module Callback
122
204
  def self.[](iface)
123
- Class.new(iface) { |klass|
205
+ Class.new(iface) {
206
+ send(:include, Helpers)
207
+
124
208
  def initialize(opts = {})
125
209
  @vtbl, @refc = self.class::VTBL.new, 1
126
210
 
@@ -144,7 +228,7 @@ module Fzeet
144
228
  attr_reader :vtbl, :refc
145
229
 
146
230
  def QueryInterface(riid, ppv)
147
- if [IID_IUnknown, self.class::IID].any? { |iid| Windows.memcmp(riid, iid, iid.size) == 0 }
231
+ if [IUnknown::IID, self.class::IID].any? { |iid| Windows.memcmp(riid, iid, iid.size) == 0 }
148
232
  ppv.write_pointer(self)
149
233
  else
150
234
  ppv.write_pointer(0); return E_NOINTERFACE
@@ -171,10 +255,8 @@ module Fzeet
171
255
  end
172
256
  end
173
257
 
174
- IID_IUnknown = GUID['00000000-0000-0000-C000-000000000046']
175
-
176
258
  IUnknown = COM::Interface[
177
- IID_IUnknown,
259
+ GUID['00000000-0000-0000-C000-000000000046'],
178
260
 
179
261
  QueryInterface: [[:pointer, :pointer], :long],
180
262
  AddRef: [[], :ulong],
@@ -1,4 +1,4 @@
1
- require_relative 'comctlcommon'
1
+ require_relative 'Common'
2
2
 
3
3
  module Fzeet
4
4
  module Windows