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

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

UI_Sampleの追加。イベントのコメントアウト解除。Form.abからテスト部分を除去。Application.DoEventsを実装。MakeControlEventHandlerを静的メンバのイベント対応へ。WindowsExceptionの追加。

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