Try OpenEdge Now
skip to main content
Programming Interfaces
External Program Interfaces : ActiveX Control Support : Programming ActiveX controls in the AppBuilder : Instantiating the control
 
Instantiating the control
The AppBuilder generates the code to instantiate the ActiveX control starting with a call to the enable_UI procedure from the Main Block. For example:
/* *************************** Main Block *************************** */

/* Parent the dialog-box to the ACTIVE-WINDOW, if there is no parent. */
IF VALID-HANDLE(ACTIVE-WINDOW) AND FRAME {&FRAME-NAME}:PARENT EQ ? THEN
  FRAME {&FRAME-NAME}:PARENT = ACTIVE-WINDOW.

/* Now enable the interface and wait for the exit condition. */
/* (NOTE: handle ERROR and END-KEY so cleanup code will always fire. */
MAIN-BLOCK:
DO ON ERROR UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK
ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK:
  RUN enable_UI.

  /* Set max-records from open query in enable_UI. */
  max-records = NUM-RESULTS("Dialog-Frame").

  WAIT-FOR GO OF FRAME {&FRAME-NAME}.
END.
RUN disable_UI.
The programmer has added the comments and code that immediately follow the call to enable_UI. Here, they must set max-records to the number of records in the query only after the query is opened (again, in enable_UI), but before the spin button control is available to scan the result. The reason for this becomes clearer in later code fragments.
The following reduction of the enable_UI procedure shows that the AppBuilder generates the code to load the ActiveX control (RUN control_load) before its static parent frame and family of ABL widgets are displayed and enabled:
/* ********************** Internal Procedures *********************** */
. . .

PROCEDURE enable_UI :
/*------------------------------------------------------------------------
Purpose: ENABLE the User Interface
Parameters: <none>
Notes: Here we display/view/enable the widgets in the
user-interface. In addition, OPEN all queries
associated with each FRAME and BROWSE.
These statements here are based on the "Other
Settings" section of the widget Property Sheets.
------------------------------------------------------------------------*/
RUN control_load.

{&OPEN-QUERY-Dialog-Frame}
GET FIRST Dialog-Frame.
DISPLAY iRecordCount
    WITH FRAME Dialog-Frame.

  . . .

END PROCEDURE.
The initial value of iRecordCount is also set at control load time (see Initializing the control). Note also that the application query is opened to obtain the data for the frame:
Note: You can view this code in the Procedures section of the AppBuilder Section Editor. However, unlike the Main Block, this is protected AppBuilder-generated code that you cannot change.
The control_load procedure, called from enable_UI, is an AppBuilder-generated procedure that loads the ActiveX control into the control-frame by executing the LoadControls( ) method of the control-frame COM object. Note the call to initialize-controls, an optional internal procedure that you can define (and which is defined in this example) to modify control properties before the control becomes visible. For example:
/* ********************** Internal Procedures *********************** */
. . .

PROCEDURE control_load :
/*------------------------------------------------------------------------
Purpose: Load the OCXs
Parameters: <none>
Notes: Here we load, initialize and make visible the
OCXs in the interface.
------------------------------------------------------------------------*/
&IF "{&OPSYS}" = "WIN32":U AND "{&WINDOW-SYSTEM}" NE "TTY":U &THEN
DEFINE VARIABLE UIB_S AS LOGICAL NO-UNDO.
DEFINE VARIABLE OCXFile AS CHARACTER NO-UNDO.

OCXFile = SEARCH( "i-ocx1.wrx":U ).

IF OCXFile <> ? THEN DO:
ASSIGN
chcustSpin = custSpin:COM-HANDLE
UIB_S = chcustSpin:LoadControls( OCXFile, "custSpin":U).
RUN initialize-controls IN THIS-PROCEDURE NO-ERROR.

END.
ELSE MESSAGE "The file, i-ocx1.wrx, could not be found." skip
"The controls cannot be loaded."
VIEW-AS ALERT-BOX TITLE "Controls Not Loaded".
&ENDIF
END PROCEDURE.
You can view but you cannot change this AppBuilder-generated code from the Section Editor.
You might wonder why you cannot load the control with a chained handle reference CtrlFrame:COM-HANDLE:LoadControls( ... ). The reason is that even though CtrlFrame:COM-HANDLE returns a component handle, it does so with reference to a widget attribute (COM-HANDLE), not a COM object property or method. You cannot make a component handle expression by chaining widget handle references (that return component handles) with component handle references.