windows_gui 2.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +13 -0
- data/RELNOTES.md +9 -0
- data/examples/Command.rbw +261 -0
- data/examples/Hello.rbw +9 -0
- data/examples/HelloOptout.rbw +12 -0
- data/examples/HelloTimeout.rbw +19 -0
- data/examples/Layered.rbw +96 -0
- data/examples/LifeCycle.rbw +123 -0
- data/examples/LifeCycleNC.rbw +153 -0
- data/examples/Menu.rbw +274 -0
- data/examples/MenuContext.rbw +158 -0
- data/examples/MenuPARGB32.rbw +308 -0
- data/examples/MinMax.rbw +98 -0
- data/examples/Minimal.rbw +86 -0
- data/examples/Paint.rbw +151 -0
- data/examples/Region.rbw +99 -0
- data/examples/Scribble.rbw +220 -0
- data/examples/WndExtra.rbw +122 -0
- data/examples/res/face-devilish.bmp +0 -0
- data/lib/windows_gui/common.rb +152 -0
- data/lib/windows_gui/gdi.rb +575 -0
- data/lib/windows_gui/kernel.rb +252 -0
- data/lib/windows_gui/libc.rb +10 -0
- data/lib/windows_gui/user.rb +2573 -0
- data/lib/windows_gui.rb +4 -0
- data/screenshot.png +0 -0
- metadata +85 -0
data/examples/Region.rbw
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'windows_gui'
|
2
|
+
|
3
|
+
include WindowsGUI
|
4
|
+
|
5
|
+
def OnCreate(hwnd,
|
6
|
+
cs
|
7
|
+
)
|
8
|
+
SetWindowRgn(hwnd,
|
9
|
+
CreateEllipticRgn(*DPIAwareXY(42, 42, 420, 210)),
|
10
|
+
0
|
11
|
+
)
|
12
|
+
|
13
|
+
0
|
14
|
+
end
|
15
|
+
|
16
|
+
def OnDestroy(hwnd)
|
17
|
+
PostQuitMessage(0); 0
|
18
|
+
end
|
19
|
+
|
20
|
+
WindowProc = FFI::Function.new(:long,
|
21
|
+
[:pointer, :uint, :uint, :long],
|
22
|
+
convention: :stdcall
|
23
|
+
) { |hwnd, uMsg, wParam, lParam|
|
24
|
+
begin
|
25
|
+
result = case uMsg
|
26
|
+
when WM_CREATE
|
27
|
+
OnCreate(hwnd, CREATESTRUCT.new(FFI::Pointer.new(lParam)))
|
28
|
+
when WM_DESTROY
|
29
|
+
OnDestroy(hwnd)
|
30
|
+
end
|
31
|
+
|
32
|
+
result || DefWindowProc(hwnd, uMsg, wParam, lParam)
|
33
|
+
rescue SystemExit => ex
|
34
|
+
PostQuitMessage(ex.status)
|
35
|
+
rescue
|
36
|
+
case MessageBox(hwnd,
|
37
|
+
L(Util.FormatException($!)),
|
38
|
+
APPNAME,
|
39
|
+
MB_ABORTRETRYIGNORE | MB_ICONERROR
|
40
|
+
)
|
41
|
+
when IDABORT
|
42
|
+
PostQuitMessage(2)
|
43
|
+
when IDRETRY
|
44
|
+
retry
|
45
|
+
end
|
46
|
+
end
|
47
|
+
}
|
48
|
+
|
49
|
+
def WinMain
|
50
|
+
WNDCLASSEX.new { |wc|
|
51
|
+
wc[:cbSize] = wc.size
|
52
|
+
wc[:lpfnWndProc] = WindowProc
|
53
|
+
wc[:hInstance] = GetModuleHandle(nil)
|
54
|
+
wc[:hIcon] = LoadIcon(nil, IDI_APPLICATION)
|
55
|
+
wc[:hCursor] = LoadCursor(nil, IDC_ARROW)
|
56
|
+
wc[:hbrBackground] = FFI::Pointer.new(COLOR_APPWORKSPACE + 1)
|
57
|
+
|
58
|
+
PWSTR(APPNAME) { |className|
|
59
|
+
wc[:lpszClassName] = className
|
60
|
+
|
61
|
+
DetonateLastError(0, :RegisterClassEx,
|
62
|
+
wc
|
63
|
+
)
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
hwnd = CreateWindowEx(
|
68
|
+
0, APPNAME, APPNAME, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
|
69
|
+
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
70
|
+
nil, nil, GetModuleHandle(nil), nil
|
71
|
+
)
|
72
|
+
|
73
|
+
raise "CreateWindowEx failed (last error: #{GetLastError()})" if
|
74
|
+
hwnd.null? && GetLastError() != 0
|
75
|
+
|
76
|
+
exit(0) if hwnd.null?
|
77
|
+
|
78
|
+
ShowWindow(hwnd, SW_SHOWNORMAL)
|
79
|
+
UpdateWindow(hwnd)
|
80
|
+
|
81
|
+
MSG.new { |msg|
|
82
|
+
until DetonateLastError(-1, :GetMessage,
|
83
|
+
msg, nil, 0, 0
|
84
|
+
) == 0
|
85
|
+
TranslateMessage(msg)
|
86
|
+
DispatchMessage(msg)
|
87
|
+
end
|
88
|
+
|
89
|
+
exit(msg[:wParam])
|
90
|
+
}
|
91
|
+
rescue
|
92
|
+
MessageBox(hwnd,
|
93
|
+
L(Util.FormatException($!)),
|
94
|
+
APPNAME,
|
95
|
+
MB_ICONERROR
|
96
|
+
); exit(1)
|
97
|
+
end
|
98
|
+
|
99
|
+
WinMain()
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'windows_gui'
|
2
|
+
|
3
|
+
include WindowsGUI
|
4
|
+
|
5
|
+
WndExtra = Struct.new(
|
6
|
+
:hpen,
|
7
|
+
:curpos,
|
8
|
+
:scribbles
|
9
|
+
)
|
10
|
+
|
11
|
+
def OnCreate(hwnd,
|
12
|
+
cs
|
13
|
+
)
|
14
|
+
xtra = Util::Id2Ref[GetWindowLong(hwnd, GWL_USERDATA)]
|
15
|
+
|
16
|
+
LOGPEN.new { |lp|
|
17
|
+
lp[:lopnWidth][:x] = DPIAwareX(10)
|
18
|
+
lp[:lopnColor] = RGB(255, 0, 0)
|
19
|
+
|
20
|
+
xtra[:hpen] = CreatePenIndirect(lp)
|
21
|
+
}
|
22
|
+
|
23
|
+
xtra[:scribbles] = []
|
24
|
+
|
25
|
+
0
|
26
|
+
end
|
27
|
+
|
28
|
+
def OnDestroy(hwnd)
|
29
|
+
xtra = Util::Id2Ref[GetWindowLong(hwnd, GWL_USERDATA)]
|
30
|
+
|
31
|
+
DeleteObject(xtra[:hpen])
|
32
|
+
|
33
|
+
PostQuitMessage(0); 0
|
34
|
+
end
|
35
|
+
|
36
|
+
def OnPaint(hwnd,
|
37
|
+
ps
|
38
|
+
)
|
39
|
+
xtra = Util::Id2Ref[GetWindowLong(hwnd, GWL_USERDATA)]
|
40
|
+
|
41
|
+
UseObjects(ps[:hdc], xtra[:hpen]) {
|
42
|
+
xtra[:scribbles].each { |scribble|
|
43
|
+
MoveToEx(ps[:hdc], *scribble[0], nil)
|
44
|
+
|
45
|
+
scribble.each { |x, y|
|
46
|
+
LineTo(ps[:hdc], x, y)
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
0
|
52
|
+
end
|
53
|
+
|
54
|
+
def OnLButtonDown(hwnd,
|
55
|
+
x, y
|
56
|
+
)
|
57
|
+
SetCapture(hwnd)
|
58
|
+
|
59
|
+
xtra = Util::Id2Ref[GetWindowLong(hwnd, GWL_USERDATA)]
|
60
|
+
|
61
|
+
xtra[:curpos] = [x, y]
|
62
|
+
xtra[:scribbles] << [[x, y]]
|
63
|
+
|
64
|
+
RECT.new { |rect|
|
65
|
+
SetRect(rect, x, y, x, y)
|
66
|
+
InflateRect(rect, *DPIAwareXY(5, 5))
|
67
|
+
InvalidateRect(hwnd, rect, 1)
|
68
|
+
}
|
69
|
+
|
70
|
+
0
|
71
|
+
end
|
72
|
+
|
73
|
+
def OnLButtonUp(hwnd,
|
74
|
+
x, y
|
75
|
+
)
|
76
|
+
ReleaseCapture()
|
77
|
+
|
78
|
+
0
|
79
|
+
end
|
80
|
+
|
81
|
+
def OnMouseMove(hwnd,
|
82
|
+
x, y
|
83
|
+
)
|
84
|
+
return 0 if GetCapture() != hwnd
|
85
|
+
|
86
|
+
xtra = Util::Id2Ref[GetWindowLong(hwnd, GWL_USERDATA)]
|
87
|
+
|
88
|
+
xtra[:scribbles].last << [x, y]
|
89
|
+
|
90
|
+
UseDC(hwnd) { |hdc|
|
91
|
+
UseObjects(hdc, xtra[:hpen]) {
|
92
|
+
MoveToEx(hdc, *xtra[:curpos], nil)
|
93
|
+
LineTo(hdc, x, y)
|
94
|
+
|
95
|
+
xtra[:curpos] = [x, y]
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
0
|
100
|
+
end
|
101
|
+
|
102
|
+
def OnRButtonDown(hwnd,
|
103
|
+
x, y
|
104
|
+
)
|
105
|
+
return 0 if GetCapture() == hwnd
|
106
|
+
|
107
|
+
xtra = Util::Id2Ref[GetWindowLong(hwnd, GWL_USERDATA)]
|
108
|
+
|
109
|
+
xtra[:scribbles].clear
|
110
|
+
|
111
|
+
InvalidateRect(hwnd, nil, 1)
|
112
|
+
|
113
|
+
0
|
114
|
+
end
|
115
|
+
|
116
|
+
WindowProc = FFI::Function.new(:long,
|
117
|
+
[:pointer, :uint, :uint, :long],
|
118
|
+
convention: :stdcall
|
119
|
+
) { |hwnd, uMsg, wParam, lParam|
|
120
|
+
begin
|
121
|
+
result = case uMsg
|
122
|
+
when WM_NCCREATE
|
123
|
+
DefWindowProc(hwnd, uMsg, wParam, lParam)
|
124
|
+
|
125
|
+
SetWindowLong(hwnd,
|
126
|
+
GWL_USERDATA,
|
127
|
+
CREATESTRUCT.new(FFI::Pointer.new(lParam))[:lpCreateParams].to_i
|
128
|
+
)
|
129
|
+
|
130
|
+
1
|
131
|
+
when WM_CREATE
|
132
|
+
OnCreate(hwnd, CREATESTRUCT.new(FFI::Pointer.new(lParam)))
|
133
|
+
when WM_DESTROY
|
134
|
+
OnDestroy(hwnd)
|
135
|
+
|
136
|
+
when WM_PAINT
|
137
|
+
DoPaint(hwnd) { |ps| result = OnPaint(hwnd, ps) }
|
138
|
+
|
139
|
+
when WM_LBUTTONDOWN
|
140
|
+
OnLButtonDown(hwnd, LOSHORT(lParam), HISHORT(lParam))
|
141
|
+
when WM_LBUTTONUP
|
142
|
+
OnLButtonUp(hwnd, LOSHORT(lParam), HISHORT(lParam))
|
143
|
+
when WM_MOUSEMOVE
|
144
|
+
OnMouseMove(hwnd, LOSHORT(lParam), HISHORT(lParam))
|
145
|
+
|
146
|
+
when WM_RBUTTONDOWN
|
147
|
+
OnRButtonDown(hwnd, LOSHORT(lParam), HISHORT(lParam))
|
148
|
+
end
|
149
|
+
|
150
|
+
result || DefWindowProc(hwnd, uMsg, wParam, lParam)
|
151
|
+
rescue SystemExit => ex
|
152
|
+
PostQuitMessage(ex.status)
|
153
|
+
rescue
|
154
|
+
case MessageBox(hwnd,
|
155
|
+
L(Util.FormatException($!)),
|
156
|
+
APPNAME,
|
157
|
+
MB_ABORTRETRYIGNORE | MB_ICONERROR
|
158
|
+
)
|
159
|
+
when IDABORT
|
160
|
+
PostQuitMessage(2)
|
161
|
+
when IDRETRY
|
162
|
+
retry
|
163
|
+
end
|
164
|
+
end
|
165
|
+
}
|
166
|
+
|
167
|
+
def WinMain
|
168
|
+
Util.Id2RefTrack(xtra = WndExtra.new)
|
169
|
+
|
170
|
+
WNDCLASSEX.new { |wc|
|
171
|
+
wc[:cbSize] = wc.size
|
172
|
+
wc[:lpfnWndProc] = WindowProc
|
173
|
+
wc[:cbWndExtra] = FFI::Type::Builtin::POINTER.size
|
174
|
+
wc[:hInstance] = GetModuleHandle(nil)
|
175
|
+
wc[:hIcon] = LoadIcon(nil, IDI_APPLICATION)
|
176
|
+
wc[:hCursor] = LoadCursor(nil, IDC_CROSS)
|
177
|
+
wc[:hbrBackground] = FFI::Pointer.new(COLOR_WINDOW + 1)
|
178
|
+
|
179
|
+
PWSTR(APPNAME) { |className|
|
180
|
+
wc[:lpszClassName] = className
|
181
|
+
|
182
|
+
DetonateLastError(0, :RegisterClassEx,
|
183
|
+
wc
|
184
|
+
)
|
185
|
+
}
|
186
|
+
}
|
187
|
+
|
188
|
+
hwnd = CreateWindowEx(
|
189
|
+
WS_EX_CLIENTEDGE, APPNAME, APPNAME, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
|
190
|
+
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
191
|
+
nil, nil, GetModuleHandle(nil), FFI::Pointer.new(xtra.object_id)
|
192
|
+
)
|
193
|
+
|
194
|
+
raise "CreateWindowEx failed (last error: #{GetLastError()})" if
|
195
|
+
hwnd.null? && GetLastError() != 0
|
196
|
+
|
197
|
+
exit(0) if hwnd.null?
|
198
|
+
|
199
|
+
ShowWindow(hwnd, SW_SHOWNORMAL)
|
200
|
+
UpdateWindow(hwnd)
|
201
|
+
|
202
|
+
MSG.new { |msg|
|
203
|
+
until DetonateLastError(-1, :GetMessage,
|
204
|
+
msg, nil, 0, 0
|
205
|
+
) == 0
|
206
|
+
TranslateMessage(msg)
|
207
|
+
DispatchMessage(msg)
|
208
|
+
end
|
209
|
+
|
210
|
+
exit(msg[:wParam])
|
211
|
+
}
|
212
|
+
rescue
|
213
|
+
MessageBox(hwnd,
|
214
|
+
L(Util.FormatException($!)),
|
215
|
+
APPNAME,
|
216
|
+
MB_ICONERROR
|
217
|
+
); exit(1)
|
218
|
+
end
|
219
|
+
|
220
|
+
WinMain()
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'windows_gui'
|
2
|
+
|
3
|
+
include WindowsGUI
|
4
|
+
|
5
|
+
WndExtra = Struct.new(
|
6
|
+
:foo
|
7
|
+
)
|
8
|
+
|
9
|
+
def OnCreate(hwnd,
|
10
|
+
cs
|
11
|
+
)
|
12
|
+
xtra = Util::Id2Ref[GetWindowLong(hwnd, GWL_USERDATA)]
|
13
|
+
|
14
|
+
xtra[:foo] = L('Foo')
|
15
|
+
|
16
|
+
-1
|
17
|
+
end
|
18
|
+
|
19
|
+
def OnDestroy(hwnd)
|
20
|
+
xtra = Util::Id2Ref[GetWindowLong(hwnd, GWL_USERDATA)]
|
21
|
+
|
22
|
+
MessageBox(nil,
|
23
|
+
xtra[:foo],
|
24
|
+
APPNAME,
|
25
|
+
MB_ICONINFORMATION
|
26
|
+
)
|
27
|
+
|
28
|
+
PostQuitMessage(0); 0
|
29
|
+
end
|
30
|
+
|
31
|
+
WindowProc = FFI::Function.new(:long,
|
32
|
+
[:pointer, :uint, :uint, :long],
|
33
|
+
convention: :stdcall
|
34
|
+
) { |hwnd, uMsg, wParam, lParam|
|
35
|
+
begin
|
36
|
+
result = case uMsg
|
37
|
+
when WM_NCCREATE
|
38
|
+
DefWindowProc(hwnd, uMsg, wParam, lParam)
|
39
|
+
|
40
|
+
SetWindowLong(hwnd,
|
41
|
+
GWL_USERDATA,
|
42
|
+
CREATESTRUCT.new(FFI::Pointer.new(lParam))[:lpCreateParams].to_i
|
43
|
+
)
|
44
|
+
|
45
|
+
1
|
46
|
+
when WM_CREATE
|
47
|
+
OnCreate(hwnd, CREATESTRUCT.new(FFI::Pointer.new(lParam)))
|
48
|
+
when WM_DESTROY
|
49
|
+
OnDestroy(hwnd)
|
50
|
+
end
|
51
|
+
|
52
|
+
result || DefWindowProc(hwnd, uMsg, wParam, lParam)
|
53
|
+
rescue SystemExit => ex
|
54
|
+
PostQuitMessage(ex.status)
|
55
|
+
rescue
|
56
|
+
case MessageBox(hwnd,
|
57
|
+
L(Util.FormatException($!)),
|
58
|
+
APPNAME,
|
59
|
+
MB_ABORTRETRYIGNORE | MB_ICONERROR
|
60
|
+
)
|
61
|
+
when IDABORT
|
62
|
+
PostQuitMessage(2)
|
63
|
+
when IDRETRY
|
64
|
+
retry
|
65
|
+
end
|
66
|
+
end
|
67
|
+
}
|
68
|
+
|
69
|
+
def WinMain
|
70
|
+
Util.Id2RefTrack(xtra = WndExtra.new)
|
71
|
+
|
72
|
+
WNDCLASSEX.new { |wc|
|
73
|
+
wc[:cbSize] = wc.size
|
74
|
+
wc[:lpfnWndProc] = WindowProc
|
75
|
+
wc[:cbWndExtra] = FFI::Type::Builtin::POINTER.size
|
76
|
+
wc[:hInstance] = GetModuleHandle(nil)
|
77
|
+
wc[:hIcon] = LoadIcon(nil, IDI_APPLICATION)
|
78
|
+
wc[:hCursor] = LoadCursor(nil, IDC_ARROW)
|
79
|
+
wc[:hbrBackground] = FFI::Pointer.new(COLOR_WINDOW + 1)
|
80
|
+
|
81
|
+
PWSTR(APPNAME) { |className|
|
82
|
+
wc[:lpszClassName] = className
|
83
|
+
|
84
|
+
DetonateLastError(0, :RegisterClassEx,
|
85
|
+
wc
|
86
|
+
)
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
hwnd = CreateWindowEx(
|
91
|
+
0, APPNAME, APPNAME, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
|
92
|
+
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
93
|
+
nil, nil, GetModuleHandle(nil), FFI::Pointer.new(xtra.object_id)
|
94
|
+
)
|
95
|
+
|
96
|
+
raise "CreateWindowEx failed (last error: #{GetLastError()})" if
|
97
|
+
hwnd.null? && GetLastError() != 0
|
98
|
+
|
99
|
+
exit(0) if hwnd.null?
|
100
|
+
|
101
|
+
ShowWindow(hwnd, SW_SHOWNORMAL)
|
102
|
+
UpdateWindow(hwnd)
|
103
|
+
|
104
|
+
MSG.new { |msg|
|
105
|
+
until DetonateLastError(-1, :GetMessage,
|
106
|
+
msg, nil, 0, 0
|
107
|
+
) == 0
|
108
|
+
TranslateMessage(msg)
|
109
|
+
DispatchMessage(msg)
|
110
|
+
end
|
111
|
+
|
112
|
+
exit(msg[:wParam])
|
113
|
+
}
|
114
|
+
rescue
|
115
|
+
MessageBox(hwnd,
|
116
|
+
L(Util.FormatException($!)),
|
117
|
+
APPNAME,
|
118
|
+
MB_ICONERROR
|
119
|
+
); exit(1)
|
120
|
+
end
|
121
|
+
|
122
|
+
WinMain()
|
Binary file
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'weakref'
|
2
|
+
require 'ffi'
|
3
|
+
|
4
|
+
WINDOWS_GUI_VISUAL_STYLES = true unless defined?(WINDOWS_GUI_VISUAL_STYLES)
|
5
|
+
WINDOWS_GUI_DPI_AWARE = true unless defined?(WINDOWS_GUI_DPI_AWARE)
|
6
|
+
|
7
|
+
module WindowsGUI
|
8
|
+
extend FFI::Library
|
9
|
+
|
10
|
+
VERSION = '2.0.0'
|
11
|
+
|
12
|
+
module Util
|
13
|
+
def FormatException(ex)
|
14
|
+
str, trace = ex.to_s, ex.backtrace
|
15
|
+
|
16
|
+
str << "\n\n-- backtrace --\n\n" << trace.join("\n") if trace
|
17
|
+
|
18
|
+
str
|
19
|
+
end
|
20
|
+
|
21
|
+
module_function :FormatException
|
22
|
+
|
23
|
+
Id2Ref = {}
|
24
|
+
|
25
|
+
def Id2RefTrack(object)
|
26
|
+
Id2Ref[object.object_id] = WeakRef.new(object)
|
27
|
+
|
28
|
+
p "Object id #{object.object_id} of #{object} stored in Id2Ref track hash" if $DEBUG
|
29
|
+
|
30
|
+
ObjectSpace.define_finalizer(object, -> id {
|
31
|
+
Id2Ref.delete(id)
|
32
|
+
|
33
|
+
p "Object id #{id} deleted from Id2Ref track hash" if $DEBUG
|
34
|
+
})
|
35
|
+
end
|
36
|
+
|
37
|
+
module_function :Id2RefTrack
|
38
|
+
|
39
|
+
module ScopedStruct
|
40
|
+
def new(*args)
|
41
|
+
raise ArgumentError, 'Cannot accept both arguments and a block' if
|
42
|
+
args.length > 0 && block_given?
|
43
|
+
|
44
|
+
struct = super
|
45
|
+
|
46
|
+
return struct unless block_given?
|
47
|
+
|
48
|
+
begin
|
49
|
+
yield struct
|
50
|
+
ensure
|
51
|
+
struct.pointer.free
|
52
|
+
|
53
|
+
p "Native memory for #{struct} freed" if $DEBUG
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
INVALID_HANDLE_VALUE = FFI::Pointer.new(-1)
|
62
|
+
|
63
|
+
def MAKEWORD(lobyte, hibyte)
|
64
|
+
(lobyte & 0xff) | ((hibyte & 0xff) << 8)
|
65
|
+
end
|
66
|
+
|
67
|
+
def LOBYTE(word)
|
68
|
+
word & 0xff
|
69
|
+
end
|
70
|
+
|
71
|
+
def HIBYTE(word)
|
72
|
+
(word >> 8) & 0xff
|
73
|
+
end
|
74
|
+
|
75
|
+
module_function :MAKEWORD, :LOBYTE, :HIBYTE
|
76
|
+
|
77
|
+
def MAKELONG(loword, hiword)
|
78
|
+
(loword & 0xffff) | ((hiword & 0xffff) << 16)
|
79
|
+
end
|
80
|
+
|
81
|
+
def LOWORD(long)
|
82
|
+
long & 0xffff
|
83
|
+
end
|
84
|
+
|
85
|
+
def HIWORD(long)
|
86
|
+
(long >> 16) & 0xffff
|
87
|
+
end
|
88
|
+
|
89
|
+
def LOSHORT(long)
|
90
|
+
((loshort = LOWORD(long)) > 0x7fff) ? loshort - 0x1_0000 : loshort
|
91
|
+
end
|
92
|
+
|
93
|
+
def HISHORT(long)
|
94
|
+
((hishort = HIWORD(long)) > 0x7fff) ? hishort - 0x1_0000 : hishort
|
95
|
+
end
|
96
|
+
|
97
|
+
module_function :MAKELONG, :LOWORD, :HIWORD, :LOSHORT, :HISHORT
|
98
|
+
|
99
|
+
def L(str)
|
100
|
+
(str << "\0").encode!('utf-16le')
|
101
|
+
end
|
102
|
+
|
103
|
+
def PWSTR(wstr)
|
104
|
+
raise 'Invalid Unicode string' unless
|
105
|
+
wstr.encoding == Encoding::UTF_16LE && wstr[-1] == L('')
|
106
|
+
|
107
|
+
ptr = FFI::MemoryPointer.new(:ushort, wstr.length).
|
108
|
+
put_bytes(0, wstr)
|
109
|
+
|
110
|
+
return ptr unless block_given?
|
111
|
+
|
112
|
+
begin
|
113
|
+
yield ptr
|
114
|
+
ensure
|
115
|
+
ptr.free
|
116
|
+
|
117
|
+
p "Native copy of '#{wstr[0...-1].encode($0.encoding)}' freed" if $DEBUG
|
118
|
+
end
|
119
|
+
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
|
123
|
+
module_function :L, :PWSTR
|
124
|
+
|
125
|
+
APPNAME = L(File.basename($0, '.rbw'))
|
126
|
+
|
127
|
+
class POINT < FFI::Struct
|
128
|
+
extend Util::ScopedStruct
|
129
|
+
|
130
|
+
layout \
|
131
|
+
:x, :long,
|
132
|
+
:y, :long
|
133
|
+
end
|
134
|
+
|
135
|
+
class SIZE < FFI::Struct
|
136
|
+
extend Util::ScopedStruct
|
137
|
+
|
138
|
+
layout \
|
139
|
+
:cx, :long,
|
140
|
+
:cy, :long
|
141
|
+
end
|
142
|
+
|
143
|
+
class RECT < FFI::Struct
|
144
|
+
extend Util::ScopedStruct
|
145
|
+
|
146
|
+
layout \
|
147
|
+
:left, :long,
|
148
|
+
:top, :long,
|
149
|
+
:right, :long,
|
150
|
+
:bottom, :long
|
151
|
+
end
|
152
|
+
end
|