source: Include/Classes/System/Windows/Forms/Control.ab@ 240

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

Control周りの修正

File size: 15.9 KB
RevLine 
[77]1' Classes/System/Windows/Forms/Control.ab
2
3#ifndef __SYSTEM_WINDOWS_FORMS_CONTROL_AB__
4#define __SYSTEM_WINDOWS_FORMS_CONTROL_AB__
5
[223]6#require <windows/WindowHandle.sbp>
7#require <Classes/System/Windows/Forms/misc.ab>
8#require <Classes/System/Windows/Forms/CreateParams.ab>
9#require <Classes/System/Windows/Forms/Message.ab>
10#require <Classes/System/Windows/Forms/PaintEventArgs.ab>
11#require <Classes/System/misc.ab>
12#require <Classes/System/Math.ab>
13#require <Classes/System/Threading/WaitHandle.ab>
14#require <Classes/System/Drawing/Color.ab>
15#require <Classes/System/Drawing/Point.ab>
16#require <Classes/System/Drawing/Size.ab>
17#require <Classes/System/Drawing/Rectangle.ab>
18#require <Classes/System/Runtime/InteropServices/GCHandle.ab>
[77]19
[223]20TypeDef InvokeProc = *Function(p As VoidPtr) As VoidPtr
21
[77]22Class AsyncResultForInvoke
23 Inherits IAsyncResult
24Public
25 ' Properties
26 Sub AsyncResultForInvoke(h As HANDLE)
27 waitHandle.Handle = h
28 End Sub
29
[240]30 Override Function AsyncState() As Object
[223]31 Return Nothing
[77]32 End Function
33
[223]34 Override Function AsyncWaitHandle() As WaitHandle
35 Return waitHandle
[77]36 End Function
37
[240]38 Override Function CompletedSynchronously() As Boolean
[77]39 Return FALSE
40 End Function
41
[240]42 Override Function IsCompleted() As Boolean
43 Return waitHandle.WaitOne(0, False)
[77]44 End Function
45
46 Const Function Result() As VoidPtr
47 Return result
48 End Function
49
50 Sub Result(r As VoidPtr)
51 result = r
52 End Sub
53
54Private
55 waitHandle As WaitHandle
56 result As VoidPtr
57End Class
58
59Class AsyncInvokeData
60Public
[223]61 FuncPtr As InvokeProc
[77]62 Data As *VoidPtr
[223]63 AsyncResult As AsyncResultForInvoke
[77]64End Class
65
66Class Control
[223]67' Inherits IWin32Window
[77]68Public
[132]69 '---------------------------------------------------------------------------
70 ' Public Properties
[223]71 Function AllowDrop() As Boolean
[77]72 End Function
73
[223]74 /*Override*/ Function Handle() As HWND
[77]75 Return wnd.HWnd
76 End Function
77
78 ' IDropTargetを実装するのでDragAcceptFiles関数は呼ばない。
[223]79 Sub AllowDrop(a As Boolean)
[77]80 End Sub
81
[223]82 Const Function Visible() As Boolean
[77]83 Return wnd.Visible
84 End Function
85
[223]86 Sub Visible(v As Boolean)
[77]87 wnd.Visible(v)
88 End Sub
89
90 Const Function Text() As String
91 Return text
92 End Function
93
[240]94 Sub Text(t As String)
[77]95 text = t
96 Dim e As EventArgs
97 OnTextChanged(e)
98 End Sub
99
[223]100 Const Function Enabled() As Boolean
[77]101 Return wnd.Enabled
102 End Function
103
[223]104 Sub Enabled(e As Boolean)
[77]105 ' OnEnabledChangedはWM_ENABLE経由で呼ばれる
106 wnd.Enabled(e)
107 End Sub
108
109 Const Function Bounds() As Rectangle
110 Dim wr As RECT
111 wr = wnd.WindowRect
[223]112 Dim r = New Rectangle(wr)
[77]113 Dim parent = Parent
[223]114 If Object.ReferenceEquals(parent, Nothing) Then
[77]115 Return parent->RectangleToClient(r)
116 Else
117 Return r
118 End If
119 End Function
120
[223]121 Sub Bounds(r As Rectangle)
[77]122 SetBoundsCore(r.X, r.Y, r.Width, r.Height, BoundsSpecified.All)
123 End Sub
124
125 Const Function Location() As Point
126 Return Bounds.Location
127 End Function
128
129 Sub Location(p As Point)
130 SetBoundsCore(p.X, p.Y, 0, 0, BoundsSpecified.Location)
131 End Sub
132
133 Const Function Size() As Size
134 Return Bounds.Size
135 End Function
136
137 Sub Size(s As Size)
138 SetBoundsCore(0, 0, s.Width, s.Height, BoundsSpecified.Size)
139 End Sub
140
141 Const Function ClientRectangle() As Rectangle
[223]142 Return New Rectangle(wnd.ClientRect)
[77]143 End Function
144
145 Const Function ClientSize() As Size
146 Return ClientRectangle.Size
147 End Function
148
149 Const Function Left() As Long
150 Dim b = Bounds
151 Return b.Left
152 End Function
153
154 Sub Left(l As Long)
155 SetBoundsCore(l, 0, 0, 0, BoundsSpecified.X)
156 End Sub
157
158 Const Function Top() As Long
159 Dim b = Bounds
160 Return b.Top
161 End Function
162
163 Sub Top(t As Long)
164 SetBoundsCore(0, t, 0, 0, BoundsSpecified.Y)
165 End Sub
166
167 Const Function Width() As Long
168 Dim b = Bounds
169 Return b.Width
170 End Function
171
172 Sub Width(w As Long)
173 SetBoundsCore(0, 0, w, 0, BoundsSpecified.Width)
174 End Sub
175
176 Const Function Height() As Long
177 Dim b = Bounds
178 Return b.Height
179 End Function
180
181 Sub Height(h As Long)
182 SetBoundsCore(0, 0, 0, h, BoundsSpecified.Height)
183 End Sub
184
185 Const Function Right() As Long
[240]186 Dim b = Bounds
187 Return b.Left + b.Width
[77]188 End Function
189
190 Const Function Bottom() As Long
[240]191 Dim b = Bounds
192 Return b.Top + b.Height
[77]193 End Function
194
195 Const Function PointToScreen(p As Point) As Point
[223]196 PointToScreen = New Point
197 ret.X = p.X
198 ret.Y = p.Y
199 wnd.ClientToScreen(ByVal VarPtr(PointToScreen) As *POINTAPI)
[77]200 End Function
201
202 Const Function PointToClient(p As Point) As Point
[223]203 PointToScreen = New Point
204 ret.X = p.X
205 ret.Y = p.Y
206 wnd.ScreenToClient(ByVal VarPtr(PointToScreen) As *POINTAPI)
[77]207 End Function
208
[223]209 Const Function RectangleToScreen(r As Rectangle) As Rectangle
210 Dim rc = r.ToRECT
211 wnd.ClientToScreen(rc)
212 Return New Rectangle(rc)
[77]213 End Function
214
[223]215 Const Function RectangleToClient(r As Rectangle) As Rectangle
216 Dim rc As RECT
217 rc = r.ToRECT()
218 wnd.ScreenToClient(rc)
219 Return New Rectangle(rc)
[77]220 End Function
221
[223]222 Const Function InvokeRequired() As Boolean
[77]223 Return wnd.ThreadID <> GetCurrentThreadId()
224 End Function
225
226 Const Virtual Function BackColor() As Color
227 Return bkColor
228 End Function
229
230 Virtual Sub BackColor(c As Color)
231 c = bkColor
232 Dim e As EventArgs
233 OnBackColorChanged(e)
234 End Sub
235
[223]236 Function Parent() As Control
[132]237 Return parent
238 End Function
239
[223]240 Const Function IsHandleCreated() As Boolean
241 Return wnd.HWnd <> 0
242 End Function
243
[132]244 Static Function DefaultBackColor() As Color
245 Return Color.FromArgb(255, 255, 255)
246 End Function
247
248 '---------------------------------------------------------------------------
[77]249 ' Constractors
250
251 Sub Control()
252 Dim sz = DefaultSize()
253 Control("", 100, 100, sz.Width, sz.Height)
254 End Sub
255
[223]256 Sub Control(text As String)
[77]257 Dim sz = DefaultSize()
258 Control(text, 100, 100, sz.Width, sz.Height)
259 End Sub
260
[223]261 Sub Control(parent As Control, text As String)
[77]262 Dim sz = DefaultSize()
263 Control(parent, text, 100, 100, sz.Width, sz.Height)
264 End Sub
265
[223]266 Sub Control(text As String, left As Long, top As Long, width As Long, height As Long)
[77]267 This.text = text
268 bkColor = DefaultBackColor
269 End Sub
270
[223]271 Sub Control(parent As Control, text As String, left As Long, top As Long, width As Long, height As Long)
[77]272 This.parent = VarPtr(parent)
273 Control(text, left, top, width, height)
274 End Sub
275
[132]276 '---------------------------------------------------------------------------
[77]277 ' Destractor
278
279 Virtual Sub ~Control()
[240]280 If Not Object.ReferenceEquals(wnd, Nothing) Then
281 If wnd.IsWindow Then
282 wnd.Destroy() ' 暫定
283 End If
[77]284 End If
285 End Sub
286
[132]287 '---------------------------------------------------------------------------
288 ' Public Methods
[77]289
290 ' 同期関数呼出、Controlが作成されたスレッドで関数を実行する。
291 ' 関数は同期的に呼び出されるので、関数が終わるまでInvokeは制御を戻さない。
[223]292 Function Invoke(pfn As InvokeProc, p As VoidPtr) As VoidPtr
[77]293 Return wnd.SendMessage(WM_CONTROL_INVOKE, p As WPARAM, pfn As LPARAM) As VoidPtr
294 End Function
295
296 ' 非同期関数呼出、Controlが作成されたスレッドで関数を実行する。
297 ' 関数は非同期的に呼び出されるので、BeginInvokeはすぐに制御を戻す。
298 ' 後にEndInvokeを呼び出すことにより、関数の戻り値を受け取れる。
[223]299 Function BeginInvoke(pfn As InvokeProc, p As VoidPtr) As IAsyncResult
[77]300 ' EndInvokeがDeleteする
[223]301 Dim asyncResult = New AsyncResultForInvoke(CreateEvent(0, FALSE, FALSE, 0))
[77]302 ' OnControlBeginInvokeがDeleteする
[223]303 Dim asyncInvokeData = New AsyncInvokeData
304 With asyncInvokeData
[77]305 .FuncPtr = pfn
306 .Data = p
[223]307 .AsyncResult = asyncResult
[77]308 End With
[223]309 Dim gch = GCHandle.Alloc(asyncInvokeData)
310 wnd.PostMessage(WM_CONTROL_BEGININVOKE, 0, GCHandle.ToIntPtr(gch))
[77]311 Return pAsyncResult
312 End Function
313
314 ' BeginInvokeで呼び出した関数の戻り値を受け取る。
315 ' その関数がまだ終了していない場合、終了するまで待機する。
[223]316 Function EndInvoke(ar As IAsyncResult) As VoidPtr
317 ar.WaitHandle.WaitOne()
318 Dim arInvoke = ar As AsyncResultForInvoke
319 Return arInvoke.Result
[77]320 End Function
321
322 ' 与えられたウィンドウハンドルがControl(若しくはその派生クラス)の
323 ' インスタンスに対応するものであった場合、
[223]324 ' 元のインスタンスを返す。
325 ' そうでなければNothingを返す。
326 Static Function FromHandle(hwnd As HWND) As Control
[77]327 If IsWindow(hwnd) Then
[223]328 If GetClassLongPtr(hwnd, GCW_ATOM) = atom Then
329 Dim gch = GCHandle.FromIntPtr(GetWindowLongPtr(hwnd, GWLP_THIS))
330 Return gch.Target As Control
[77]331 End If
332 End If
[223]333 Return Nothing As Control
[77]334 End Function
335
336 Virtual Sub ResetText()
337 text = ""
338 End Sub
339
[223]340 Override Function ToString() As String
[77]341 Return text
342 End Function
343
344 ' Wrapper Methods
345 Sub BringToFront()
346 wnd.BringToTop()
347 End Sub
348
349 Sub Hide()
350 wnd.Show(SW_HIDE)
351 End Sub
352
353 Sub Show()
354 wnd.Show(SW_SHOW)
355 End Sub
356
357 Sub Update()
358 wnd.Update()
359 End Sub
360
[240]361 Sub CreateControl()
362 CreateHandle() '暫定
363 End Sub
364
[77]365Protected
[240]366
[132]367 '---------------------------------------------------------------------------
368 ' Protected Properties
[223]369' Const Virtual Function CanRaiseEvents() As Boolean
370 Virtual Function CreateParams() As CreateParams
371 Return createParams
[77]372 End Function
373' Virtual Function DefaultCursor() As Cursor
374
375 Virtual Function DefaultSize() As Size
376 Dim s As Size(300, 300)
377 Return s
378 End Function
379
380' Function FontHeight() As Long
381' Sub FontHeight(h As Long)
382
383' Const Virtual Function Cursor() As Cursor
[240]384' Virtual Sub Cursor(c As Cursor)
[77]385
[132]386 '---------------------------------------------------------------------------
387 ' Protected Methods
[77]388 Virtual Sub CreateHandle()
389 Dim createParams = CreateParams()
[223]390 Dim gch = GCHandle.Alloc(This)
391 TlsSetValue(tlsIndex, GCHandle.ToIntPtr(gch) As VoidPtr)
[240]392 With createParams
[77]393 Dim hwndParent = 0 As HWND
[223]394 If Not Object.ReferenceEquals(parent, Nothing) Then
395 hwndParent = parent.Handle
[77]396 End If
[240]397 Dim pText As PCTSTR
398 If String.IsNullOrEmpty(text) Then
399 pText = "" As PCTSTR
400 Else
401 pText = ToTCStr(text)
402 End If
403
404 If CreateWindowEx(.ExStyle, atom As ULONG_PTR As PCSTR, pText, .Style, _
[77]405 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, _
406 hwndParent, 0, hInstance, 0) = 0 Then
407 ' Error
[223]408 Dim buf[1023] As TCHAR
409 wsprintf(buf, ToTCStr(Ex"Control: CreateWindowEx failed. Error code: &h%08X\r\n"), GetLastError())
[77]410 OutputDebugString(buf)
411' Debug
412 ExitThread(0)
413 End If
414 End With
[223]415 gch.Free()
[77]416 End Sub
417
[223]418 Virtual Sub DefWndProc(m As Message)
[77]419 m.Result = DefWindowProc(m.HWnd, m.Msg, m.WParam, m.LParam)
420 End Sub
421
[223]422 Virtual Sub WndProc(m As Message)
[77]423 With m
424 Select Case .Msg
425 Case WM_GETTEXTLENGTH
426 .Result = text.Length
427 Case WM_GETTEXT
[223]428 Dim size = Math.Min(.WParam As ULONG_PTR, (text.Length + 1) As ULONG_PTR)
429 memcpy(.LParam As PCTSTR, ToTCStr(text), size * SizeOf (TCHAR))
[77]430 .Result = size
431 Case WM_SETTEXT
[223]432 text = New String(.LParam As PCTSTR)
[77]433 Case WM_ENABLE
[223]434 OnEnabledChanged(EventArgs.Empty)
[77]435 Case WM_ERASEBKGND
436 ' OnPaintBackgroundに移すべき
[132]437 Dim hdc = .WParam As HDC
[77]438 Dim hbr = CreateSolidBrush(bkColor.ToCOLORREF())
439 Dim hbrOld = SelectObject(hdc, hbr)
[132]440 Dim rc = wnd.ClientRect
[77]441 Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom)
442 SelectObject(hdc, hbrOld)
443 DeleteObject(hbr)
444 Case WM_CONTROL_INVOKE
[223]445 Dim pfn = .LParam As InvokeProc
[77]446 .Result = pfn(m.WParam As VoidPtr) As LRESULT
447 Case WM_CONTROL_BEGININVOKE
448 OnControlBeginInvoke(m)
[223]449 Case WM_CREATE
450 OnHandleCreated(EventArgs.Empty)
[240]451 Case WM_DESTROY
452 OnHandleDestroyed(EventArgs.Empty)
[77]453 Case Else
454 DefWndProc(m)
455 End Select
456 End With
457 End Sub
458
459 Virtual Sub SetClientSizeCore(x As Long, y As Long)
460 Dim rc As RECT
461 With rc
462 .left = 0
463 .top = 0
464 .right = x
465 .bottom = y
466 End With
467 Dim hasMenu = FALSE As BOOL
468 If wnd.Parent As HWND = 0 Then
469 If wnd.Menu <> 0 Then
470 hasMenu = TRUE
471 End If
472 End If
473 AdjustWindowRectEx(rc, wnd.Style, hasMenu, wnd.ExStyle)
474 wnd.Move(rc)
475 End Sub
476
477 Virtual Sub SetBoundsCore(x As Long, y As Long, width As Long, height As Long, bs As BoundsSpecified)
[223]478' If Not (bs As DWord And BoundsSpecified.X As DWord) Then
[77]479 x = Left
[223]480' End If
481' If Not (bs As DWord And BoundsSpecified.Y As DWord) Then
[77]482 y = Right
[223]483' End If
484' If Not (bs As DWord And BoundsSpecified.Width As DWord) Then
[77]485 width = Width
[223]486' End If
487' If Not (bs As DWord And BoundsSpecified.Height As DWord) Then
[77]488 height = Height
[223]489' End If
[77]490 wnd.Move(x, y, width, height)
491 End Sub
492
493 Virtual Sub NotifyInvalidate(r As Rectangle)
494 Dim rc As RECT
495 rc = r.ToRECT()
496 wnd.InvalidateRect(rc)
497 End Sub
498
[223]499 Virtual Sub OnPaintBackground(e As PaintEventArgs) : End Sub
500 Virtual Sub OnEnabledChanged(e As EventArgs) : End Sub
501 Virtual Sub OnBackColorChanged(e As EventArgs) : End Sub
502 Virtual Sub OnHandleCreated(e As EventArgs) : End Sub
[240]503 Virtual Sub OnHandleDestroyed(e As EventArgs) : End Sub
[223]504 Virtual Sub OnTextChanged(e As EventArgs)
505 wnd.SetText(ToTCStr(text))
[77]506 End Sub
507
508Private
509 ' Member variables
510 wnd As WindowHandle
511 text As String
[223]512 parent As Control
[77]513 bkColor As Color
514
515 Static createParams As CreateParams
516
517 'ウィンドウ作成時にウィンドウプロシージャへThisを伝えるためのもの
518 Static tlsIndex As DWord
519
520 Static hInstance As HINSTANCE
521 Static atom As ATOM
522
523 Static Const WM_CONTROL_INVOKE = WM_USER + 0 As DWord
524 Static Const WM_CONTROL_BEGININVOKE = WM_USER + 1 As DWord
525
[223]526 Static Const WindowClassName = "ActiveBasic Control"
[77]527Public
528 Static Sub Initialize(hinst As HINSTANCE)
529 tlsIndex = TlsAlloc()
530 hInstance = hinst
531
532 Dim wcx As WNDCLASSEX
533 With wcx
534 .cbSize = Len (wcx)
535 .style = CS_HREDRAW Or CS_VREDRAW Or CS_DBLCLKS
536 .lpfnWndProc = AddressOf (WndProcFirst)
537 .cbClsExtra = 0
538 .cbWndExtra = SizeOf (LONG_PTR) * 2
539 .hInstance = hinst
540 .hIcon = 0
541 .hCursor = LoadImage(0, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE Or LR_SHARED) As HCURSOR
542 .hbrBackground = 0
543 .lpszMenuName = 0
[240]544 .lpszClassName = ToTCStr(WindowClassName)
[77]545 .hIconSm = 0
546 End With
547 atom = RegisterClassEx(wcx)
548 If atom = 0 Then
[223]549 Dim buf[1023] As TCHAR
550 wsprintf(buf, ToTCStr(Ex"Control: RegisterClasseEx failed. Error code: &h%08X\r\n"), GetLastError())
[77]551 OutputDebugString(buf)
552 Debug
553 ExitThread(0)
554 End If
555
556 With createParams
557 ' 値は暫定的なもの
558 .Style = WS_OVERLAPPEDWINDOW
559 .ExStyle = WS_EX_APPWINDOW
560 End With
561 End Sub
562
563 Static Sub Uninitialize()
564 UnregisterClass(atom As ULONG_PTR As PCSTR, hInstance)
565 TlsFree(tlsIndex)
566 End Sub
567Private
568 Static Const GWLP_THIS = SizeOf (LONG_PTR) * 0 As Long
569 Static Const GWLP_TAG = SizeOf (LONG_PTR) * 1 As Long
570
571 ' Windowsから呼ばれるウィンドウプロシージャ。WndProc
572 Static Function WndProcFirst(hwnd As HWND, msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
[223]573 Dim rThis = Control.FromHandle(hwnd) As Control
574 If Object.ReferenceEquals(rThis As Object, Nothing) Then
575 Dim gchValue = TlsGetValue(tlsIndex) As LONG_PTR
576 Dim gch = GCHandle.FromIntPtr(gchValue)
577 rThis = gch.Target As Control
[77]578 ' ウィンドウが作られて最初にWndProcFirstが呼ばれたとき
[223]579 If Object.ReferenceEquals(rThis, Nothing) Then
[77]580 ' あってはならない事態
581 Debug
[240]582 ExitThread(-1)
[77]583 End If
[223]584 rThis.wnd = New WindowHandle(hwnd)
585 SetWindowLongPtr(hwnd, GWLP_THIS, gchValue)
[77]586 End If
[240]587
588 Dim m = Message.Create(hwnd, msg, wp, lp)
[223]589 rThis.WndProc(m)
[77]590 Return m.Result
591 End Function
592
593 ' BeginInvokeが呼ばれたときの処理
[223]594 Sub OnControlBeginInvoke(m As Message)
595 Dim gch = GCHandle.FromIntPtr(m.LParam)
596 Dim data = gch.Target As AsyncInvokeData
597 With data
598 Dim pfn = .FuncPtr
599 .AsyncResult.Result = pfn(.Data)
600 SetEvent(.AsyncResult.AsyncWaitHandle.Handle)
601 End With
[77]602 End Sub
603End Class
604
605Class _System_ControlIinitializer
606Public
607 Sub _System_ControlIinitializer(hinst As HINSTANCE)
608 Control.Initialize(hinst)
609 End Sub
610
611 Sub ~_System_ControlIinitializer()
612 Control.Uninitialize()
613 End Sub
614End Class
615
616#ifndef _SYSTEM_NO_INITIALIZE_CONTROL_
617Dim _System_ControlInitializer As _System_ControlIinitializer(GetModuleHandle(0))
618#endif '_SYSTEM_NO_INITIALIZE_CONTROL_
619
620#endif '__SYSTEM_WINDOWS_FORMS_CONTROL_AB__
[240]621
Note: See TracBrowser for help on using the repository browser.