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
Line 
1'Classes/ActiveBasic/Windows/UI/Control.ab
2
3#require <Classes/ActiveBasic/Windows/UI/EventArgs.ab>
4#require <Classes/ActiveBasic/COM/ComClassBase.ab>
5
6Namespace ActiveBasic
7Namespace Windows
8Namespace UI
9
10Namespace Detail
11 TypeDef PTrackMouseEvent = *Function(ByRef tme As TRACKMOUSEEVENT) As BOOL
12End Namespace
13
14Class Control
15 Inherits WindowHandle
16 Implements ActiveBasic.COM.InterfaceQuerable
17Public
18 /*!
19 @brief Destroyイベントよりも後に呼ばれるDestroyイベントデリゲート
20 @date 2008/07/16
21 */
22 finalDestroy As ActiveBasic.Windows.UI.Handler
23
24 Sub Control()
25 comImpl = New COM.ComClassDelegationImpl(This)
26 End Sub
27
28 Virtual Sub ~Control()
29 End Sub
30
31 Function Handle() As HWND
32 Handle = hwnd
33 End Function
34
35 /*!
36 @brief HWNDからControlインスタンスを取得する。
37 @param[in] hwnd 対象のウィンドウハンドル
38 @return 対応するControlインスタンス。ただし、存在しなければNothing。
39 */
40 Static Function FromHWnd(hwnd As HWND) As Control
41 FromHWnd = Nothing
42 If _System_IsWindow(hwnd) Then
43 FromHWnd = FromHWndCore(hwnd)
44 End If
45 End Function
46
47Private
48 Static Function FromHWndCore(hwnd As HWND) As Control
49 FromHWndCore = _System_PtrObj(GetProp(hwnd, PropertyInstance As ULONG_PTR As PCTSTR) As VoidPtr) As Control
50 End Function
51
52'--------------------------------
53' ウィンドウ作成
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
61
62Public
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)
69 Dim cs As CREATESTRUCT
70 With cs
71 .dwExStyle = exStyle
72 .lpszClass = (atom As ULONG_PTR) As LPCTSTR
73 .lpszName = 0
74 .style = style
75 .x = 0
76 .y = 0
77 .cx = 0
78 .cy = 0
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
87 GetCreateStruct(cs)
88 createImpl(cs, parent)
89 End Sub
90
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)
97 End Sub
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
110Protected
111 Abstract Sub GetCreateStruct(ByRef cs As CREATESTRUCT)
112
113 Sub createImpl(ByRef cs As CREATESTRUCT, parent As Control)
114 If hwnd <> 0 Then
115 Throw New System.InvalidOperationException("Window already created.")
116 End If
117
118 StartWndProc()
119
120 With cs
121 'よそのウィンドウクラスの場合、WndProcFirst内のhwndの代入が行われないため、ここでも行っておく。
122 hwnd = CreateWindowEx(.dwExStyle, .lpszClass, .lpszName, .style,
123 .x, .y, .cx, .cy, .hwndParent, .hMenu, .hInstance, .lpCreateParams)
124 If hwnd = 0 Then
125 ActiveBasic.Windows.ThrowByWindowsError(GetLastError())
126 End If
127
128 If IsNothing(FromHWndCore(hwnd)) <> False Then
129 AssociateHWnd(hwnd)
130 TlsSetValue(tlsIndex, 0)
131 End If
132 End With
133
134 If IsNothing(parent) = False Then
135 RegisterUnassociateHWnd(parent)
136 End If
137 End Sub
138
139'--------------------------------
140' ウィンドウプロシージャ
141'Protected
142Public
143 Virtual Function WndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
144 Dim h = Nothing As MessageHandler
145 Dim b = messageMap.TryGetValue(Hex$(msg), h)
146 If b Then
147 If Not IsNothing(h) Then
148 Dim a = New MessageArgs(hwnd, msg, wp, lp)
149 h(This, a)
150 WndProc = a.LResult
151 Exit Function
152 End If
153 End If
154 WndProc = DefWndProc(msg, wp, lp)
155 End Function
156
157 Virtual Function DefWndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
158 DefWndProc = DefWindowProc(hwnd, msg, wp, lp)
159 End Function
160
161Private
162 Static Function makeKeysFormMsg(e As MessageArgs) As Keys
163 Dim t As DWord
164 t = e.WParam And Keys.KeyCode
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
168 makeKeysFormMsg = t As Keys
169 End Function
170
171 Static Function makeMouseEventFromMsg(e As MessageArgs) As MouseArgs
172 Dim wp = e.WParam
173 Dim lp = e.LParam
174 makeMouseEventFromMsg = New MouseArgs(LOWORD(wp) As MouseButtons, 1, GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 0)
175 End Function
176
177Protected
178 /*!
179 @brief 最初にウィンドウプロシージャを使うための前処理を行う関数
180 @date 2008/07/11
181 WndProcFirstを使うときは、この関数を呼んでおく必要がある。
182 */
183 Sub StartWndProc()
184 TlsSetValue(tlsIndex, ObjPtr(This))
185 registerStandardEvent()
186 End Sub
187Private
188 /*!
189 @brief 主なメッセージハンドラの登録を行う関数
190 @date 2008/08/02
191 */
192 Sub registerStandardEvent()
193 AddMessageEvent(WM_ERASEBKGND, AddressOf(OnEraseBackground))
194 Dim md = New MessageHandler(AddressOf(OnMouseDownBase))
195 AddMessageEvent(WM_LBUTTONDOWN, md)
196 AddMessageEvent(WM_RBUTTONDOWN, md)
197 AddMessageEvent(WM_MBUTTONDOWN, md)
198 AddMessageEvent(WM_XBUTTONDOWN, md)
199 Dim mu = New MessageHandler(AddressOf(OnMouseUpBase))
200 AddMessageEvent(WM_LBUTTONUP, mu)
201 AddMessageEvent(WM_RBUTTONUP, mu)
202 AddMessageEvent(WM_MBUTTONUP, mu)
203 AddMessageEvent(WM_XBUTTONUP, mu)
204 Dim mb = New MessageHandler(AddressOf(OnMouseDblClkBase))
205 AddMessageEvent(WM_LBUTTONDBLCLK, mb)
206 AddMessageEvent(WM_RBUTTONDBLCLK, mb)
207 AddMessageEvent(WM_MBUTTONDBLCLK, mb)
208 AddMessageEvent(WM_XBUTTONDBLCLK, mb)
209
210 AddMessageEvent(WM_MOUSEMOVE, AddressOf(OnMouseMoveBase))
211 AddMessageEvent(WM_MOUSELEAVE, AddressOf(OnMouseLeaveBase))
212 AddMessageEvent(WM_MOUSEHOVER, AddressOf(OnMouseHoverBase))
213 AddMessageEvent(WM_PAINT, AddressOf(OnPaintBase))
214 AddMessageEvent(WM_KEYDOWN, AddressOf(OnKeyDownBase))
215 AddMessageEvent(WM_CHAR, AddressOf(OnChar))
216 AddMessageEvent(WM_CREATE, AddressOf(OnCreateBase))
217 AddMessageEvent(WM_SIZE, AddressOf(OnSize))
218 End Sub
219
220 Sub OnEraseBackground(sender As Object, e As MessageArgs)
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
227 e.LResult = TRUE
228 End Sub
229
230 Sub OnMouseDownBase(sender As Object, e As MessageArgs)
231 OnMouseDown(makeMouseEventFromMsg(e))
232 End Sub
233
234 Sub OnMouseUpBase(sender As Object, e As MessageArgs)
235 Dim me = makeMouseEventFromMsg(e)
236 If doubleClickFired = False Then
237 OnClick(Args.Empty)
238 OnMouseClick(me)
239 Else
240 doubleClickFired = False
241 End If
242 OnMouseUp(me)
243 End Sub
244
245 Sub OnMouseDblClkBase(sender As Object, e As MessageArgs)
246 Dim me = makeMouseEventFromMsg(e)
247 doubleClickFired = True
248 OnMouseDown(me)
249 OnDoubleClick(Args.Empty)
250 OnMouseDoubleClick(me)
251 End Sub
252
253 Sub OnMouseMoveBase(sender As Object, e As MessageArgs)
254 Dim me = makeMouseEventFromMsg(e)
255 If mouseEntered = False Then
256 mouseEntered = True
257 OnMouseEnter(me)
258 trackMouseEvent(TME_LEAVE Or TME_HOVER)
259 End If
260 OnMouseMove(me)
261 End Sub
262
263 Sub OnMouseLeaveBase(sender As Object, e As MessageArgs)
264 OnMouseLeave(Args.Empty)
265 mouseEntered = False
266 End Sub
267
268 Sub OnMouseHoverBase(sender As Object, e As MessageArgs)
269 Dim me = makeMouseEventFromMsg(e)
270 OnMouseHover(me)
271 End Sub
272
273 Sub OnPaintBase(sender As Object, e As MessageArgs)
274 Dim ps As PAINTSTRUCT
275 BeginPaint(ps)
276 Try
277 OnPaintDC(New PaintDCArgs(ps.hdc, ps.rcPaint))
278 Finally
279 EndPaint(ps)
280 End Try
281 End Sub
282
283 Sub OnKeyDownBase(sender As Object, e As MessageArgs)
284 OnKeyDown(New KeyArgs(makeKeysFormMsg(e)))
285 End Sub
286
287 Sub OnKeyUpBase(sender As Object, e As MessageArgs)
288 OnKeyUp(New KeyArgs(makeKeysFormMsg(e)))
289 End Sub
290
291 Sub OnChar(sender As Object, e As MessageArgs)
292 OnKeyPress(New KeyPressArgs(e.WParam As Char))
293 End Sub
294
295 Sub OnCreateBase(sender As Object, e As MessageArgs)
296 OnCreate(New CreateArgs(e.LParam As *CREATESTRUCT))
297 End Sub
298
299 Sub OnSize(sender As Object, e As MessageArgs)
300 OnResize(New ResizeArgs(e.WParam, e.LParam))
301 End Sub
302
303 messageMap As System.Collections.Generic.Dictionary<Object /*DWord*/, MessageHandler>
304
305Public
306 /*!
307 @biref メッセージイベントハンドラを登録する。
308 @date 2007/12/04
309 */
310 Sub AddMessageEvent(message As DWord, h As MessageHandler)
311 If Not IsNothing(h) Then
312 If IsNothing(messageMap) Then
313 messageMap = New System.Collections.Generic.Dictionary<Object, MessageHandler>
314 End If
315 Dim msg = Hex$(message)
316 Dim m = Nothing As MessageHandler
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
323 End Sub
324
325 /*!
326 @biref メッセージイベントハンドラ登録を解除する。
327 @date 2007/12/04
328 */
329 Sub RemoveMessageEvent(message As DWord, a As MessageHandler)
330 If Not IsNothing(a) Then
331 If Not IsNothing(messageMap) Then
332 Dim msg = Hex$(message)
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
345'--------
346'イベント
347
348#include "ControlEvent.sbp"
349
350'--------------------------------
351' インスタンスメンバ変数
352Private
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
364
365'--------------------------------
366' 初期ウィンドウクラス
367Protected
368 Static Function WndProcFirst(hwnd As HWND, msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
369 Imports System.Runtime.InteropServices
370
371 Dim rThis = FromHWndCore(hwnd)
372 If IsNothing(rThis) Then
373 rThis = _System_PtrObj(TlsGetValue(tlsIndex)) As Control
374 TlsSetValue(tlsIndex, 0)
375 If IsNothing(rThis) Then
376 Goto *InstanceIsNotFound
377 End If
378 ' ウィンドウが作られて最初にWndProcFirstが呼ばれたとき
379 rThis.AssociateHWnd(hwnd)
380 End If
381 If msg = WM_NCDESTROY Then
382 rThis.UnassociateHWnd()
383 End If
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)
390 Exit Function
391
392 *InstanceIsNotFound
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))
396 WndProcFirst = DefWindowProc(hwnd, msg, wp, lp)
397 End Function
398
399 /*!
400 @brief Controlインスタンスとウィンドウハンドルを結び付ける。
401 @param[in] hwnd 結び付けるウィンドウハンドル
402 @date 2008/07/16
403 これを実行することで、UnassociateHWndされるまでControlがGC対象にならなくなると共に、
404 FromHWndでウィンドウハンドルからControlインスタンスの取得が可能となる。
405 */
406 Sub AssociateHWnd(hwnd As HWND)
407 This.hwnd = hwnd
408 This.Prop[PropertyInstance] = ObjPtr(This) As HANDLE
409 comImpl.AddRef()
410 End Sub
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()
434 comImpl.Release()
435 End Sub
436
437' Static Const WM_CONTROL_INVOKE = WM_USER + 0 As DWord
438' Static Const WM_CONTROL_BEGININVOKE = WM_USER + 1 As DWord
439
440'--------------------------------
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'--------------------------------
451' その他の補助関数
452Private
453 Function trackMouseEvent(flags As DWord) As BOOL
454 If pTrackMouseEvent <> 0 Then
455 Dim tme As TRACKMOUSEEVENT
456 With tme
457 .cbSize = Len(tme)
458 .dwFlags = flags
459 .hwndTrack = hwnd
460 .dwHoverTime = HOVER_DEFAULT
461 End With
462 trackMouseEvent = pTrackMouseEvent(tme)
463 End If
464 End Function
465
466'--------------------------------
467' 初期化終了関連(特にウィンドウクラス)
468Private
469 'ウィンドウ作成時にウィンドウプロシージャへThisを伝えるためのもの
470 Static tlsIndex As DWord
471
472 Static hInstance As HINSTANCE
473 Static atom As ATOM
474 Static hmodComctl As HMODULE
475 Static pTrackMouseEvent As Detail.PTrackMouseEvent
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
483 hmodComctl = LoadLibrary("comctl32.dll")
484 pTrackMouseEvent = GetProcAddress(hmodComctl, ToMBStr("_TrackMouseEvent")) As Detail.PTrackMouseEvent
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()
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
521 If hmodComctl <> 0 Then
522 FreeLibrary(hmodComctl)
523 End If
524 If PropertyInstance <> 0 Then
525 GlobalDeleteAtom(PropertyInstance)
526 End If
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.