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

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

ウィンドウ作成関数を親用のCreateFormと子用のCreateに分離。

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