Advanced ActiveX Controls in Visual FoxPro 5.0

Greg Carpenter

December, 1996

Introduction

This paper describes a variety of advanced ActiveX™ control topics that will be of interest to developers of ActiveX controls and to developers who include ActiveX controls with their distributed Microsoft® Visual FoxPro™ applications.

Simple Data Bound Controls

Visual FoxPro 5.0 has been enhanced to support simple data-bound ActiveX controls. Visual FoxPro allows simple data-bound controls to be bound to a field or variable like native Visual FoxPro controls.

A simple data-bound control can update Visual FoxPro data pessimistically or optimistically. To update data pessimistically, the simple data bound control queries the Visual FoxPro IPropertyNotifySink method OnRequestEdit to determine if the data can be updated. If it is granted permission by Visual FoxPro, the control calls the IPropertyNotifySink method OnChanged to update the data.

To update data optimistically, the simple data bound control assumes it is okay to update the data, doesn’t query Visual FoxPro, and calls the IPropertyNotifySink method OnChanged to update the data.

Visual FoxPro transfers the data value through the IDispatch interface. Visual FoxPro is made aware of the changes to the data value through a common property change notification mechanism.

Creating a simple bound control

An ActiveX control developer can add three attributes to the control’s Object Description Language (ODL) file to support simple data binding in an ActiveX control. The following table lists the ODL attributes that Visual FoxPro requires to host a simple data-bound control.

Attribute Description
Bindable Set on properties supporting the OnChanged notification. Required for simple data binding.
RequestEdit Set on properties supporting the OnRequestEdit notification.
DefaultBind Indicates the single bindable property that best represents the control. Required for simple data binding.

The following is an example of a typical ODL property description demonstrating the use of the Bindable, RequestEdit, and DefaultBind attributes.

[id(1), bindable, requestedit, displaybind, defaultbind] BSTR BoundProp

Extender properties for simple bound controls

When a control with the Bindable and DefaultBind properties is instantiated in Visual FoxPro, Visual FoxPro automatically adds two extender properties to the control—the ControlSource and Value properties. The ControlSource property can be used to bind the control to a Visual FoxPro field or variable, in a manner similar to the ControlSource property for native Visual FoxPro controls such as the TextBox and EditBox controls. The Value property is a hidden property and is used internally by Visual FoxPro. Note that the Value property can only be used by Visual FoxPro and cannot be added as a user-defined property.

Simple Frame Controls

Visual FoxPro 5.0 has been enhanced to allow the use of Simple Frame (ISimpleFrame) controls. Simple Frame controls were popularized by Visual Basic® 4.0 to support the flat object model of Visual Basic. Because Visual Basic 4.0 does not have a containership model like Visual FoxPro, Visual Basic 4.0 supports Simple Frame controls so that you can place controls inside a logical grouping (a container).

In Visual Basic 4.0, a control can be placed within the bounds of a Simple Frame control; the control is treated as a member of the bounding Simple Frame control.

In Visual Basic 5.0, the ControlContainer property of the bounding control can be set to True to enable Simple Frame behavior.

Visual FoxPro identifies Simple Frame controls by calling the lpOleObject->GetMiscStatus() method and it returning a flag named OLEMISC_SIMPLEFRAME.

Creating simple frame controls with Microsoft Visual C++

To create a Simple Frame control when using Microsoft Visual C++® and the Control Developer’s Kit (CDK), choose the Simple Frame Control check box when creating a control with the Control wizard.

Simple frame control design and run time issues

Visual FoxPro is a non-windowed control environment; it supports windowless Visual FoxPro native controls. Therefore Visual FoxPro doesn’t always regress properly to accommodate windowed ActiveX controls such as Simple Frame controls. When a Simple Frame control is dropped onto the Visual FoxPro design surface, Visual FoxPro creates a bounding window which contains the Simple Frame control. This window allows most Simple Frame controls to behave correctly in design mode. However, because the Visual FoxPro native controls aren’t windowed controls, you should note the following:

