When programming with ActiveX controls and COM objects, you can pass one- or two-dimensional COBOL tables to methods or properties that expect SAFEARRAY parameters. The runtime automatically converts a one- or two-dimensional COBOL table to a COM SAFEARRAY, as long as it contains only one elementary item that is USAGE HANDLE or USAGE HANDLE OF VARIANT.
The COM SAFEARRAY data type can contain elements of any type. Therefore, you must convert your COBOL data into variant type data before adding it to the array. Use the C$SETVARIANT library routine to create a new variant that stores the data if the initial value of the handle item passed to it is LOW-VALUES or SPACES. You need to free this variant using the DESTROY verb.
To use SAFEARRAYs, you should do the following:
For example, Microsoft Chart Control has a property called ChartData. The value of this property is a SAFEARRAY. Each element of the array is a data point value for the chart.
01 myTable. 03 filler occurs 5 times. 05 chart-data usage handle of variant. screen section. 01 screen-1. 03 mschart-1 MSChart line 3, column 5, size 50, lines 16. 03 my-button push-button, "E&xit Program", ok-button, line 32, cline 23, column 27, size 13. procedure division. Main-Logic. perform varying col-number from 1 by 1 until col-number > 5 call "c$setvariant" using col-number, chart-data(col-number) end-perform. display standard graphical window, title "ActiveX Table MSChart Sample - tblchart.cbl" lines 37, size 66, background-low. display screen-1. modify mschart-1 ChartData = myTable. perform, with test after, until exit-button-pushed accept screen-1 end-perform. perform varying col-number from 1 by 1 until col-number > 5 destroy chart-data(col-number) end-perform. destroy screen-1. stop run.
Notice that the initial values of the chart-data table elements are spaces. When C$SETVARIANT is called with the chart-data items set to spaces, it creates new variant handles and sets the chart-data item to the variant handle.
The DESTROY statement destroys these handles and releases the associated memory. The DESTROY statement also sets the chart-data item to low-values to allow multiple destroys of the same handle item without any negative effects.
The following code is an example of a table with two OCCURS clauses passed as a two-dimensional SAFEARRAY to the ChartData property. Microsoft Chart Control takes the "string" elements of this array to be the x-axis labels and the numeric elements to be two series of chart data.
77 col-label pic x(20). 77 series-2-data pic 99. 01 myTable. 03 filler occurs 5 times. 05 filler occurs 3 times. 07 chart-data usage handle of variant. screen section. 01 screen-1. 03 mschart-1 MSChart line 3, column 5, size 50, lines 16. 03 my-button push-button, "E&xit Program", ok-button, line 32, cline 23, column 27, size 13. procedure division. Main-Logic. perform varying col-number from 1 by 1 until col-number > 5 string "Label " delimited by size col-number delimited by size into col-label call "c$setvariant" using col-label, chart-data(col-number,1) call "c$setvariant" using col-number, chart-data(col-number,2) multiply col-number by 2 giving series-2-data call "c$setvariant" using series-2-data, chart-data(col-number,3) end-perform. display standard graphical window, title "ActiveX Table MSChart Sample - tblchart.cbl" lines 37, size 66, background-low. display screen-1. modify mschart-1 ChartData = myTable. perform, with test after, until exit-button-pushed accept screen-1 end-perform. perform varying col-number from 1 by 1 until col-number > 5 destroy chart-data(col-number,1) destroy chart-data(col-number,2) destroy chart-data(col-number,3) end-perform. destroy screen-1. stop run.
Some ActiveX and COM objects that use SAFEARRAYs accept that some items in the array may be empty (for example, Microsoft ADO). Items that are empty are normally passed using the VT_EMPTY variant type.
If an element in an array that you want to pass is optional (i.e., it may sometimes be empty), you must tell the runtime this by coding one of the following:
01 VariantParam. 03 VariantTable usage handle of variant occurs 5. call "c$setvariant" USING x"00" VariantTable(1)
or
call "c$setvariant" USING "" VariantTable(1)
This tells the runtime to convert the content of VariantTable(1) to VT_EMPTY. If you use the latter approach, you may receive and ignore compiler warnings that an empty literal was encountered.