Wiki Home

VFP Ole Control Visible Bug


Namespace: VFP
*
* Applies to: VFP 8 SP1, VFP7, presumably all versions up to, and including
* VFP 9 Public Beta 1720 (which is the latest at the time of this writing)
*
* This bug seems to be reproducible with any ActiveX control which has a
* visible element. The basic problem appears to be that VFP does not check
* container/forms's children for olecontrol instances which now need the 
* WS_VISIBLE style set. 
* 
* Note that this bug is also reproducible on a straight form - simply
* replace "x.cnt." with "x.", and remove the line "x.visible = .t." for an
* example
*
* Also note that this affects pre-added (in a class definition, for instance)
* activeX controls as well as dynamically added ones, as in this example
*
* Sample workaround code is included, though is somewhat clunky.
* It would be better to use BindEvent() to bind Visible_Assign(), 
* but it can't be done, as _assign methods are inherently protected, and 
* so, cannot be "BindEvent()"ed
*

PUBLIC x
LOCAL llWorkaround
llWorkaround = .F.

x = CreateObject(Iif(llWorkaround, "frmBase", "Form"))
x.Visible = .T.

x.Addobject("cnt", Iif(llWorkaround, "cntBase", "Container"))

*
* Note that the next line may use any OLE control with a visible element and
* a "hWnd" property:
*

x.cnt.Addobject("ole", "oleControl", "MSComCtl2.FlatScrollBar")

x.cnt.ole.Visible = .T.
x.cnt.Visible = .T.
*
* At this point, x.visible, x.cnt.visible and x.cnt.ole.visible will
* all be true, but the ActiveX control will not be visible, which can be 
* checked by checking the WS_VISIBLE style of the control:
*
#define GWL_STYLE           (-16)
#define WS_VISIBLE          (0x10000000)
DECLARE INTEGER ;
  GetWindowLong IN WIN32API ;
  INTEGER hWnd, ;
  INTEGER nLongOffset
llBug = Bitand(GetWindowLong(x.cnt.ole.hWnd, GWL_STYLE), WS_VISIBLE) == 0
ASSERT llBug != llWorkaround

DEFINE CLASS frmBase AS Form
  FUNCTION CheckChildOleControlVisibility
    *
    * For GetWindowLong:
    *
    #define GWL_STYLE           (-16)
    #define WS_VISIBLE          (0x10000000)

    LOCAL I
    FOR I = 1 TO THIS.ControlCount
      WITH THIS.Controls(m.I)
        IF .Visible
          DO CASE
            CASE InList(Upper(.BaseClass), "FORM", "CONTAINER")
              IF PemStatus(THIS.Controls(m.I), "CheckChildOleControlVisibility", 5)
                .CheckChildOleControlVisibility()
              ELSE
                ASSERT .F.
              ENDIF
            CASE Upper(.BaseClass) == "OLECONTROL"
              IF PemStatus(THIS.Controls(m.I), "hWnd", 5)
                DECLARE INTEGER ;
                  GetWindowLong IN WIN32API ;
                  INTEGER hWnd, ;
                  INTEGER nLongOffset
                IF Bitand(GetWindowLong(.hWnd, GWL_STYLE), WS_VISIBLE) = 0
                  .Visible = .F.
                  .Visible = .T.
                ENDIF
              ELSE
                .Visible = .F.
                .Visible = .T.
              ENDIF
          ENDCASE
        ENDIF
      ENDWITH
    ENDFOR
  ENDFUNC
  FUNCTION Visible_Assign(tvNewVal)
    THIS.Visible = m.tvNewVal
    IF m.tvNewVal
      THIS.CheckChildOleControlVisibility()
    ENDIF
  ENDFUNC
ENDDEFINE

DEFINE CLASS cntBase AS Container
  FUNCTION CheckChildOleControlVisibility
    *
    * For GetWindowLong:
    *
    #define GWL_STYLE           (-16)
    #define WS_VISIBLE          (0x10000000)

    LOCAL I
    FOR I = 1 TO THIS.ControlCount
      WITH THIS.Controls(m.I)
        IF .Visible
          DO CASE
            CASE InList(Upper(.BaseClass), "FORM", "CONTAINER")
              IF PemStatus(THIS.Controls(m.I), "CheckChildOleControlVisibility", 5)
                .CheckChildOleControlVisibility()
              ELSE
                ASSERT .F.
              ENDIF
            CASE Upper(.BaseClass) == "OLECONTROL"
              IF PemStatus(THIS.Controls(m.I), "hWnd", 5)
                DECLARE INTEGER ;
                  GetWindowLong IN WIN32API ;
                  INTEGER hWnd, ;
                  INTEGER nLongOffset
                IF Bitand(GetWindowLong(.hWnd, GWL_STYLE), WS_VISIBLE) = 0
                  .Visible = .F.
                  .Visible = .T.
                ENDIF
              ELSE
                .Visible = .F.
                .Visible = .T.
              ENDIF
          ENDCASE
        ENDIF
      ENDWITH
    ENDFOR
  ENDFUNC
  FUNCTION Visible_Assign(tvNewVal)
    THIS.Visible = m.tvNewVal
    IF m.tvNewVal
      THIS.CheckChildOleControlVisibility()
    ENDIF
  ENDFUNC
ENDDEFINE
-- Peter Crabtree
Contributors: Peter Crabtree
Category VFP Troubleshooting Category VFP Bugs
( Topic last updated: 2004.06.30 04:14:02 AM )