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

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

EditBox, TaskMsgの追加。

File size: 13.7 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 = 0
68 .y = 0
69 .cx = 0
70 .cy = 0
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 AddMessageEvent(WM_SIZE, AddressOf(OnSize))
190 End Sub
191
192 Sub OnEraseBackground(sender As Object, e As MessageArgs)
193 Dim rc = ClientRect
194 FillRect(e.WParam As HDC, rc, (COLOR_3DFACE + 1) As HBRUSH)
195 e.LResult = TRUE
196 End Sub
197
198 Sub OnMouseDownBase(sender As Object, e As MessageArgs)
199 OnMouseDown(makeMouseEventFromMsg(e))
200 End Sub
201
202 Sub OnMouseUpBase(sender As Object, e As MessageArgs)
203 Dim me = makeMouseEventFromMsg(e)
204 If doubleClickFired = False Then
205 OnClick(Args.Empty)
206 OnMouseClick(me)
207 doubleClickFired = False
208 End If
209 OnMouseUp(me)
210 End Sub
211
212 Sub OnMouseDblClkBase(sender As Object, e As MessageArgs)
213 Dim me = makeMouseEventFromMsg(e)
214 doubleClickFired = True
215 OnMouseDown(me)
216 OnDoubleClick(Args.Empty)
217 OnMouseDoubleClick(me)
218 End Sub
219
220 Sub OnMouseMoveBase(sender As Object, e As MessageArgs)
221 Dim me = makeMouseEventFromMsg(e)
222 If mouseEntered Then
223 OnMouseMove(me)
224 Else
225 mouseEntered = True
226 OnMouseEnter(me)
227 End If
228 End Sub
229
230 Sub OnMouseLeaveBase(sender As Object, e As MessageArgs)
231 Dim me = makeMouseEventFromMsg(e)
232 OnMouseLeave(me)
233 mouseEntered = False
234 End Sub
235
236 Sub OnPaintBase(sender As Object, e As MessageArgs)
237 Dim ps As PAINTSTRUCT
238 BeginPaint(ps)
239 Try
240 OnPaintDC(New PaintDCArgs(ps.hdc, ps.rcPaint))
241 Finally
242 EndPaint(ps)
243 End Try
244 End Sub
245
246 Sub OnKeyDownBase(sender As Object, e As MessageArgs)
247 OnKeyDown(New KeyArgs(makeKeysFormMsg(e)))
248 End Sub
249
250 Sub OnKeyUpBase(sender As Object, e As MessageArgs)
251 OnKeyUp(New KeyArgs(makeKeysFormMsg(e)))
252 End Sub
253
254 Sub OnChar(sender As Object, e As MessageArgs)
255 OnKeyPress(New KeyPressArgs(e.WParam As Char))
256 End Sub
257
258 Sub OnCreateBase(sender As Object, e As MessageArgs)
259 OnCreate(New CreateArgs(e.LParam As *CREATESTRUCT))
260 End Sub
261
262 Sub OnSize(sender As Object, e As MessageArgs)
263 OnResize(New ResizeArgs(e.WParam, e.LParam))
264 End Sub
265
266 messageMap As System.Collections.Generic.Dictionary<Object /*DWord*/, MessageHandler>
267
268Public
269 /*!
270 @biref メッセージイベントハンドラを登録する。
271 @date 2007/12/04
272 */
273 Sub AddMessageEvent(message As DWord, h As MessageHandler)
274 If Not IsNothing(h) Then
275 If IsNothing(messageMap) Then
276 messageMap = New System.Collections.Generic.Dictionary<Object, MessageHandler>
277 End If
278 Dim msg = Hex$(message)
279 Dim m = Nothing As MessageHandler
280 If messageMap.TryGetValue(msg, m) Then
281 messageMap.Item[msg] = m + h
282 Else
283 messageMap.Item[msg] = h
284 End If
285 End If
286 End Sub
287
288 /*!
289 @biref メッセージイベントハンドラ登録を解除する。
290 @date 2007/12/04
291 */
292 Sub RemoveMessageEvent(message As DWord, a As MessageHandler)
293 If Not IsNothing(a) Then
294 If Not IsNothing(messageMap) Then
295 Dim msg = Hex$(message)
296 Dim m = messageMap.Item[msg]
297 If Not IsNothing(m) Then
298 messageMap.Item[msg] = m - a
299 End If
300 End If
301 End If
302 End Sub
303
304'--------------------------------
305' ウィンドウメッセージ処理
306
307
308'--------
309'イベント
310
311#include "ControlEvent.sbp"
312
313'--------------------------------
314' インスタンスメンバ変数
315Private
316 /*!
317 @brief マウスカーソルがクライアント領域に入っているかどうかのフラグ
318 外から中に入ってきたときにMouseEnterイベントを発生させるために用意している。
319 */
320 mouseEntered As Boolean
321 /*!
322 @brief ダブルクリックが起こったかどうかのフラグ
323 Click/MouseClickイベントのために用意している。
324 @date 2008/07/12
325 */
326 doubleClickFired As Boolean
327
328'--------------------------------
329' 初期ウィンドウクラス
330Private
331 Static Function WndProcFirst(hwnd As HWND, msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
332 Imports System.Runtime.InteropServices
333
334 Dim rThis = FromHWndCore(hwnd)
335 If IsNothing(rThis) Then
336 Dim gchValue = TlsGetValue(tlsIndex) As LONG_PTR
337 TlsSetValue(tlsIndex, 0)
338 If gchValue = 0 Then
339 Goto *InstanceIsNotFound
340 End If
341 Dim gch = GCHandle.FromIntPtr(gchValue)
342 rThis = gch.Target As Control
343 ' ウィンドウが作られて最初にWndProcFirstが呼ばれたとき
344
345 AssociateHWnd(gch, hwnd)
346 End If
347 If msg = WM_NCDESTROY Then
348 rThis.UnassociateHWnd()
349 End If
350 If msg = WM_DESTROY And IsNothing(rThis.finalDestroy) = False Then
351 Dim f = rThis.finalDestroy
352 f(rThis, Args.Empty)
353' finalDestroy(This, Args.Empty)
354 End If
355 WndProcFirst = rThis.WndProc(msg, wp, lp)
356 Exit Function
357
358 *InstanceIsNotFound
359 Dim err = "ActiveBasic.Windows.UI.Control.WndProcFirst: The attached instance is not found. msg = &h" _
360 + Hex$(msg) + Ex"\r\n"
361 OutputDebugString(ToTCStr(err))
362 WndProcFirst = DefWindowProc(hwnd, msg, wp, lp)
363 End Function
364
365 /*!
366 @brief Controlインスタンスとウィンドウハンドルを結び付ける。
367 @param[in] 結び付けられるControlインスタンスを格納したGCHandle
368 @param[in] hwnd 結び付けるウィンドウハンドル
369 @date 2008/07/16
370 これを実行することで、UnassociateHWndされるまでControlがGC対象にならなくなる。
371 */
372 Static Sub AssociateHWnd(gch As System.Runtime.InteropServices.GCHandle, hwnd As HWND)
373 Imports System.Runtime.InteropServices
374 Dim rThis = gch.Target As Control
375 If IsNothing(rThis) Then
376 Exit Sub
377 End If
378 rThis.hwnd = hwnd
379 rThis.Prop[PropertyInstance] = GCHandle.ToIntPtr(gch) As HANDLE
380 End Sub
381
382 /*!
383 @brief オーナーの破棄時にこのControlインスタンスとウィンドウハンドルの結び付けを解除するよう登録する。
384 @param[in] owner 結び付けの解除を連動させるControl
385 @date 2008/07/16
386 ownerのFinalDestoryでこのControlとHWNDとの結び付けを解除する。
387 */
388 Sub RegisterUnassociateHWnd(owner As Control)
389 If IsNothing(owner) = False Then
390 Dim e = New Handler(AddressOf(UnassociateHWndOnEvent))
391 If IsNothing(finalDestroy) Then
392 owner.finalDestroy = e
393 Else
394 owner.finalDestroy += e
395 End If
396 End If
397 End Sub
398
399 Sub UnassociateHWndOnEvent(sender As Object, e As Args)
400 UnassociateHWnd()
401 End Sub
402
403 Sub UnassociateHWnd()
404 Imports System.Runtime.InteropServices
405 Dim gchValue = Prop(PropertyInstance) As ULONG_PTR
406 If gchValue <> 0 Then
407 GCHandle.FromIntPtr(gchValue).Free()
408 End If
409 End Sub
410
411' Static Const WM_CONTROL_INVOKE = WM_USER + 0 As DWord
412' Static Const WM_CONTROL_BEGININVOKE = WM_USER + 1 As DWord
413
414'--------------------------------
415' その他の補助関数
416Private
417' Sub tracMouseEvent()
418/* If pTrackMouseEvent <> 0 Then
419 Dim tme As TRACKMOUSEEVENT
420 With tme
421 .cbSize = Len(tme)
422 .dwFlags = TME_HOVER Or TME_LEAVE
423 .hwndTrack = wnd
424 .dwHoverTime = HOVER_DEFAULT
425 End With
426 pTrackMouseEvent(tme)
427 End If
428*/ 'End Sub
429
430'--------------------------------
431' 初期化終了関連(特にウィンドウクラス)
432Private
433 'ウィンドウ作成時にウィンドウプロシージャへThisを伝えるためのもの
434 Static tlsIndex As DWord
435
436 Static hInstance As HINSTANCE
437 Static atom As ATOM
438 Static hmodComctl As HMODULE
439' Static pTrackMouseEvent As PTrackMouseEvent
440
441 Static Const WindowClassName = "ActiveBasic.Windows.UI.Control"
442 Static Const PropertyInstance = 0 As ATOM
443Public
444 Static Sub Initialize(hinst As HINSTANCE)
445 tlsIndex = TlsAlloc()
446 hInstance = hinst
447' hmodComctl = LoadLibrary("comctl32.dll")
448' pTrackMouseEvent = GetProcAddress(hmodComctl, ToMBStr("_TrackMouseEvent"))
449
450 Dim PropertyInstanceString = WindowClassName + " " + Hex$(GetCurrentProcessId())
451 PropertyInstance = GlobalAddAtom(ToTCStr(PropertyInstanceString))
452
453 Dim wcx As WNDCLASSEX
454 With wcx
455 .cbSize = Len (wcx)
456 .style = CS_HREDRAW Or CS_VREDRAW Or CS_DBLCLKS
457 .lpfnWndProc = AddressOf (WndProcFirst)
458 .cbClsExtra = 0
459 .cbWndExtra = 0
460 .hInstance = hinst
461 .hIcon = 0
462 .hCursor = LoadImage(0, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE Or LR_SHARED) As HCURSOR
463 .hbrBackground = 0
464 .lpszMenuName = 0
465 .lpszClassName = ToTCStr(WindowClassName)
466 .hIconSm = 0
467 End With
468 atom = RegisterClassEx(wcx)
469 If atom = 0 Then
470 Dim buf[1023] As TCHAR
471 wsprintf(buf, Ex"ActiveBasic.Windows.UI.Control.Control: RegisterClasseEx failed. Error code: &h%08X\r\n", GetLastError())
472 OutputDebugString(buf)
473 Debug
474 ExitThread(0)
475 End If
476 End Sub
477
478 Static Sub Uninitialize()
479 If atom <> 0 Then
480 UnregisterClass(atom As ULONG_PTR As PCSTR, hInstance)
481 End If
482 If tlsIndex <> 0 And tlsIndex <> &hffffffff Then
483 TlsFree(tlsIndex)
484 End If
485' If hmodComctl <> 0 Then
486' FreeLibrary(hmodComctl)
487' End If
488 If PropertyInstance <> 0 Then
489 GlobalDeleteAtom(PropertyInstance)
490 End If
491 End Sub
492
493End Class
494
495End Namespace 'UI
496End Namespace 'Widnows
497End Namespace 'ActiveBasic
Note: See TracBrowser for help on using the repository browser.