fzeet 0.5.2 → 0.5.3

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 (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