Ignore:
Timestamp:
Aug 24, 2008, 5:28:59 PM (16 years ago)
Author:
イグトランス (egtra)
Message:

サブクラス化機構(Control.Attach)の整備

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ab5.0/ablib/src/Classes/ActiveBasic/Windows/UI/Control.ab

    r604 r615  
    1212End Namespace
    1313
     14/*
     15@brief Windowsのウィンドウを管理する基底クラス
     16@auther Egtra
     17*/
    1418Class Control
    1519    Inherits WindowHandle
     
    2428    Sub Control()
    2529        comImpl = New COM.ComClassDelegationImpl(This)
    26     End Sub
    27 
    28     Virtual Sub ~Control()
    2930    End Sub
    3031
     
    5253'--------------------------------
    5354' ウィンドウ作成
    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
    6155
    6256Public
     
    108102        CreateEx(parent, style Or WS_CHILD Or WS_VISIBLE, exStyle, id As ULONG_PTR As HMENU)
    109103    End Sub
     104
    110105Protected
    111106    Abstract Sub GetCreateStruct(ByRef cs As CREATESTRUCT)
    112107
    113108    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
     109        throwIfAlreadyCreated()
    117110
    118111        StartWndProc()
     
    123116                .x, .y, .cx, .cy, .hwndParent, .hMenu, .hInstance, .lpCreateParams)
    124117            If hwnd = 0 Then
    125                 ActiveBasic.Windows.ThrowWithLastError()
     118                ThrowWithLastErrorNT("Control.CreateEx")
    126119            End If
    127120           
     
    134127        If IsNothing(parent) = False Then
    135128            RegisterUnassociateHWnd(parent)
     129        End If
     130    End Sub
     131
     132Public
     133    Sub Attach(hwndNew As HWND)
     134        throwIfAlreadyCreated()
     135        If hwndNew = 0 Then
     136            Throw New System.ArgumentNullException("Control.Attach")
     137        End If
     138        registerStandardEvent()
     139        AssociateHWnd(hwndNew)
     140        prevWndProc = SetWindowLongPtr(GWLP_WNDPROC, AddressOf(WndProcFirst) As LONG_PTR) As WNDPROC
     141    End Sub
     142
     143Private
     144    Sub throwIfAlreadyCreated()
     145        If hwnd <> 0 Then
     146            Throw New System.InvalidOperationException("Window already created.")
    136147        End If
    137148    End Sub
     
    148159                Dim a = New MessageArgs(hwnd, msg, wp, lp)
    149160                h(This, a)
    150                 WndProc = a.LResult
    151                 Exit Function
     161                If a.Handled Then
     162                    WndProc = a.LResult
     163                    Exit Function
     164                End If
    152165            End If
    153166        End If
     
    156169
    157170    Virtual Function DefWndProc(msg As DWord, wp As WPARAM, lp As LPARAM) As LRESULT
    158         DefWndProc = DefWindowProc(hwnd, msg, wp, lp)
     171        If prevWndProc Then
     172            DefWndProc = CallWindowProc(prevWndProc, hwnd, msg, wp, lp)
     173        Else
     174            DefWndProc = DefWindowProc(hwnd, msg, wp, lp)
     175        End If
    159176    End Function
    160177
     
    219236
    220237    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
     238        Dim a = New PaintBackgroundArgs(e.WParam, e.LParam)
     239        e.Handled = e.Handled And OnPaintBackground(a)
     240        e.LResult = a.Painted
    228241    End Sub
    229242
    230243    Sub OnMouseDownBase(sender As Object, e As MessageArgs)
    231         OnMouseDown(makeMouseEventFromMsg(e))
     244        e.Handled = e.Handled And OnMouseDown(makeMouseEventFromMsg(e))
    232245    End Sub
    233246
     
    240253            doubleClickFired = False
    241254        End If
    242         OnMouseUp(me)
     255        e.Handled = e.Handled And OnMouseUp(me)
    243256    End Sub
    244257
     
    248261        OnMouseDown(me)
    249262        OnDoubleClick(Args.Empty)
    250         OnMouseDoubleClick(me)
     263        e.Handled = e.Handled And OnMouseDoubleClick(me)
    251264    End Sub
    252265
     
    258271            trackMouseEvent(TME_LEAVE Or TME_HOVER)
    259272        End If
    260         OnMouseMove(me)
     273        e.Handled = e.Handled And OnMouseMove(me)
    261274    End Sub
    262275
    263276    Sub OnMouseLeaveBase(sender As Object, e As MessageArgs)
    264         OnMouseLeave(Args.Empty)
     277        e.Handled = e.Handled And OnMouseLeave(Args.Empty)
    265278        mouseEntered = False
    266279    End Sub
     
    268281    Sub OnMouseHoverBase(sender As Object, e As MessageArgs)
    269282        Dim me = makeMouseEventFromMsg(e)
    270         OnMouseHover(me)
     283        e.Handled = e.Handled And OnMouseHover(me)
    271284    End Sub
    272285
    273286    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
     287        If ActiveBasic.IsNothing(paintDC) Then
     288            e.Handled = False
     289        Else
     290            Dim ps As PAINTSTRUCT
     291            BeginPaint(ps)
     292            Try
     293                OnPaintDC(New PaintDCArgs(ps.hdc, ps.rcPaint))
     294            Finally
     295                EndPaint(ps)
     296            End Try
     297        End If
    281298    End Sub
    282299
    283300    Sub OnKeyDownBase(sender As Object, e As MessageArgs)
    284         OnKeyDown(New KeyArgs(makeKeysFormMsg(e)))
     301        e.Handled = e.Handled And OnKeyDown(New KeyArgs(makeKeysFormMsg(e)))
    285302    End Sub
    286303
    287304    Sub OnKeyUpBase(sender As Object, e As MessageArgs)
    288         OnKeyUp(New KeyArgs(makeKeysFormMsg(e)))
     305        e.Handled = e.Handled And OnKeyUp(New KeyArgs(makeKeysFormMsg(e)))
    289306    End Sub
    290307
    291308    Sub OnChar(sender As Object, e As MessageArgs)
    292         OnKeyPress(New KeyPressArgs(e.WParam As Char))
     309        e.Handled = e.Handled And OnKeyPress(New KeyPressArgs(e.WParam As Char))
    293310    End Sub
    294311
    295312    Sub OnCreateBase(sender As Object, e As MessageArgs)
    296         OnCreate(New CreateArgs(e.LParam As *CREATESTRUCT))
     313        e.Handled = e.Handled And OnCreate(New CreateArgs(e.LParam As *CREATESTRUCT))
    297314    End Sub
    298315
    299316    Sub OnSize(sender As Object, e As MessageArgs)
    300         OnResize(New ResizeArgs(e.WParam, e.LParam))
     317        e.Handled = e.Handled And OnResize(New ResizeArgs(e.WParam, e.LParam))
    301318    End Sub
    302319
     
    352369Private
    353370    /*!
     371    @brief  サブクラス化前のウィンドウプロシージャ
     372    @date   2008/08/23
     373    サブクラス化していなければNULL
     374    */
     375    prevWndProc As WNDPROC
     376    /*!
    354377    @brief マウスカーソルがクライアント領域に入っているかどうかのフラグ
    355378    外から中に入ってきたときにMouseEnterイベントを発生させるために用意している。
     
    381404        If msg = WM_NCDESTROY Then
    382405            rThis.UnassociateHWnd()
     406            rThis.hwnd = 0
    383407        End If
    384408        If msg = WM_DESTROY And IsNothing(rThis.finalDestroy) = False Then
    385409            Dim f = rThis.finalDestroy
    386410            f(rThis, Args.Empty)
    387 '           finalDestroy(This, Args.Empty)
    388411        End If
    389412        WndProcFirst = rThis.WndProc(msg, wp, lp)
     
    391414
    392415    *InstanceIsNotFound
    393         Dim err = "ActiveBasic.Windows.UI.Control.WndProcFirst: The attached instance is not found. msg = &h" _
    394             + Hex$(msg) + Ex"\r\n"
     416        Dim err = String.Concat("Control.WndProcFirst: The attached instance is not found. msg = &h",
     417            Hex$(msg), Ex"\r\n")
    395418        OutputDebugString(ToTCStr(err))
    396419        WndProcFirst = DefWindowProc(hwnd, msg, wp, lp)
     
    399422    /*!
    400423    @brief  Controlインスタンスとウィンドウハンドルを結び付ける。
    401     @param[in] hwnd 結び付けるウィンドウハンドル
     424    @param[in] hwndNew  結び付けるウィンドウハンドル
    402425    @date   2008/07/16
    403426    これを実行することで、UnassociateHWndされるまでControlがGC対象にならなくなると共に、
    404427    FromHWndでウィンドウハンドルからControlインスタンスの取得が可能となる。
    405428    */
    406     Sub AssociateHWnd(hwnd As HWND)
    407         This.hwnd = hwnd
    408         This.Prop[PropertyInstance] = ObjPtr(This) As HANDLE
     429    Sub AssociateHWnd(hwndNew As HWND)
     430        hwnd = hwndNew
     431        Prop[PropertyInstance] = ObjPtr(This) As HANDLE
    409432        comImpl.AddRef()
    410433    End Sub
     
    429452    Sub UnassociateHWndOnEvent(sender As Object, e As Args)
    430453        UnassociateHWnd()
     454        hwnd = 0
    431455    End Sub
    432456
     
    447471
    448472Private
     473    /*!
     474    @brief ウィンドウの寿命管理
     475    Controlには次のAddRef-Releaseの対がある。
     476    @li createImpl - WM_NCDESTROY(ウィンドウプロシージャがWndProcFirstの場合)
     477    @li createImpl - UnassociateHWnd←UnassociateHWndOnEvent←RegisterUnassociateHWnd(その他のウィンドウクラスの場合)
     478    @li Attach - WM_NCDESTROY(サブクラス化された場合)
     479    なお、Control派生クラスをサブクラス化すると、後ろ2つが両方適用される。
     480    */
    449481    comImpl As COM.ComClassDelegationImpl
     482
    450483'--------------------------------
    451484'   その他の補助関数
     
    526559        End If
    527560    End Sub
    528 
    529561End Class
    530562
Note: See TracChangeset for help on using the changeset viewer.