Extender properties for simple frame controls

When Visual FoxPro determines that an ActiveX control is a Simple Frame control, it automatically adds four extender properties to the control to allow the control to work well within Visual FoxPro. One of the four properties are available only at run time. The following table lists the four extender properties that are added to a Simple Frame control at run time.

Property Description
Paint Occurs when a WM_PAINT event is sent to the Simple Frame control’s window. If a class is created through code that sets the OLEClass property to a Simple Frame control, a procedure named PAINT can be added to trap this event and can execute code at run time. Available only at run time.
ShowTips Determines if ToolTips are shown for contained controls. Because this property is added dynamically, it cannot be inherited. If the Simple Frame control is subclassed, ShowTips must be set in the Init event of the Simple Frame control in order to function correctly.
SetAll Container function used to set a property for multiple objects in the container.
AddObject The AddObject method is added because a Simple Frame control is treated as a container in Visual FoxPro.

Windows System Events and ActiveX Controls

By default, Visual FoxPro 5.0 processes Windows® system events like the Windows message queue between execution of lines of user program code. For example, a Windows paint message may be executed to redraw an area of the screen between execution of lines of user program code.

The AutoYield property and the DOEVENTS command were added to Visual FoxPro to specify how the behavior of ActiveX controls is affected by Windows system events.

The AutoYield property

The AutoYield property determines if Visual FoxPro processes Windows system events (performs a Windows API PeekMessage) between execution of lines of user program code. If AutoYield is set to True (the default), Visual FoxPro looks for Windows system events between execution of lines of user program code. If AutoYield is set to False, Visual FoxPro doesn’t process Windows system events between execution of lines of user program code.

The following, taken from the AutoYield Property topic in the Visual FoxPro Help file, describes the effect of the AutoYield property on ActiveX controls.

The AutoYield property should be set to False when a form contains an ActiveX control. Setting AutoYield to False prevents events for an ActiveX control from executing between lines of user program code. For example, if AutoYield is set to True, clicking an ActiveX control while user program code is executing may cause an event for the ActiveX control to execute, ignoring the user program code for the event, producing undesirable or unpredictable results.

The following occurs when the AutoYield property is set to False:

The DOEVENTS command

If the AutoYield property is set to False, Windows system events are not processed between lines of user program code. The DOEVENTS command allows Windows system events to be processed when AutoYield is set to False. If user program code is running and requires a long time to execute, Windows system events are queued until the user program code completes execution or the DOEVENTS command is issued. You can also issue DOEVENTS when AutoYield is set to True, but it will have little or no effect on Visual FoxPro performance or behavior.

ActiveX control event firing

A common approach used by some ActiveX control vendors is to have an event fire when a particular method on the control is called. For example, if an ActiveX control has a DoCalculate method, it may internally execute a ProcessingTotal event. When the DoCalculate method is executed, the control in turn executes the ProcessingTotal event. However, if AutoYield is set to True, Visual FoxPro ignores the ProcessingTotal event and doesn’t run any user code for the event.

One of the side effects of setting AutoYield to True is that when code is running, Visual FoxPro does not allow ActiveX control events to execute additional code. In our example above, the code that calls the DoCalculate method is running and Visual FoxPro, seeing that AutoYield is set to True, does not allow the event code to execute—other Visual FoxPro code is running when the ProcessingTotal event occurs. If AutoYield is set to False, the ProcessingTotal event is executed.

Internally, Visual FoxPro returns a status of S_FALSE to the ActiveX control that is calling EventDispatch->Invoke( ). If the ActiveX control is created with the Visual C++ CDK, the status is eaten by the FIRE() mechanism and is not reported to the ActiveX control. However, if the ActiveX control is created without the CDK wrapper, the status may be reported to the ActiveX control.

