Progress
External Program
Interfaces


Handling ActiveX Control Events

Unlike Progress widget events, ActiveX control events often pass parameters. Also, while there are a few standard events common to most ActiveX controls, there are an infinite variety of possible events that are unique to each ActiveX control. Because Progress cannot have direct knowledge of all these possible events and must be able to handle the parameters of many of them, the standard Progress trigger mechanism cannot handle them.

Instead, Progress allows you to handle ActiveX control events using OCX event procedures. An OCX event procedure is a standard Progress internal procedure that serves as an event handler for ActiveX controls. The parameter-passing mechanism provided for Progress procedures handles most parameters that ActiveX control events typically pass. Progress identifies an OCX event procedure from the way its name is put together. This is the only syntactic feature that distinguishes the Progress internal procedure as an OCX event procedure.

Creating Event Procedures In the AppBuilder

In the AppBuilder, you define OCX event procedures as OCX event triggers. You can identify each ActiveX control event in the AppBuilder event list by the “OCX.” prefix attached to the event name. When you select an event name to define an OCX event trigger, the AppBuilder automatically generates an internal procedure block for the event procedure, including any procedure parameter definitions. (For more information, see the Progress AppBuilder Developer’s Guide .)

Coding Event Procedures

When you create an OCX event trigger in the AppBuilder, the AppBuilder defines an internal procedure template with the following components:

If you code OCX event procedures in external procedure files other than the one where you instantiate the ActiveX control, you must code the complete event procedure yourself. In addition, you must also add the procedure to the list that Progress searches to find event procedures to handle events. For more information, see the "Managing External Procedure Files" section.

Coding Event Procedure Names

Progress supports two types of OCX event procedures, distinguished by the procedure name:

NOTE: Names of event procedures are not case sensitive.

The names for control-bound event procedures contain three parts, delimited by a period (.). Each part can be quoted if it contains embedded spaces:

  1. The name of the control-frame (the NAME attribute value of the control-frame widget)
  2. The name of the ActiveX control (the Name property value set in the Property Editor)
  3. The name of the event that is handled by the procedure.

As with all internal procedures that you add in the AppBuilder, the PROCEDURE statement and procedure name is not visible in the Section Editor. However, this is one that you or the AppBuilder might code:

PROCEDURE CtrlFrame.CSSpin.SpinUp . 

This begins the definition for a procedure to handle the SpinUp event for the control named CSSpin in the control-frame named CtrlFrame.

The names for generic event procedures contain two parts, delimited by a period (.):

  1. ANYWHERE
  2. The name of the event that is handled by the procedure.

The AppBuilder does not provide a mechanism to generate generic event procedures. You must code these yourself in the AppBuilder using the New Procedure dialog box, or you can add them to an external procedure file. Here is an example:

PROCEDURE ANYWHERE.SpinUp . 

A generic event procedure with this name handles the SpinUp event for any control instance that does not have a control-bound event procedure defined for the SpinUp event.

Coding Event Parameter Definitions

As for any procedure definition, you code event procedure parameters using the DEFINE PARAMETER statement. When you create an event procedure as an OCX trigger in the AppBuilder, the AppBuilder provides default definitions for all required parameters. These default definitions attempt to specify a Progress data type that is compatible with the COM data type of the corresponding OCX event parameter. This data type generally follows the data type mappings shown in Table 9–4.

Table 9–4: Data Type Mappings For OCX Event Parameters
COM Data Type
Progress Data Type
Boolean
LOGICAL
Byte
INTEGER
Currency
DECIMAL
Date
DATE
Double
DECIMAL
Integer (2-byte integer)
INTEGER
Long (4-byte integer)
INTEGER
Object (COM)
COM-HANDLE
Single (Float)
DECIMAL
String
CHARACTER
Unsigned Byte
INTEGER
Unsigned Long (4-byte integer)
INTEGER
Unsigned Short (2-byte integer)
INTEGER
Variant
<ANYTYPE>1
VT-ARRAY (if single-dimensional array of bytes)
RAW
  1. You must replace <ANYTYPE>, provided by the AppBuilder in some OCX event trigger templates, with a valid Progress data type.

