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
RevLine 
[473]1'Classes/ActiveBasic/Windows/UI/Control.ab
2
[545]3#require <Classes/ActiveBasic/Windows/UI/EventArgs.ab>
[473]4
5Namespace ActiveBasic
6Namespace Windows
7Namespace UI
8
[542]9'Namespace Detail
10' TypeDef PTrackMouseEvent = *Function(ByRef tme As TRACKMOUSEEVENT) As BOOL
11'End Namespace
12
[473]13Class Control
[547]14 Inherits WindowHandle
[473]15Public
[551]16 /*!
17 @brief Destroyイベントよりも後に呼ばれるDestroyイベントデリゲート
18 @date 2008/07/16
19 */
20 finalDestroy As ActiveBasic.Windows.UI.Handler
[547]21
[473]22 Sub Control()
23 End Sub
24
25 Virtual Sub ~Control()
26 End Sub
27
[542]28 Function Handle() As HWND
29 Handle = hwnd
[473]30 End Function
31
32 Static Function FromHWnd(hwnd As HWND) As Control
33 FromHWnd = Nothing
[547]34 If _System_IsWindow(hwnd) Then
[473]35 FromHWnd = FromHWndCore(hwnd)
36 End If
37 End Function
38
39Private
40 Static Function FromHWndCore(hwnd As HWND) As Control
[551]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
[473]46 End If
47 End Function
48
49'--------------------------------
[544]50' ウィンドウ作成
[547]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
[542]58
[473]59Public
[551]60 Sub Create(parent = Nothing As Control, style = 0 As DWord, exStyle = 0 As DWord, hmenu = 0 As HMENU)
[473]61 Dim cs As CREATESTRUCT
[551]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
[473]80 GetCreateStruct(cs)
[551]81 createImpl(cs, parent)
[547]82 End Sub
[473]83
[551]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
[473]87Protected
88 Abstract Sub GetCreateStruct(ByRef cs As CREATESTRUCT)
89
[551]90 Sub createImpl(ByRef cs As CREATESTRUCT, parent As Control)
[473]91 Imports System.Runtime.InteropServices
92
[559]93 If hwnd <> 0 Then
94 Throw New System.InvalidOperationException("Window already created.")
95 End If
96
[473]97 Dim gch = GCHandle.Alloc(This)
98 TlsSetValue(tlsIndex, GCHandle.ToIntPtr(gch) As VoidPtr)
99
[542]100 StartWndProc()
101
[473]102 With cs
[551]103 'よそのクラスの場合、WndProcFirst内のhwndの代入が行われないため、ここでも行っておく。
104 hwnd = CreateWindowEx(.dwExStyle, .lpszClass, .lpszName, .style,
[473]105 .x, .y, .cx, .cy, .hwndParent, .hMenu, .hInstance, .lpCreateParams)
[547]106 If hwnd = 0 Then
[559]107 Debug
[547]108 ActiveBasic.Windows.ThrowByWindowsError(GetLastError())
109 End If
[551]110
111 If IsNothing(FromHWndCore(hwnd)) <> False Then
112 AssociateHWnd(gch, hwnd)
113 TlsSetValue(tlsIndex, 0)
114 End If
[473]115 End With
[551]116
117 If IsNothing(parent) = False Then
118 RegisterUnassociateHWnd(parent)
119 End If
[547]120 End Sub
[473]121
122'--------------------------------
123' ウィンドウプロシージャ
124'Protected
125Public
126 Virtual Function WndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
[551]127 Dim h = Nothing As MessageHandler
[542]128 Dim b = messageMap.TryGetValue(Hex$(msg), h)
129 If b Then
130 If Not IsNothing(h) Then
[551]131 Dim a = New MessageArgs(hwnd, msg, wp, lp)
[542]132 h(This, a)
133 WndProc = a.LResult
134 Exit Function
135 End If
136 End If
137 WndProc = DefWndProc(msg, wp, lp)
[473]138 End Function
139
140 Virtual Function DefWndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
[542]141 DefWndProc = DefWindowProc(hwnd, msg, wp, lp)
[473]142 End Function
143
144Private
[551]145 Static Function makeKeysFormMsg(e As MessageArgs) As Keys
[473]146 Dim t As DWord
[544]147 t = e.WParam And Keys.KeyCode
[473]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
[544]151 makeKeysFormMsg = t As Keys
[473]152 End Function
153
[551]154 Static Function makeMouseEventFromMsg(e As MessageArgs) As MouseArgs
[544]155 Dim wp = e.WParam
156 Dim lp = e.LParam
[551]157 makeMouseEventFromMsg = New MouseArgs(LOWORD(wp) As MouseButtons, 1, GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 0)
[542]158 End Function
[473]159
[542]160 /*!
161 @brief 最初にウィンドウプロシージャが呼ばれるときに実行される関数
162 ここでは、主なメッセージハンドラの登録を行っている。
163 @date 2008/07/11
164 */
165 Sub StartWndProc()
[547]166 AddMessageEvent(WM_ERASEBKGND, AddressOf(OnEraseBackground))
[551]167 Dim md = New MessageHandler(AddressOf(OnMouseDownBase))
[542]168 AddMessageEvent(WM_LBUTTONDOWN, md)
169 AddMessageEvent(WM_RBUTTONDOWN, md)
170 AddMessageEvent(WM_MBUTTONDOWN, md)
171 AddMessageEvent(WM_XBUTTONDOWN, md)
[551]172 Dim mu = New MessageHandler(AddressOf(OnMouseUpBase))
[542]173 AddMessageEvent(WM_LBUTTONUP, mu)
174 AddMessageEvent(WM_RBUTTONUP, mu)
175 AddMessageEvent(WM_MBUTTONUP, mu)
176 AddMessageEvent(WM_XBUTTONUP, mu)
[551]177 Dim mb = New MessageHandler(AddressOf(OnMouseDblClkBase))
[542]178 AddMessageEvent(WM_LBUTTONDBLCLK, mu)
179 AddMessageEvent(WM_RBUTTONDBLCLK, mu)
180 AddMessageEvent(WM_MBUTTONDBLCLK, mu)
181 AddMessageEvent(WM_XBUTTONDBLCLK, mu)
[544]182
[547]183 AddMessageEvent(WM_MOUSEMOVE, AddressOf(OnMouseMoveBase))
184 AddMessageEvent(WM_MOUSELEAVE, AddressOf(OnMouseLeaveBase))
185 AddMessageEvent(WM_PAINT, AddressOf(OnPaintBase))
186 AddMessageEvent(WM_KEYDOWN, AddressOf(OnKeyDownBase))
[551]187 AddMessageEvent(WM_CHAR, AddressOf(OnChar))
[547]188 AddMessageEvent(WM_CREATE, AddressOf(OnCreateBase))
[542]189 End Sub
[473]190
[551]191 Sub OnEraseBackground(sender As Object, e As MessageArgs)
[547]192 Dim rc = ClientRect
[542]193 FillRect(e.WParam As HDC, rc, (COLOR_3DFACE + 1) As HBRUSH)
194 e.LResult = TRUE
195 End Sub
[473]196
[551]197 Sub OnMouseDownBase(sender As Object, e As MessageArgs)
[544]198 OnMouseDown(makeMouseEventFromMsg(e))
[542]199 End Sub
200
[551]201 Sub OnMouseUpBase(sender As Object, e As MessageArgs)
[544]202 Dim me = makeMouseEventFromMsg(e)
[542]203 If doubleClickFired = False Then
[551]204' OnClick(System.Args.Empty)
[542]205 OnMouseClick(me)
206 doubleClickFired = False
207 End If
208 OnMouseUp(me)
209 End Sub
210
[551]211 Sub OnMouseDblClkBase(sender As Object, e As MessageArgs)
[544]212 Dim me = makeMouseEventFromMsg(e)
[542]213 doubleClickFired = True
214 OnMouseDown(me)
[551]215' OnDoubleClick(System.Args.Empty)
[542]216 OnMouseDoubleClick(me)
217 End Sub
218
[551]219 Sub OnMouseMoveBase(sender As Object, e As MessageArgs)
[544]220 Dim me = makeMouseEventFromMsg(e)
[542]221 If mouseEntered Then
222 OnMouseMove(me)
223 Else
224 mouseEntered = True
225 OnMouseEnter(me)
226 End If
227 End Sub
228
[551]229 Sub OnMouseLeaveBase(sender As Object, e As MessageArgs)
[544]230 Dim me = makeMouseEventFromMsg(e)
231 OnMouseLeave(me)
232 mouseEntered = False
233 End Sub
234
[551]235 Sub OnPaintBase(sender As Object, e As MessageArgs)
[542]236 Dim ps As PAINTSTRUCT
[547]237 BeginPaint(ps)
[544]238 Try
[551]239 OnPaintDC(New PaintDCArgs(ps.hdc, ps.rcPaint))
[544]240 Finally
[547]241 EndPaint(ps)
[544]242 End Try
[542]243 End Sub
244
[551]245 Sub OnKeyDownBase(sender As Object, e As MessageArgs)
246 OnKeyDown(New KeyArgs(makeKeysFormMsg(e)))
[544]247 End Sub
[542]248
[551]249 Sub OnKeyUpBase(sender As Object, e As MessageArgs)
250 OnKeyUp(New KeyArgs(makeKeysFormMsg(e)))
[544]251 End Sub
252
[551]253 Sub OnChar(sender As Object, e As MessageArgs)
254 OnKeyPress(New KeyPressArgs(e.WParam As Char))
255 End Sub
[544]256
[551]257 Sub OnCreateBase(sender As Object, e As MessageArgs)
[559]258 OnCreate(New CreateArgs(e.LParam As *CREATESTRUCT))
[544]259 End Sub
260
[551]261 messageMap As System.Collections.Generic.Dictionary<Object /*DWord*/, MessageHandler>
[542]262
263Public
[473]264 /*!
[542]265 @biref メッセージイベントハンドラを登録する。
[473]266 @date 2007/12/04
267 */
[551]268 Sub AddMessageEvent(message As DWord, h As MessageHandler)
[542]269 If Not IsNothing(h) Then
270 If IsNothing(messageMap) Then
[551]271 messageMap = New System.Collections.Generic.Dictionary<Object, MessageHandler>
[542]272 End If
273 Dim msg = Hex$(message)
[551]274 Dim m = Nothing As MessageHandler
[542]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
[473]281 End Sub
282
[542]283 /*!
284 @biref メッセージイベントハンドラ登録を解除する。
285 @date 2007/12/04
286 */
[551]287 Sub RemoveMessageEvent(message As DWord, a As MessageHandler)
[542]288 If Not IsNothing(a) Then
289 If Not IsNothing(messageMap) Then
[545]290 Dim msg = Hex$(message)
[542]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
[473]303'--------
304'イベント
305
306#include "ControlEvent.sbp"
307
308'--------------------------------
[544]309' インスタンスメンバ変数
[473]310Private
[542]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
[473]322
323'--------------------------------
[544]324' 初期ウィンドウクラス
[473]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
[547]329 Dim rThis = FromHWndCore(hwnd)
[473]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
[559]340 AssociateHWnd(gch, hwnd)
[473]341 End If
342 If msg = WM_NCDESTROY Then
[551]343 rThis.UnassociateHWnd()
[473]344 End If
[551]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)
[473]351 Exit Function
352
353 *InstanceIsNotFound
[559]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))
[473]357 WndProcFirst = DefWindowProc(hwnd, msg, wp, lp)
358 End Function
[542]359
[551]360 /*!
361 @brief Controlインスタンスとウィンドウハンドルを結び付ける。
362 @param[in] 結び付けられるControlインスタンスを格納したGCHandle
363 @param[in] hwnd 結び付けるウィンドウハンドル
364 @date 2008/07/16
365 これを実行することで、UnassociateHWndされるまでControlがGC対象にならなくなる。
366 */
[559]367 Static Sub AssociateHWnd(gch As System.Runtime.InteropServices.GCHandle, hwnd As HWND)
[551]368 Imports System.Runtime.InteropServices
369 Dim rThis = gch.Target As Control
370 If IsNothing(rThis) Then
[559]371 Exit Sub
[551]372 End If
373 rThis.hwnd = hwnd
374 rThis.Prop[PropertyInstance] = GCHandle.ToIntPtr(gch) As HANDLE
[559]375 End Sub
[551]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
[473]406' Static Const WM_CONTROL_INVOKE = WM_USER + 0 As DWord
407' Static Const WM_CONTROL_BEGININVOKE = WM_USER + 1 As DWord
408
409'--------------------------------
[542]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'--------------------------------
[544]426' 初期化終了関連(特にウィンドウクラス)
[542]427Private
[473]428 'ウィンドウ作成時にウィンドウプロシージャへThisを伝えるためのもの
429 Static tlsIndex As DWord
430
431 Static hInstance As HINSTANCE
432 Static atom As ATOM
[542]433 Static hmodComctl As HMODULE
434' Static pTrackMouseEvent As PTrackMouseEvent
[473]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
[542]442' hmodComctl = LoadLibrary("comctl32.dll")
443' pTrackMouseEvent = GetProcAddress(hmodComctl, ToMBStr("_TrackMouseEvent"))
[473]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()
[542]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
[473]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.