ffi-wingui-core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2010 - 2011 Radoslav Peev
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.
@@ -0,0 +1,219 @@
1
+ require 'ffi-wingui-core'
2
+
3
+ include WinGUI
4
+
5
+ EnableVisualStyles()
6
+
7
+ APPNAME = File.basename(__FILE__, '.rbw')
8
+
9
+ CMD_ITEM1 = WM_APP + 1
10
+ CTL_BUTTON1 = CMD_ITEM1 + 1
11
+
12
+ WndExtra = Struct.new(
13
+ :haccel,
14
+ :hmf
15
+ )
16
+
17
+ class WndExtra
18
+ REFS = {}
19
+
20
+ def initialize(*args)
21
+ super
22
+
23
+ REFS[object_id] = self
24
+
25
+ ObjectSpace.define_finalizer(self, -> id {
26
+ REFS.delete(id)
27
+ })
28
+ end
29
+ end
30
+
31
+ def onCreate(hwnd,
32
+ cs
33
+ )
34
+ #xtra = ObjectSpace._id2ref(GetWindowLong(hwnd, GWL_USERDATA))
35
+ xtra = WndExtra::REFS[GetWindowLong(hwnd, GWL_USERDATA)]
36
+
37
+ hbar = CreateMenu()
38
+ hmenu1 = CreatePopupMenu()
39
+ AppendMenu(hmenu1, MF_STRING, CMD_ITEM1, "Item&1\tAlt+I")
40
+ AppendMenu(hbar, MF_POPUP, hmenu1.to_i, 'Menu&1')
41
+ SetMenu(hwnd, hbar)
42
+
43
+ accels = [
44
+ [FVIRTKEY | FALT, 'I'.ord, CMD_ITEM1]
45
+ ]
46
+
47
+ FFI::MemoryPointer.new(ACCEL, accels.size) { |paccels|
48
+ accels.each.with_index { |data, i|
49
+ accel = ACCEL.new(paccels + i * ACCEL.size)
50
+
51
+ accel[:fVirt], accel[:key], accel[:cmd] = data
52
+ }
53
+
54
+ xtra[:haccel] = CreateAcceleratorTable(paccels, accels.size)
55
+ }
56
+
57
+ ncm = NONCLIENTMETRICS.new; ncm[:cbSize] = ncm.size
58
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.size, ncm, 0);
59
+ xtra[:hmf] = CreateFontIndirect(ncm[:lfMenuFont]);
60
+
61
+ hbtn1 = CreateWindowEx(
62
+ 0, 'Button', '&Button1', WS_CHILD | WS_VISIBLE,
63
+ 10, 10, 100, 25,
64
+ hwnd, FFI::Pointer.new(CTL_BUTTON1), GetModuleHandle(nil), nil
65
+ )
66
+ SendMessage(hbtn1, WM_SETFONT, xtra[:hmf].to_i, 1)
67
+
68
+ 0
69
+ end
70
+
71
+ def onDestroy(hwnd)
72
+ #xtra = ObjectSpace._id2ref(GetWindowLong(hwnd, GWL_USERDATA))
73
+ xtra = WndExtra::REFS[GetWindowLong(hwnd, GWL_USERDATA)]
74
+
75
+ DestroyAcceleratorTable(xtra[:haccel])
76
+ DeleteObject(xtra[:hmf])
77
+
78
+ PostQuitMessage(0); 0
79
+ end
80
+
81
+ def onItem1(verb,
82
+ hctl, hwnd
83
+ )
84
+ MessageBox(hwnd,
85
+ __method__.to_s,
86
+ APPNAME,
87
+ MB_ICONINFORMATION
88
+ )
89
+
90
+ =begin
91
+ verb:
92
+ 0 - menu
93
+ 1 - accelerator
94
+ =end
95
+
96
+ raise 'WM_COMMAND hctl must be NULL for menu/accelerator' unless
97
+ hctl.null?
98
+
99
+ EnableWindow(GetDlgItem(hwnd, CTL_BUTTON1), 1)
100
+ EnableMenuItem(GetMenu(hwnd), CMD_ITEM1, MF_GRAYED)
101
+
102
+ 0
103
+ end
104
+
105
+ def onButton1(verb,
106
+ hctl, hwnd
107
+ )
108
+ MessageBox(hwnd,
109
+ __method__.to_s,
110
+ APPNAME,
111
+ MB_ICONINFORMATION
112
+ )
113
+
114
+ =begin
115
+ verb:
116
+ BN_xxx
117
+ =end
118
+
119
+ raise 'WM_COMMAND hctl must NOT be NULL for control' if
120
+ hctl.null?
121
+
122
+ EnableMenuItem(GetMenu(hwnd), CMD_ITEM1, MF_ENABLED)
123
+ EnableWindow(hctl, 0)
124
+
125
+ 0
126
+ end
127
+
128
+ def windowProc(hwnd,
129
+ uMsg,
130
+ wParam, lParam
131
+ )
132
+ case uMsg
133
+ when WM_NCCREATE
134
+ DefWindowProc(hwnd, uMsg, wParam, lParam)
135
+
136
+ SetWindowLong(hwnd,
137
+ GWL_USERDATA,
138
+ CREATESTRUCT.new(FFI::Pointer.new(lParam))[:lpCreateParams].to_i
139
+ )
140
+
141
+ return 1
142
+ when WM_CREATE
143
+ return onCreate(hwnd, CREATESTRUCT.new(FFI::Pointer.new(lParam)))
144
+ when WM_DESTROY
145
+ return onDestroy(hwnd)
146
+ when WM_COMMAND
147
+ id, verb = LOWORD(wParam), HIWORD(wParam)
148
+ hctl = FFI::Pointer.new(lParam)
149
+
150
+ case id
151
+ when CMD_ITEM1
152
+ return onItem1(verb, hctl, hwnd)
153
+ when CTL_BUTTON1
154
+ return onButton1(verb, hctl, hwnd)
155
+ end
156
+ end
157
+
158
+ DefWindowProc(hwnd, uMsg, wParam, lParam)
159
+ rescue
160
+ MessageBox(nil,
161
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
162
+ APPNAME,
163
+ MB_ICONERROR
164
+ ); PostQuitMessage(2)
165
+ end
166
+
167
+ def main
168
+ wc = WNDCLASSEX.new
169
+ xtra = WndExtra.new
170
+
171
+ wc[:cbSize] = wc.size
172
+ wc[:lpfnWndProc] = method(:windowProc)
173
+ #wc[:cbWndExtra] = FFI::Pointer.size
174
+ wc[:cbWndExtra] = FFI::Type::Builtin::POINTER.size
175
+ wc[:hInstance] = GetModuleHandle(nil)
176
+ wc[:hIcon] = LoadIcon(nil, IDI_APPLICATION)
177
+ wc[:hCursor] = LoadCursor(nil, IDC_ARROW)
178
+ wc[:hbrBackground] = FFI::Pointer.new(CTLCOLOR_DLG + 1)
179
+ wc[:lpszClassName] = className = FFI::MemoryPointer.from_string(
180
+ APPNAME
181
+ )
182
+
183
+ DetonateLastError(0, :RegisterClassEx,
184
+ wc
185
+ ) { className.free }
186
+
187
+ hwnd = CreateWindowEx(
188
+ 0, APPNAME, APPNAME, WS_OVERLAPPEDWINDOW,
189
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
190
+ nil, nil, GetModuleHandle(nil), FFI::Pointer.new(xtra.object_id)
191
+ )
192
+
193
+ raise "CreateWindowEx failed (last error: #{GetLastError()})" if
194
+ hwnd.null? && GetLastError() != 0
195
+
196
+ ShowWindow(hwnd, SW_SHOWNORMAL)
197
+ UpdateWindow(hwnd)
198
+
199
+ msg = MSG.new
200
+
201
+ until DetonateLastError(-1, :GetMessage,
202
+ msg, nil, 0, 0
203
+ ) == 0
204
+ if TranslateAccelerator(hwnd, xtra[:haccel], msg) == 0
205
+ TranslateMessage(msg)
206
+ DispatchMessage(msg)
207
+ end
208
+ end
209
+
210
+ exit(msg[:wParam])
211
+ rescue
212
+ MessageBox(nil,
213
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
214
+ APPNAME,
215
+ MB_ICONERROR
216
+ ); exit(1)
217
+ end
218
+
219
+ main
@@ -0,0 +1,11 @@
1
+ require 'ffi-wingui-core'
2
+
3
+ include WinGUI
4
+
5
+ EnableVisualStyles()
6
+
7
+ MessageBox(nil,
8
+ 'Hello, world!',
9
+ 'Hello',
10
+ MB_ICONINFORMATION
11
+ )
@@ -0,0 +1,115 @@
1
+ require 'ffi-wingui-core'
2
+
3
+ include WinGUI
4
+
5
+ EnableVisualStyles()
6
+
7
+ APPNAME = File.basename(__FILE__, '.rbw')
8
+
9
+ def onCreate(hwnd,
10
+ cs
11
+ )
12
+ answer = MessageBox(nil,
13
+ 'Create?',
14
+ cs[:lpszName].read_string,
15
+ MB_YESNO | MB_ICONQUESTION
16
+ )
17
+
18
+ return -1 if answer == IDNO
19
+
20
+ 0
21
+ end
22
+
23
+ def onClose(hwnd)
24
+ answer = MessageBox(hwnd,
25
+ 'Close?',
26
+ APPNAME,
27
+ MB_YESNO | MB_ICONQUESTION |
28
+ MB_DEFBUTTON2
29
+ )
30
+
31
+ DestroyWindow(hwnd) if answer == IDYES
32
+
33
+ 0
34
+ end
35
+
36
+ def onDestroy(hwnd)
37
+ MessageBox(nil,
38
+ __method__.to_s,
39
+ APPNAME,
40
+ MB_ICONINFORMATION
41
+ )
42
+
43
+ PostQuitMessage(0); 0
44
+ end
45
+
46
+ def windowProc(hwnd,
47
+ uMsg,
48
+ wParam, lParam
49
+ )
50
+ case uMsg
51
+ when WM_CREATE
52
+ return onCreate(hwnd, CREATESTRUCT.new(FFI::Pointer.new(lParam)))
53
+ when WM_CLOSE
54
+ return onClose(hwnd)
55
+ when WM_DESTROY
56
+ return onDestroy(hwnd)
57
+ end
58
+
59
+ DefWindowProc(hwnd, uMsg, wParam, lParam)
60
+ rescue
61
+ MessageBox(nil,
62
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
63
+ APPNAME,
64
+ MB_ICONERROR
65
+ ); PostQuitMessage(2)
66
+ end
67
+
68
+ def main
69
+ wc = WNDCLASSEX.new
70
+
71
+ wc[:cbSize] = wc.size
72
+ wc[:lpfnWndProc] = method(:windowProc)
73
+ wc[:hInstance] = GetModuleHandle(nil)
74
+ wc[:hIcon] = LoadIcon(nil, IDI_APPLICATION)
75
+ wc[:hCursor] = LoadCursor(nil, IDC_ARROW)
76
+ wc[:hbrBackground] = FFI::Pointer.new(COLOR_WINDOW + 1)
77
+ wc[:lpszClassName] = className = FFI::MemoryPointer.from_string(
78
+ APPNAME
79
+ )
80
+
81
+ DetonateLastError(0, :RegisterClassEx,
82
+ wc
83
+ ) { className.free }
84
+
85
+ hwnd = CreateWindowEx(
86
+ 0, APPNAME, APPNAME, WS_OVERLAPPEDWINDOW,
87
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
88
+ nil, nil, GetModuleHandle(nil), nil
89
+ )
90
+
91
+ raise "CreateWindowEx failed (last error: #{GetLastError()})" if
92
+ hwnd.null? && GetLastError() != 0
93
+
94
+ ShowWindow(hwnd, SW_SHOWNORMAL)
95
+ UpdateWindow(hwnd)
96
+
97
+ msg = MSG.new
98
+
99
+ until DetonateLastError(-1, :GetMessage,
100
+ msg, nil, 0, 0
101
+ ) == 0
102
+ TranslateMessage(msg)
103
+ DispatchMessage(msg)
104
+ end
105
+
106
+ exit(msg[:wParam])
107
+ rescue
108
+ MessageBox(nil,
109
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
110
+ APPNAME,
111
+ MB_ICONERROR
112
+ ); exit(1)
113
+ end
114
+
115
+ main
@@ -0,0 +1,145 @@
1
+ require 'ffi-wingui-core'
2
+
3
+ include WinGUI
4
+
5
+ EnableVisualStyles()
6
+
7
+ APPNAME = File.basename(__FILE__, '.rbw')
8
+
9
+ def onNCCreate(hwnd,
10
+ cs
11
+ )
12
+ answer = MessageBox(nil,
13
+ 'NCCreate?',
14
+ cs[:lpszName].read_string,
15
+ MB_YESNO | MB_ICONQUESTION
16
+ )
17
+
18
+ return 0 if answer == IDNO
19
+
20
+ 1
21
+ end
22
+
23
+ def onCreate(hwnd,
24
+ cs
25
+ )
26
+ answer = MessageBox(nil,
27
+ 'Create?',
28
+ cs[:lpszName].read_string,
29
+ MB_YESNO | MB_ICONQUESTION
30
+ )
31
+
32
+ return -1 if answer == IDNO
33
+
34
+ 0
35
+ end
36
+
37
+ def onClose(hwnd)
38
+ answer = MessageBox(hwnd,
39
+ 'Close?',
40
+ APPNAME,
41
+ MB_YESNO | MB_ICONQUESTION |
42
+ MB_DEFBUTTON2
43
+ )
44
+
45
+ DestroyWindow(hwnd) if answer == IDYES
46
+
47
+ 0
48
+ end
49
+
50
+ def onDestroy(hwnd)
51
+ MessageBox(nil,
52
+ __method__.to_s,
53
+ APPNAME,
54
+ MB_ICONINFORMATION
55
+ )
56
+
57
+ 0
58
+ end
59
+
60
+ def onNCDestroy(hwnd)
61
+ MessageBox(nil,
62
+ __method__.to_s,
63
+ APPNAME,
64
+ MB_ICONINFORMATION
65
+ )
66
+
67
+ PostQuitMessage(0); 0
68
+ end
69
+
70
+ def windowProc(hwnd,
71
+ uMsg,
72
+ wParam, lParam
73
+ )
74
+ case uMsg
75
+ when WM_NCCREATE
76
+ DefWindowProc(hwnd, uMsg, wParam, lParam)
77
+
78
+ return onNCCreate(hwnd, CREATESTRUCT.new(FFI::Pointer.new(lParam)))
79
+ when WM_CREATE
80
+ return onCreate(hwnd, CREATESTRUCT.new(FFI::Pointer.new(lParam)))
81
+ when WM_CLOSE
82
+ return onClose(hwnd)
83
+ when WM_DESTROY
84
+ return onDestroy(hwnd)
85
+ when WM_NCDESTROY
86
+ return onNCDestroy(hwnd)
87
+ end
88
+
89
+ DefWindowProc(hwnd, uMsg, wParam, lParam)
90
+ rescue
91
+ MessageBox(nil,
92
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
93
+ APPNAME,
94
+ MB_ICONERROR
95
+ ); PostQuitMessage(2)
96
+ end
97
+
98
+ def main
99
+ wc = WNDCLASSEX.new
100
+
101
+ wc[:cbSize] = wc.size
102
+ wc[:lpfnWndProc] = method(:windowProc)
103
+ wc[:hInstance] = GetModuleHandle(nil)
104
+ wc[:hIcon] = LoadIcon(nil, IDI_APPLICATION)
105
+ wc[:hCursor] = LoadCursor(nil, IDC_ARROW)
106
+ wc[:hbrBackground] = FFI::Pointer.new(COLOR_WINDOW + 1)
107
+ wc[:lpszClassName] = className = FFI::MemoryPointer.from_string(
108
+ APPNAME
109
+ )
110
+
111
+ DetonateLastError(0, :RegisterClassEx,
112
+ wc
113
+ ) { className.free }
114
+
115
+ hwnd = CreateWindowEx(
116
+ 0, APPNAME, APPNAME, WS_OVERLAPPEDWINDOW,
117
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
118
+ nil, nil, GetModuleHandle(nil), nil
119
+ )
120
+
121
+ raise "CreateWindowEx failed (last error: #{GetLastError()})" if
122
+ hwnd.null? && GetLastError() != 0
123
+
124
+ ShowWindow(hwnd, SW_SHOWNORMAL)
125
+ UpdateWindow(hwnd)
126
+
127
+ msg = MSG.new
128
+
129
+ until DetonateLastError(-1, :GetMessage,
130
+ msg, nil, 0, 0
131
+ ) == 0
132
+ TranslateMessage(msg)
133
+ DispatchMessage(msg)
134
+ end
135
+
136
+ exit(msg[:wParam])
137
+ rescue
138
+ MessageBox(nil,
139
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
140
+ APPNAME,
141
+ MB_ICONERROR
142
+ ); exit(1)
143
+ end
144
+
145
+ main
@@ -0,0 +1,78 @@
1
+ require 'ffi-wingui-core'
2
+
3
+ include WinGUI
4
+
5
+ EnableVisualStyles()
6
+
7
+ APPNAME = File.basename(__FILE__, '.rbw')
8
+
9
+ def onDestroy(hwnd)
10
+ PostQuitMessage(0); 0
11
+ end
12
+
13
+ def windowProc(hwnd,
14
+ uMsg,
15
+ wParam, lParam
16
+ )
17
+ case uMsg
18
+ when WM_DESTROY
19
+ return onDestroy(hwnd)
20
+ end
21
+
22
+ DefWindowProc(hwnd, uMsg, wParam, lParam)
23
+ rescue
24
+ MessageBox(nil,
25
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
26
+ APPNAME,
27
+ MB_ICONERROR
28
+ ); PostQuitMessage(2)
29
+ end
30
+
31
+ def main
32
+ wc = WNDCLASSEX.new
33
+
34
+ wc[:cbSize] = wc.size
35
+ wc[:lpfnWndProc] = method(:windowProc)
36
+ wc[:hInstance] = GetModuleHandle(nil)
37
+ wc[:hIcon] = LoadIcon(nil, IDI_APPLICATION)
38
+ wc[:hCursor] = LoadCursor(nil, IDC_ARROW)
39
+ wc[:hbrBackground] = FFI::Pointer.new(COLOR_WINDOW + 1)
40
+ wc[:lpszClassName] = className = FFI::MemoryPointer.from_string(
41
+ APPNAME
42
+ )
43
+
44
+ DetonateLastError(0, :RegisterClassEx,
45
+ wc
46
+ ) { className.free }
47
+
48
+ hwnd = CreateWindowEx(
49
+ 0, APPNAME, APPNAME, WS_OVERLAPPEDWINDOW,
50
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
51
+ nil, nil, GetModuleHandle(nil), nil
52
+ )
53
+
54
+ raise "CreateWindowEx failed (last error: #{GetLastError()})" if
55
+ hwnd.null? && GetLastError() != 0
56
+
57
+ ShowWindow(hwnd, SW_SHOWNORMAL)
58
+ UpdateWindow(hwnd)
59
+
60
+ msg = MSG.new
61
+
62
+ until DetonateLastError(-1, :GetMessage,
63
+ msg, nil, 0, 0
64
+ ) == 0
65
+ TranslateMessage(msg)
66
+ DispatchMessage(msg)
67
+ end
68
+
69
+ exit(msg[:wParam])
70
+ rescue
71
+ MessageBox(nil,
72
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
73
+ APPNAME,
74
+ MB_ICONERROR
75
+ ); exit(1)
76
+ end
77
+
78
+ main
@@ -0,0 +1,130 @@
1
+ require 'ffi-wingui-core'
2
+
3
+ include WinGUI
4
+
5
+ EnableVisualStyles()
6
+
7
+ APPNAME = File.basename(__FILE__, '.rbw')
8
+
9
+ WndExtra = Struct.new(
10
+ :foo
11
+ )
12
+
13
+ class WndExtra
14
+ REFS = {}
15
+
16
+ def initialize(*args)
17
+ super
18
+
19
+ REFS[object_id] = self
20
+
21
+ ObjectSpace.define_finalizer(self, -> id {
22
+ REFS.delete(id)
23
+ })
24
+ end
25
+ end
26
+
27
+ def onCreate(hwnd,
28
+ cs
29
+ )
30
+ #xtra = ObjectSpace._id2ref(GetWindowLong(hwnd, GWL_USERDATA))
31
+ xtra = WndExtra::REFS[GetWindowLong(hwnd, GWL_USERDATA)]
32
+
33
+ xtra[:foo] = 'Foo'
34
+
35
+ -1
36
+ end
37
+
38
+ def onDestroy(hwnd)
39
+ #xtra = ObjectSpace._id2ref(GetWindowLong(hwnd, GWL_USERDATA))
40
+ xtra = WndExtra::REFS[GetWindowLong(hwnd, GWL_USERDATA)]
41
+
42
+ MessageBox(nil,
43
+ xtra[:foo],
44
+ APPNAME,
45
+ MB_ICONINFORMATION
46
+ )
47
+
48
+ PostQuitMessage(0); 0
49
+ end
50
+
51
+ def windowProc(hwnd,
52
+ uMsg,
53
+ wParam, lParam
54
+ )
55
+ case uMsg
56
+ when WM_NCCREATE
57
+ DefWindowProc(hwnd, uMsg, wParam, lParam)
58
+
59
+ SetWindowLong(hwnd,
60
+ GWL_USERDATA,
61
+ CREATESTRUCT.new(FFI::Pointer.new(lParam))[:lpCreateParams].to_i
62
+ )
63
+
64
+ return 1
65
+ when WM_CREATE
66
+ return onCreate(hwnd, CREATESTRUCT.new(FFI::Pointer.new(lParam)))
67
+ when WM_DESTROY
68
+ return onDestroy(hwnd)
69
+ end
70
+
71
+ DefWindowProc(hwnd, uMsg, wParam, lParam)
72
+ rescue
73
+ MessageBox(nil,
74
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
75
+ APPNAME,
76
+ MB_ICONERROR
77
+ ); PostQuitMessage(2)
78
+ end
79
+
80
+ def main
81
+ wc = WNDCLASSEX.new
82
+ xtra = WndExtra.new
83
+
84
+ wc[:cbSize] = wc.size
85
+ wc[:lpfnWndProc] = method(:windowProc)
86
+ #wc[:cbWndExtra] = FFI::Pointer.size
87
+ wc[:cbWndExtra] = FFI::Type::Builtin::POINTER.size
88
+ wc[:hInstance] = GetModuleHandle(nil)
89
+ wc[:hIcon] = LoadIcon(nil, IDI_APPLICATION)
90
+ wc[:hCursor] = LoadCursor(nil, IDC_ARROW)
91
+ wc[:hbrBackground] = FFI::Pointer.new(COLOR_WINDOW + 1)
92
+ wc[:lpszClassName] = className = FFI::MemoryPointer.from_string(
93
+ APPNAME
94
+ )
95
+
96
+ DetonateLastError(0, :RegisterClassEx,
97
+ wc
98
+ ) { className.free }
99
+
100
+ hwnd = CreateWindowEx(
101
+ 0, APPNAME, APPNAME, WS_OVERLAPPEDWINDOW,
102
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
103
+ nil, nil, GetModuleHandle(nil), FFI::Pointer.new(xtra.object_id)
104
+ )
105
+
106
+ raise "CreateWindowEx failed (last error: #{GetLastError()})" if
107
+ hwnd.null? && GetLastError() != 0
108
+
109
+ ShowWindow(hwnd, SW_SHOWNORMAL)
110
+ UpdateWindow(hwnd)
111
+
112
+ msg = MSG.new
113
+
114
+ until DetonateLastError(-1, :GetMessage,
115
+ msg, nil, 0, 0
116
+ ) == 0
117
+ TranslateMessage(msg)
118
+ DispatchMessage(msg)
119
+ end
120
+
121
+ exit(msg[:wParam])
122
+ rescue
123
+ MessageBox(nil,
124
+ %'#{$!.to_s}\n\n#{$!.backtrace.join("\n")}',
125
+ APPNAME,
126
+ MB_ICONERROR
127
+ ); exit(1)
128
+ end
129
+
130
+ main