For event procedures you write yourself, you can also find the suggested Progress data type for each parameter displayed in the Progress COM Object Viewer for each selected control event. For more information on this viewer, see Using COM Objects In the 4GL."

In the AppBuilder, Progress uses data type mappings from the COM data type specified in the Type Library for the ActiveX control. If Progress cannot determine a data type mapping, the AppBuilder specifies <ANYTYPE> as a place holder. You must change <ANYTYPE> to the data type that most closely matches the expected value. Progress does its best to convert the COM data type to the Progress data type you specify. For more information on a COM data type, see the available documentation on the Microsoft Component Object Model and the event parameter you want to convert, then see "COM Object Data Type Mapping." For information on Type Libraries and Progress, see Using COM Objects In the 4GL."

The AppBuilder also provides a default mode option (INPUT, OUTPUT, or INPUT-OUTPUT) for each parameter definition. Here, although Progress does its best to interpret the information in the Type Library for the ActiveX control, this is not a direct mapping. You might have to modify the mode option. If the option chosen by Progress is incorrect, this generates a run-time error. If the event parameter is passed as read-only, define it as an INPUT parameter. If you can change its initial value and must pass it back to the ActiveX control, define it as an INPUT-OUTPUT parameter. If only the value you return to the ActiveX control has any meaning, define it as an OUTPUT parameter.

CAUTION: If an INPUT parameter passes in a COM-HANDLE value, use the RELEASE OBJECT statement to release the specified COM object when you no longer need it (usually before the event procedure returns). Otherwise, the component handle might become unavailable and the COM object might never be released. Also, not releasing the COM object in the event procedure can cause unpredictable behavior with some controls.

CAUTION: If an event procedure has any INPUT-OUTPUT or OUTPUT parameters and contains any I/O-blocking statements, such as SET or UPDATE, the output parameters are not returned to the control.
Using System Handles In OCX Event Procedures

Progress allows you to obtain the identities of both the ActiveX control that generates an event and the associated control-frame widget from within an OCX event procedure. The COM-SELF system handle returns the component handle of the ActiveX control and the SELF system handle returns the widget handle of the control-frame. This is especially useful in generic event procedures where the source of an event cannot be known.

Unlike for 4GL ON triggers, the RETURN NO-APPLY statement has no affect in an OCX event procedure. Some COM object events provide a similar mechanism using output parameters. For example, the standard KeyPress event passes a key code as an INPUT-OUTPUT parameter. If you set this parameter to 0 in the event handler, the key is discarded.

NOTE: To trigger a Progress widget event from the 4GL, you use the APPLY statement. However, to trigger an ActiveX control event in the 4GL, you execute its OCX event procedure as a standard internal procedure, passing any required parameters.

Event Handler Example

The following example shows an OCX event trigger for the NewItem event of the CSComboBox control MyCombo in control-frame CtrlFrame-2. This event occurs when a user enters an item in the text box that is not in the combo box list:

PROCEDURE CtrlFrame-2.MyCombo.NewItem .

DEFINE INPUT-OUTPUT PARAMETER p-ComboText AS CHARACTER NO-UNDO.
DEFINE INPUT-OUTPUT PARAMETER p-KeepFocus AS INTEGER NO-UNDO.

    COM-SELF:AddItem(p-ComboText, 1).
    p-KeepFocus = -1.

END PROCEDURE. 

The programmer uses the COM-SELF handle to add the new text item to the list with the AddItem( ) method. Setting p-KeepFocus to -1 ensures that the control maintains input focus after the item is added to the list.

If this event procedure is in the AppBuilder-generated application file, the programmer might otherwise choose to call the AddItem( ) method indirectly using the component handles provided by the AppBuilder (chCtrlFrame-2) and the control-frame COM object (MyCombo property):

PROCEDURE CtrlFrame-2.MyCombo.NewItem .

DEFINE INPUT-OUTPUT PARAMETER p-ComboText AS CHARACTER NO-UNDO.
DEFINE INPUT-OUTPUT PARAMETER p-KeepFocus AS INTEGER NO-UNDO.

    chCtrlFrame-2:MyCombo:AddItem(p-ComboText, 1).
    p-KeepFocus = -1.

END PROCEDURE. 


Copyright © 2004 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095