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