Greg Carpenter
December, 1996
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.
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.
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
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.
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.
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.
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:
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. |
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 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:
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.
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.
Answers
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.
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.
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.
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.
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.
You can subclass the Access Calendar control to use it as a date picker.
CREATE CLASS olecalendar OF myvcx AS olecontrol
*** 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.
You can subclass the Microsoft Rich Textbox control to bind it to a Visual FoxPro memo field.
CREATE CLASS olerichtext OF myvcx AS olecontrol
*** 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.