Because Visual Basic returns S_OK for all EventDispatch->Invoke( ) calls, you can use Visual Basic to help diagnose problems with the execution of ActiveX control events.

Take the following quiz to learn more about the execution of event code in ActiveX controls.

  1. AutoYield is set to True and an ActiveX control has a Click event. If there is code being run that performs a lengthy calculation, and the mouse is clicked on the ActiveX control during the lengthy calculation, does the event code for the Click event get executed?

  2. AutoYield is set to False and an ActiveX control has a Click event. If there is code being run that performs a lengthy calculation, and the mouse is clicked on the ActiveX control during the lengthy calculation, does the event code for the Click event get executed?

Answers

  1. No. Because Visual FoxPro is running code and AutoYield is set to True, the event code from the Click event isn’t executed.

  2. Not immediately. Recall the first example above of the ActiveX control with the DoCalculate method and ProcessingTotal event. DoCalculate is a method that directly calls into the ActiveX control; the ActiveX control then executes the ProcessingTotal event—the event is being generated internally from a method call. However, the Click event is executed because a Windows system message for WM_LBUTTONDOWN gets processed by the ActiveX control, is then translated to a Click event, and is passed to Visual FoxPro. Because AutoYield is set to False, Visual FoxPro doesn’t process Windows system events during the lengthy calculation. Therefore, the ActiveX control does not get the chance to see the Windows system WM_LBUTTONDOWN message until the calculation code completes or DOEVENTS is called. So the event code gets executed, but it isn’t executed when the mouse is clicked.

Vtable Binding

One of the greatest performance improvements in Visual FoxPro 5.0 results from its ability to perform vtable binding to ActiveX controls. Vtable binding (also sometimes referred to as dual-interface binding) allows Visual FoxPro to bind to an ActiveX control through a function pointer instead of through the IDispatch method. This provides considerably quicker access to an ActiveX control’s properties and functions. If a type library on an ActiveX control is marked as TYPEFLAG_FDUAL, the ActiveX control should support dual interfaces. Each event or method can then be marked as FUNC_PUREVIRTUAL so that Visual FoxPro can take advantage of this speedier binding technique.

Warnings

Unfortunately, not all ActiveX controls are properly marked for vtable binding. There are very few containers like Visual FoxPro that support vtable binding for ActiveX controls. Therefore, ActiveX control vendors do not have many applications with which to test their ActiveX controls. Because some ActiveX controls mark themselves as TYPEFLAG_FDUAL but do not support it, they can cause a general protection fault in OLEAUT32.DLL when they are dropped onto a Visual FoxPro form.

Visual FoxPro 5.0 provides two methods for a developer to prevent the general protection fault. If an ActiveX control is known to have TYPEFLAG_FDUAL set but does not support it, its OLE class ID (GUID) may be added to the HKEY_CLASSES_ROOT\NoDualInterface\{clsid} set of keys in the registry. Visual FoxPro 5.0 adds this key to the registry when it is installed. It also places the GUID for the Microsoft Web Browser Control in the list along with the GUIDs of other controls known to state in error that they support dual interfaces.

A new SYS(2333) function is supported in Visual FoxPro 5.0 to enable or disable ActiveX vtable binding support. SYS(2333) determines if vtable binding is used for any ActiveX control instantiated after the function is issued. If SYS(2333,0) is issued, vtable binding is disabled for all instantiated ActiveX controls until SYS(2333,1) is issued. Issuing SYS(2333) without the 0 or 1 argument is identical to issuing SYS(2333,1)—vtable binding enabled for ActiveX controls.

FreezeEvents

Visual FoxPro 5.0 now supports FreezeEvents (from the OLE Control SDK guidelines). LpOlEControl->FreezeEvents(TRUE) is called just prior to setting the SetClientSite pointer of the ActiveX control. LpOleControl->FreezeEvents(FALSE) is called just prior to the INIT code of the ActiveX control being called.

