source: trunk/ab5.0/ablib/src/Classes/ActiveBasic/Windows/UI/Control.ab@ 545

Last change on this file since 545 was 545, checked in by イグトランス (egtra), 16 years ago

ActiveBasic.Windows.UI.FormsをUIへ移動。UI以下にForms以外置くものが思い浮かばないので。

File size: 12.8 KB
Line 
1'Classes/ActiveBasic/Windows/UI/Control.ab
2
3#require <Classes/ActiveBasic/Windows/UI/EventArgs.ab>
4
5Namespace ActiveBasic
6Namespace Windows
7Namespace UI
8
9'Namespace Detail
10' TypeDef PTrackMouseEvent = *Function(ByRef tme As TRACKMOUSEEVENT) As BOOL
11'End Namespace
12
13Class Control
14Public
15 Sub Control()
16 End Sub
17
18 Virtual Sub ~Control()
19 End Sub
20
21 Function Handle() As HWND
22 Handle = hwnd
23 End Function
24
25 Static Function FromHWnd(hwnd As HWND) As Control
26 FromHWnd = Nothing
27 If IsWindow(hwnd) Then
28 FromHWnd = FromHWndCore(hwnd)
29 End If
30 End Function
31
32Private
33 Static Function FromHWndCore(hwnd As HWND) As Control
34 If GetClassLongPtr(hwnd, GCW_ATOM) = atom Then
35 Dim gchValue = GetProp(hwnd, PropertyInstance As ULONG_PTR As PCTSTR) As ULONG_PTR
36 If gchValue <> 0 Then
37 Dim gch = System.Runtime.InteropServices.GCHandle.FromIntPtr(gchValue)
38 FromHWndCore = gch.Target As Control
39 Exit Function
40 End If
41 End If
42 End Function
43
44'--------------------------------
45' ウィンドウ作成
46/*
47 Function Create(
48 parent As HWND,
49 rect As RECT,
50 name As String,
51 style As DWord,
52 exStyle = 0 As DWord,
53 menu = 0 As HMENU) As HWND
54*/
55
56Public
57 Function Create() As Boolean
58 Dim cs As CREATESTRUCT
59 cs.hInstance = hInstance
60 cs.lpszClass = (atom As ULONG_PTR) As LPCTSTR
61 GetCreateStruct(cs)
62 Create = createImpl(cs)
63 End Function
64
65Protected
66 Abstract Sub GetCreateStruct(ByRef cs As CREATESTRUCT)
67
68 Function createImpl(ByRef cs As CREATESTRUCT) As Boolean
69 Imports System.Runtime.InteropServices
70
71 Dim gch = GCHandle.Alloc(This)
72 TlsSetValue(tlsIndex, GCHandle.ToIntPtr(gch) As VoidPtr)
73
74 StartWndProc()
75
76 With cs
77 Dim hwnd = CreateWindowEx(.dwExStyle, .lpszClass, .lpszName, .style,
78 .x, .y, .cx, .cy, .hwndParent, .hMenu, .hInstance, .lpCreateParams)
79 createImpl = hwnd <> 0
80 End With
81 End Function
82
83'--------------------------------
84' ウィンドウプロシージャ
85'Protected
86Public
87 Virtual Function WndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
88 Dim h = Nothing As MessageEventHandler
89 Dim b = messageMap.TryGetValue(Hex$(msg), h)
90 If b Then
91 If Not IsNothing(h) Then
92 Dim a = New MessageEventArgs(hwnd, msg, wp, lp)
93 h(This, a)
94 WndProc = a.LResult
95 Exit Function
96 End If
97 End If
98 WndProc = DefWndProc(msg, wp, lp)
99 End Function
100
101 Virtual Function DefWndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
102 DefWndProc = DefWindowProc(hwnd, msg, wp, lp)
103 End Function
104
105Private
106 Static Function makeKeysFormMsg(e As MessageEventArgs) As Keys
107 Dim t As DWord
108 t = e.WParam And Keys.KeyCode
109 t Or= (GetKeyState(VK_SHIFT) As Word And &h8000) << 1
110 t Or= (GetKeyState(VK_CONTROL) As Word And &h8000) << 2
111 t Or= (GetKeyState(VK_MENU) As Word And &h8000) << 3
112 makeKeysFormMsg = t As Keys
113 End Function
114
115 Static Function makeMouseEventFromMsg(e As MessageEventArgs) As MouseEventArgs
116 Dim wp = e.WParam
117 Dim lp = e.LParam
118 makeMouseEventFromMsg = New MouseEventArgs(LOWORD(wp) As MouseButtons, 1, GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 0)
119 End Function
120
121 /*!
122 @brief 最初にウィンドウプロシージャが呼ばれるときに実行される関数
123 ここでは、主なメッセージハンドラの登録を行っている。
124 @date 2008/07/11
125 */
126 Sub StartWndProc()
127 Dim t = This '#177対策
128 AddMessageEvent(WM_ERASEBKGND, AddressOf(t.OnEraseBackground))
129 Dim md = New MessageEventHandler(AddressOf(t.OnMouseDownBase))
130 AddMessageEvent(WM_LBUTTONDOWN, md)
131 AddMessageEvent(WM_RBUTTONDOWN, md)
132 AddMessageEvent(WM_MBUTTONDOWN, md)
133 AddMessageEvent(WM_XBUTTONDOWN, md)
134 Dim mu = New MessageEventHandler(AddressOf(t.OnMouseUpBase))
135 AddMessageEvent(WM_LBUTTONUP, mu)
136 AddMessageEvent(WM_RBUTTONUP, mu)
137 AddMessageEvent(WM_MBUTTONUP, mu)
138 AddMessageEvent(WM_XBUTTONUP, mu)
139 Dim mb = New MessageEventHandler(AddressOf(t.OnMouseDblClkBase))
140 AddMessageEvent(WM_LBUTTONDBLCLK, mu)
141 AddMessageEvent(WM_RBUTTONDBLCLK, mu)
142 AddMessageEvent(WM_MBUTTONDBLCLK, mu)
143 AddMessageEvent(WM_XBUTTONDBLCLK, mu)
144
145 AddMessageEvent(WM_MOUSELEAVE, AddressOf(t.OnMouseLeaveBase))
146 AddMessageEvent(WM_PAINT, AddressOf(t.OnPaintBase))
147 AddMessageEvent(WM_KEYDOWN, AddressOf(t.OnKeyDownBase))
148' AddMessageEvent(WM_CHAR, AddressOf(t.OnChar))
149 AddMessageEvent(WM_CREATE, AddressOf(t.OnCreateBase))
150 End Sub
151
152 Sub OnEraseBackground(sender As Object, e As MessageEventArgs)
153 Dim rc As RECT
154 Dim r = GetClientRect(hwnd, rc)
155 FillRect(e.WParam As HDC, rc, (COLOR_3DFACE + 1) As HBRUSH)
156 e.LResult = TRUE
157 End Sub
158
159 Sub OnMouseDownBase(sender As Object, e As MessageEventArgs)
160 OnMouseDown(makeMouseEventFromMsg(e))
161 End Sub
162
163 Sub OnMouseUpBase(sender As Object, e As MessageEventArgs)
164 Dim me = makeMouseEventFromMsg(e)
165 If doubleClickFired = False Then
166' OnClick(System.EventArgs.Empty)
167 OnMouseClick(me)
168 doubleClickFired = False
169 End If
170 OnMouseUp(me)
171 End Sub
172
173 Sub OnMouseDblClkBase(sender As Object, e As MessageEventArgs)
174 Dim me = makeMouseEventFromMsg(e)
175 doubleClickFired = True
176 OnMouseDown(me)
177' OnDoubleClick(System.EventArgs.Empty)
178 OnMouseDoubleClick(me)
179 End Sub
180
181 Sub OnMouseMoveBase(sender As Object, e As MessageEventArgs)
182 Dim me = makeMouseEventFromMsg(e)
183 If mouseEntered Then
184 OnMouseMove(me)
185 Else
186 mouseEntered = True
187 OnMouseEnter(me)
188 End If
189 End Sub
190
191 Sub OnMouseLeaveBase(sender As Object, e As MessageEventArgs)
192 Dim me = makeMouseEventFromMsg(e)
193 OnMouseLeave(me)
194 mouseEntered = False
195 End Sub
196
197 Sub OnPaintBase(sender As Object, e As MessageEventArgs)
198 Dim ps As PAINTSTRUCT
199 BeginPaint(hwnd, ps)
200 Try
201 OnPaintDC(New PaintDCEventArgs(ps.hdc, ps.rcPaint))
202 Finally
203 EndPaint(hwnd, ps)
204 End Try
205 End Sub
206
207 Sub OnKeyDownBase(sender As Object, e As MessageEventArgs)
208 OnKeyDown(New KeyEventArgs(makeKeysFormMsg(e)))
209 End Sub
210
211 Sub OnKeyUpBase(sender As Object, e As MessageEventArgs)
212 OnKeyUp(New KeyEventArgs(makeKeysFormMsg(e)))
213 End Sub
214
215' コメントアウト解除のときはStartWndProcのコメントアウト解除も忘れないこと
216' Sub OnChar(sender As Object, e As MessageEventArgs)
217' OnKeyPress(New KeyPressEventArgs(e.WParam As Char))
218' End Sub
219
220 Sub OnCreateBase(sender As Object, e As MessageEventArgs)
221 OnCreate(New CreateEventArgs(e.LParam As *CREATESTRUCT))
222 End Sub
223
224 messageMap As System.Collections.Generic.Dictionary<Object /*DWord*/, MessageEventHandler>
225
226Public
227 /*!
228 @biref メッセージイベントハンドラを登録する。
229 @date 2007/12/04
230 */
231 Sub AddMessageEvent(message As DWord, h As MessageEventHandler)
232 If Not IsNothing(h) Then
233 If IsNothing(messageMap) Then
234 messageMap = New System.Collections.Generic.Dictionary<Object, MessageEventHandler>
235 End If
236 Dim msg = Hex$(message)
237 Dim m = Nothing As MessageEventHandler
238 If messageMap.TryGetValue(msg, m) Then
239 messageMap.Item[msg] = m + h
240 Else
241 messageMap.Item[msg] = h
242 End If
243 End If
244 End Sub
245
246 /*!
247 @biref メッセージイベントハンドラ登録を解除する。
248 @date 2007/12/04
249 */
250 Sub RemoveMessageEvent(message As DWord, a As MessageEventHandler)
251 If Not IsNothing(a) Then
252 If Not IsNothing(messageMap) Then
253 Dim msg = Hex$(message)
254 Dim m = messageMap.Item[msg]
255 If Not IsNothing(m) Then
256 messageMap.Item[msg] = m - a
257 End If
258 End If
259 End If
260 End Sub
261
262'--------------------------------
263' ウィンドウメッセージ処理
264
265
266'--------
267'イベント
268
269#include "ControlEvent.sbp"
270
271'--------------------------------
272' インスタンスメンバ変数
273Private
274 hwnd As HWND
275 /*!
276 @brief マウスカーソルがクライアント領域に入っているかどうかのフラグ
277 外から中に入ってきたときにMouseEnterイベントを発生させるために用意している。
278 */
279 mouseEntered As Boolean
280 /*!
281 @brief ダブルクリックが起こったかどうかのフラグ
282 Click/MouseClickイベントのために用意している。
283 @date 2008/07/12
284 */
285 doubleClickFired As Boolean
286
287'--------------------------------
288' 初期ウィンドウクラス
289Private
290 Static Function WndProcFirst(hwnd As HWND, msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
291 Imports System.Runtime.InteropServices
292
293 Dim rThis = Control.FromHWndCore(hwnd)
294 If IsNothing(rThis) Then
295 Dim gchValue = TlsGetValue(tlsIndex) As LONG_PTR
296 TlsSetValue(tlsIndex, 0)
297 If gchValue = 0 Then
298 Goto *InstanceIsNotFound
299 End If
300 Dim gch = GCHandle.FromIntPtr(gchValue)
301 rThis = gch.Target As Control
302 ' ウィンドウが作られて最初にWndProcFirstが呼ばれたとき
303
304 If IsNothing(rThis) Then
305 Goto *InstanceIsNotFound
306 End If
307 rThis.hwnd = hwnd
308 SetProp(hwnd, PropertyInstance As ULONG_PTR As PCSTR, gchValue As HANDLE)
309 End If
310 WndProcFirst = rThis.WndProc(msg, wp, lp)
311 If msg = WM_NCDESTROY Then
312 Dim gchValue = GetProp(hwnd, PropertyInstance As ULONG_PTR As PCTSTR) As ULONG_PTR
313 If gchValue <> 0 Then
314 Dim gch = GCHandle.FromIntPtr(gchValue)
315 gch.Free()
316 End If
317 End If
318
319 Exit Function
320
321 *InstanceIsNotFound
322 OutputDebugString("ActiveBasic.Windows.UI.Control.WndProcFirst: The attached instance is not found.")
323 WndProcFirst = DefWindowProc(hwnd, msg, wp, lp)
324 End Function
325
326' Static Const WM_CONTROL_INVOKE = WM_USER + 0 As DWord
327' Static Const WM_CONTROL_BEGININVOKE = WM_USER + 1 As DWord
328
329'--------------------------------
330' その他の補助関数
331Private
332' Sub tracMouseEvent()
333/* If pTrackMouseEvent <> 0 Then
334 Dim tme As TRACKMOUSEEVENT
335 With tme
336 .cbSize = Len(tme)
337 .dwFlags = TME_HOVER Or TME_LEAVE
338 .hwndTrack = wnd
339 .dwHoverTime = HOVER_DEFAULT
340 End With
341 pTrackMouseEvent(tme)
342 End If
343*/ 'End Sub
344
345'--------------------------------
346' 初期化終了関連(特にウィンドウクラス)
347Private
348 'ウィンドウ作成時にウィンドウプロシージャへThisを伝えるためのもの
349 Static tlsIndex As DWord
350
351 Static hInstance As HINSTANCE
352 Static atom As ATOM
353 Static hmodComctl As HMODULE
354' Static pTrackMouseEvent As PTrackMouseEvent
355
356 Static Const WindowClassName = "ActiveBasic.Windows.UI.Control"
357 Static Const PropertyInstance = 0 As ATOM
358Public
359 Static Sub Initialize(hinst As HINSTANCE)
360 tlsIndex = TlsAlloc()
361 hInstance = hinst
362' hmodComctl = LoadLibrary("comctl32.dll")
363' pTrackMouseEvent = GetProcAddress(hmodComctl, ToMBStr("_TrackMouseEvent"))
364
365 Dim PropertyInstanceString = WindowClassName + " " + Hex$(GetCurrentProcessId())
366 PropertyInstance = GlobalAddAtom(ToTCStr(PropertyInstanceString))
367
368 Dim wcx As WNDCLASSEX
369 With wcx
370 .cbSize = Len (wcx)
371 .style = CS_HREDRAW Or CS_VREDRAW Or CS_DBLCLKS
372 .lpfnWndProc = AddressOf (WndProcFirst)
373 .cbClsExtra = 0
374 .cbWndExtra = 0
375 .hInstance = hinst
376 .hIcon = 0
377 .hCursor = LoadImage(0, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE Or LR_SHARED) As HCURSOR
378 .hbrBackground = 0
379 .lpszMenuName = 0
380 .lpszClassName = ToTCStr(WindowClassName)
381 .hIconSm = 0
382 End With
383 atom = RegisterClassEx(wcx)
384 If atom = 0 Then
385 Dim buf[1023] As TCHAR
386 wsprintf(buf, Ex"ActiveBasic.Windows.UI.Control.Control: RegisterClasseEx failed. Error code: &h%08X\r\n", GetLastError())
387 OutputDebugString(buf)
388 Debug
389 ExitThread(0)
390 End If
391 End Sub
392
393 Static Sub Uninitialize()
394 If atom <> 0 Then
395 UnregisterClass(atom As ULONG_PTR As PCSTR, hInstance)
396 End If
397 If tlsIndex <> 0 And tlsIndex <> &hffffffff Then
398 TlsFree(tlsIndex)
399 End If
400' If hmodComctl <> 0 Then
401' FreeLibrary(hmodComctl)
402' End If
403 If PropertyInstance <> 0 Then
404 GlobalDeleteAtom(PropertyInstance)
405 End If
406 End Sub
407
408End Class
409
410Class Form '仮
411 Inherits Control
412Protected
413 Override Sub GetCreateStruct(ByRef cs As CREATESTRUCT)
414 With cs
415 .lpCreateParams = 0
416 '.hInstance
417 .hMenu = 0
418 .hwndParent = 0
419 .cy = CW_USEDEFAULT
420 .cx = CW_USEDEFAULT
421 .y = CW_USEDEFAULT
422 .x = CW_USEDEFAULT
423 .style = WS_OVERLAPPEDWINDOW
424 .lpszName = ""
425 '.lpszClass
426 .dwExStyle = 0
427 End With
428 End Sub
429Public
430
431 Override Function WndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
432 WndProc = 0
433 Select Case msg
434 Case Else
435 WndProc = Super.WndProc(msg, wp, lp)
436 End Select
437 End Function
438End Class
439
440End Namespace 'UI
441End Namespace 'Widnows
442End Namespace 'ActiveBasic
443
444'----------
445'テスト実行用
446
447Imports ActiveBasic.Windows.UI
448
449'OleInitialize()
450Control.Initialize(GetModuleHandle(0))
451
452Class MyForm
453 Inherits Form
454Public
455 Sub MyForm()
456 Dim f = This
457 f.AddMessageEvent(WM_DESTROY, AddressOf (f.Destory))
458 f.AddPaintDC(AddressOf (f.Paint))
459 End Sub
460
461 Sub Destory(sender As Object, e As EventArgs)
462 OutputDebugString(Ex"Destory\r\n")
463 PostQuitMessage(0)
464 End Sub
465
466 Sub Paint(sender As Object, e As PaintDCEventArgs)
467 TextOut(e.Handle, 10, 10, "Hello world!", 12)
468 End Sub
469End Class
470
471Dim f = New MyForm
472f.Create()
473ShowWindow(f.Handle, SW_SHOW)
474
475Dim m As MSG
476Do
477 Dim ret = GetMessage(m, 0, 0, 0)
478 If ret = 0 Then
479 Exit Do
480 ElseIf ret = -1 Then
481 ExitProcess(-1)
482 End If
483
484 TranslateMessage(m)
485 DispatchMessage(m)
486Loop
487
488f = Nothing
489System.GC.Collect()
490
491Control.Uninitialize()
492'OleUninitialize()
493
494End
Note: See TracBrowser for help on using the repository browser.