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

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

Controlをデリゲートベースにした。DictionaryのContainsKeyとTryGetValueを実装。デリゲートの追加・削除の右辺にNothingを指定可能にした。

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