ActiveX Control Distribution and Licensing

When a Visual FoxPro developer includes an ActiveX control with their application, it must be referenced in an .SCX or .VCX file. The ActiveX licensing scheme used by Visual FoxPro requires that the control be embedded in one of these files. If an ActiveX control is shipped with an application that uses ADDOBJECT( ) to add an ActiveX control to a container, an error will occur unless the design time license is also shipped with the ActiveX control. Design time licensing can typically be obtained from the ActiveX control vendor.

Data Binding to Non-Data Bound Controls

Visual FoxPro’s unique ability to subclass ActiveX controls provides great advantages. By sub-classing certain ActiveX controls, the developer can give the appearance of data binding even though the ActiveX control doesn’t directly support data binding. The two examples below demonstrate how to perform data binding to the Access Calendar Control and the RichText Object control.

Access Calendar control example

You can subclass the Access Calendar control to use it as a date picker.

  1. Issue the following in the Command window:

    CREATE CLASS olecalendar OF myvcx AS olecontrol

  2. The Insert Object dialog box is displayed.

  3. Choose the Insert Control option button, choose the Calendar control, and then choose OK.

  4. From the Class menu, choose the New Property option.

  5. In the Name field, type Date_Field.

  6. In the Description field type Specifies a date type field to which the calendar is linked.

  7. Choose Add, and then choose Close.

  8. From the Class menu, choose the New Method option.

  9. In the Name field, type RefreshDisplay.

  10. In the Description field type Updates the calendar display with the value in the field specified in Date_Field property.

  11. Choose Add, and then choose Close.

  12. Place the following code in the each of the specified methods and events:
    *** AfterUpdate Event ***
    nYear = THIS.year
    nDay = THIS.day
    nMonth = THIS.month
    dValue = CTOD(ALLTRIM(STR(nMonth)) + "/" + ALLTRIM(STR(nDay)) + ;
      "/" + ALLTRIM(STR(nYear)))
    cColumn = THIS.date_column
    IF !EMPTY(cColumn) THEN
        REPLACE &cColumn WITH dValue
    ENDIF
    THISFORM.Refresh
    
    *** RefreshDisplay Method ***
    
    cColumn = this.date_column
    IF !EMPTY(cColumn) THEN
        THISFORM.oleCalendar1.Month = MONTH(&cColumn)
        THISFORM.oleCalendar1.Day = DAY(&cColumn)
        THISFORM.oleCalendar1.Year = YEAR(&cColumn)
    ENDIF
    
    *** LostFocus Event ***
    
    THIS.Visible = .F.
    

The Access Calendar control can then be bound to a date type field in a table by specifying the name of the field in the Date_Field property. To use the Calendar control, place it on a form. In the Refresh method of the form, add THISFORM.oleCalendar1.RefreshDisplay. Save and run the form.

Rich Textbox control example

You can subclass the Microsoft Rich Textbox control to bind it to a Visual FoxPro memo field.

  1. Issue the following in the Command window:

    CREATE CLASS olerichtext OF myvcx AS olecontrol

  2. The Insert Object dialog box is displayed.

  3. Choose the Insert Control option button, choose the Microsoft Rich Textbox control, and then choose OK.

  4. From the Class menu, choose the New Property option.

  5. In the Name field, type Memo_Name.

  6. In the Description field type Specifies a memo field to which the rich textbox is linked.

  7. Choose Add, and then choose Close.

  8. Place the following code in the each of the specified events:
    *** LostFocus Event ***
    cMemo = this.memo_name
    REPLACE &cMemo with this.textrtf
    *** Refresh Event ***
    cMemo = this.memo_name
    this.textrtf = &cMemo
    

The Microsoft Rich Textbox control can then be bound to a memo field in a table by specifying the name of the memo field in the Memo_Name property. To use the Rich Textbox control, place it on a form. Save and run the form.