The COBOL Interfacing Environment | Installf Facility |
The first part of this chapter describes how to interface from your COBOL program to:
The second part of this chapter describes interfacing and mixed-language programming on UNIX.
Cancelling a COBOL program ensures that the next time it is referenced it is in its initial state. However, this does not necessarily happen when a non-COBOL program is cancelled. Any tidying-up of resources (memory, open files, and so on) used by the non-COBOL program depends on the language used to create the program and the various options associated with its compiler.
32-bit :
On the 32-bit COBOL systems, when you cancel a dynamically called COBOL
or non-COBOL program, the memory used by the program is freed. Cancelling
programs that are statically linked into the executable does not free any
memory.
16-bit :
Cancelling a non-COBOL program on 16-bit COBOL systems does not free the
memory used. For example, if you have a .dll file written in C and
called from a COBOL program, cancelling that .dll file does not
remove it from memory until the application finishes.
We recommend that you write your assembler subprograms to comply with the standard COBOL calling convention.
DOS:
An assembler subprogram on DOS that obeys the COBOL calling
convention takes the form as shown in the following example.
;--------------------------------------------------------- ; Example skeleton assembler subprogram ;--------------------------------------------------------- ; Declare local data segment(s) ;--------------------------------------------------------- DATA segment word public 'DATA'
...
data used by subprogram
...
DATA ends
;---------------------------------------------------------
; Declare local code segment(s)
;---------------------------------------------------------
CODE segment byte public 'CODE'
assume cs:code
;---------------------------------------------------------
; Declare public entry point
;---------------------------------------------------------
PUBLIC EXAMPLE
;---------------------------------------------------------
; Declare equates for accessing params(COBOL convention)
;---------------------------------------------------------
param1 equ bp+6
param2 equ bp+10
EXAMPLE proc far
push bp ; preserve bp
mov bp,sp ; address params on stack
push ds ; preserve ds, si, di
push si
push di
...
program code
...
lds si,[param1] ; access parameter 1
...
lds si,[param2] ; access parameter 2
...
mov ax,{return-code} ; set up return code
...
pop di
pop si
pop ds ; restored ds,si,di
pop bp ; restored bp
ret
EXAMPLE endp
CODE ends
end
The assembler subprogram might consist of multiple code and data segments. You should ensure that the initial code entry point is at the start of the first code segment defined or alternatively that you explicitly define the entry point label after the "end" directive.
16-bit on Windows and OS/2:
On the 16-bit COBOL system the structure of an assembler subprogram
on Windows and OS/2 is basically the same as that for DOS, so in general
your assembler subprogram source is identical between DOS, Windows and
OS/2. There are, however, a few extra points which you might need to take
into consideration.
Windows V3:
library exetype windows 3.0 code preload fixed discardable data preload moveable single heapsize 8048 exports entry-point-name @1 wep @2 residentname
Windows NT:
library exports entry-point-name @1
OS/2:
library initinstance code loadoncall exports entry-point-name @1
32-bit on Windows NT and OS/2:
On the 32-bit COBOL systems on Windows NT and OS/2 V2 an
assembler subprogram that obeys the COBOL calling convention takes the
following form:
;---------------------------------------------------------
; Example skeleton assembler subprogram
;---------------------------------------------------------
;---------------------------------------------------------
; Declare local data segment(s)
;---------------------------------------------------------
.386
.MODEL FLAT ;This line should be omitted for Windows NT
DATA32 segment dword use32 public 'DATA'
...
data used by subprogram
...
DATA32 ends
;---------------------------------------------------------
; Declare local code segment(s)
;---------------------------------------------------------
CODE32 segment dword use32 public 'CODE'
assume cs:flat, ds:flat, ss:flat, es:flat
;---------------------------------------------------------
; Declare public entry point
;---------------------------------------------------------
PUBLIC EXAMPLE
;---------------------------------------------------------
; Declare equates for accessing params(COBOL convention)
;---------------------------------------------------------
param1 equ ebp+8
param2 equ ebp+12
EXAMPLE proc near push ebp ; preserve ebp mov ebp,esp ; address params on stack push esi ; preserve esi, edi push edi |
The assembler subprogram may consist of multiple code and data segments. You should ensure that the initial code entry point is at the start of the first code segment defined or alternatively that you explicitly define the entry point label after the "end" directive.
Notes:
Windows NT:
On Windows NT, in the example above the
.def file should contain the following lines:
library libname exports entry-point-name @1
OS/2 V2:
For OS/2 V2, in the example above the
.def file should contain the following lines:
library libname code LOADONCALL exports entry-point-name @1
Assembler subprograms must be statically or dynamically linked. If they are statically linked they must use the faster form of static linking. To make the above example statically linked, call it using the COBOL statements:
special-names. call-convention 8 is litlinked. . . . call litlinked "EXAMPLE" using parameter1, parameter2
16-bit:
On the 16-bit COBOL system, an alternative method for making the program
statically linked is:
call "_ _EXAMPLE" using parameter1, parameter2
To make the above example dynamically linked, call it using:
call "EXAMPLE" using parameter1, parameter2
16-bit:
For more information on static and dynamic linking on the 16-bit COBOL
system, see your Object COBOL User Guide.
When using Animator to debug your application, Animator automatically steps through calls to assembler subprograms and onto the next statement after the call. If your assembler subprogram needs to write output to the user screen then, in order to ensure that the user screen is correctly updated by the assembler subprogram, you should use the FLASH-CALLS directive when invoking Animator. This restriction does not apply to Animator V2.
16-bit:
On the 16-bit COBOL system, the Compiler generates LARGE/HUGE
memory model code by default. This causes all parameters passed by
reference to be pushed as 32-bit pointers on the stack. This also causes
all calls to be FAR calls
. Accordingly, all returns from subprograms must be FAR returns
. You can change this by using the MODEL directive
when compiling your COBOL program.
If you set MODEL"SMALL" or MODEL"MEDIUM", all parameters are pushed as 16-bit offsets. The parameters can be accessed by using the 16-bit offsets from the value of the DS register upon entry to the subprogram, as this value is the start of a Data Division segment. For all other settings of MODEL, the parameters are a 32-bit segment:offset address.
If you set MODEL"SMALL" or MODEL "COMPACT", all returns must be NEAR returns. For all other settings of MODEL you must use FAR returns.
It is possible to do FAR calls in MODEL"SMALL" or MODEL"MEDIUM" programs. By prefixing the name of the subprogram with two underscores in a COBOL literal, in addition to causing the subprogram to be statically linked, you tell the Compiler to generate a FAR call and to push all parameters as 32-bit addresses on the stack. The Compiler removes both the underscores at code generation time.
The following sections describe the state of the registers when an assembler program is called from a COBOL program.
The registers used at call time from a 16-bit COBOL program are as follows:
Register
|
Usage
|
---|---|
CX | Number of parameters pushed on the stack by the calling COBOL program. |
SS:SP | The return address followed by the pushed parameters,
as follows:
NEAR for models SMALL and COMPACT. FAR for models MEDIUM, LARGE and HUGE. For models SMALL and MEDIUM all BY REFERENCE parameters are 16-bit offsets from the current value of DS. For models COMPACT, LARGE and HUGE, the BY REFERENCE parameters are 32-bit segment:offset addresses. |
DS | There is only one DS value for models SMALL and MEDIUM. This value points to the start of the Data Division. For all other models the value of DS is undefined at entry to a subprogram since parameters are passed as 32-bit addresses, including the segment value and offset. It might be necessary to include directives when compiling non-COBOL programs to force the compiler to generate code that assumes nothing about the value of DS upon entry to a subprogram. |
BP | Stack pointer used by COBOL programs. This register must be preserved across the subroutine call. |
DF | The direction flag is set forward on entry to the assembler program. You should ensure that the flag is still set to this value when the program returns to its caller and also any time the COBOL run-time is entered; for example, if your assembler calls another COBOL program. |
The registers used at call time from a 32-bit OS/2 COBOL program, using CALL-CONVENTION 0 (the default call convention) are as shown below. A call using CALL-CONVENTION 0 is equivalent to the OS/2 _System calling convention.
Register
|
Usage
|
---|---|
AL | Size of the parameter list. If the parameter list is greater than 255 double words, the value contained in AL is the 8 least significant bytes of the size. |
DF | Clear on entry. The register must be cleared on exit. |
ESP | The return address, followed by the parameters which have been pushed in right to left order. |
The registers EBP, EBX, ESI and EDI must be preserved by the called program.
The called program should return a non-floating-point value to the calling program in EAX. If the program returns a floating-point value, it should use the floating point stack ST(0). If a floating point item is to be returned, the COBOL program should:
The registers used at call time from a 32-bit OS/2 COBOL program, using CALL-CONVENTION 16 are as shown below. A call using CALL-CONVENTION 16 is equivalent to the OS/2 _Optlink calling convention.
Register
|
Usage
|
---|---|
DF | Clear on entry. The register must be cleared on exit. |
ESP | The return address, followed by the parameters which have been pushed in right to left order. |
The three conforming parameters that are lexically leftmost are passed in the registers EAX, EDX and ECX. All data items called by reference, and all items passed by value, except the first four COMP-1 and COMP-2 data items are considered to be conforming parameters. The first four by value COMP-1 and COMP-2 data items are passed on the floating point stack. Space for the parameters in registers is allocated on the stack, but the parameters are not copied into that space.
The registers EBP, EBX, ESI and EDI must be preserved by the called program.
The called program should return a non-floating-point value to the calling program in EAX. If the program returns a floating-point value, it should use the floating point stack ST(0). If a floating-point value is to be returned, the COBOL program should:
The registers used at call time from a 32-bit Windows NT COBOL program, using CALL-CONVENTION 0 (the default call convention) are:
Register
|
Usage
|
---|---|
ESP | The return address, followed by parameters which have been pushed in right to left order |
The registers EBP, EBX, ESI and EDI must be preserved by the called program.
The return address should be stored in EAX for four byte data items, or in the EDX:EAX register pair for an eight byte structure.
The following sections show you how your programs can interface with the Windows and OS/2 API routines.
16-bit on Windows:
On the 16-bit COBOL system for Windows, the Windows API routines
can be treated as a special case of a subprogram that can be called
directly from COBOL. The API routines should always be called using a
calling convention that includes the Pascal conventions (bits 1 and 2 set
in the value, for example
CALL-CONVENTION 3) and, since these routines are always resolved at
link time, all calls to API routines should be statically linked. This can
be done either by the recommended method of using CALL-CONVENTION 11
(combining conventions 8 and 3) or by the obsolete method of preceding the
API routine name with a double-underscore prefix.
For example, the following Windows program makes use of an API routine to display a message box. The old method of specifying static linking has been commented out and replaced with the preferred notation.
special-names. call-convention 11 is winapi call-convention 3 is winapiold. procedure division. call winapi "MessageBox" using by value 0 size 2, by reference "Hello world" & x"00", by reference "Micro Focus" & x"00", by value 0 size 2. * call winapiold "_ _MessageBox" using * by value 0 size 2, * by reference "Hello world" & x"00", * by reference "Micro Focus" & x"00", * by value 0 size 2.
16-bit on OS/2:
On the 16-bit COBOL system for OS/2, the OS/2 API routines can be
treated as a special case of a subprogram that can be called directly from
COBOL. The API routines should always be called using a call convention
that includes the Pascal conventions (bits 1 and 2 set in the value, for
example
CALL-CONVENTION 3) and, since these routines are always resolved at
link time, all calls to API routines should be static linked. This can be
done either by the recommended method of using CALL-CONVENTION 11
(combining conventions 8 and 3) or by the obsolete method of preceding the
API routine name with a double-underscore prefix.
For example, the following OS/2 program makes use of an API routine to retrieve the current country information. The old method of specifying static linking has been commented out and replaced with the preferred notation.
special-names. call-convention 11 is os2api call-convention 3 is os2apiold. working-storage section. 01 ctry-info. 03 ctry-code pic xx comp-5. 03 code-page-id pic xx comp-5. 03 filler pic x(36). 01 ctry-info-len pic xx comp-5 value 40. 01 select-code-and-page. 03 select-code pic x(4) comp-5 value 0. 03 select-page-id pic x(4) comp-5 value 0. procedure division. call os2api "DosGetCtryInfo" using by value 40 size 2 by reference select-code-and-page ctry-info ctry-info-len * call os2apiold "_ _DosGetCtryInfo" using * by value 40 size 2 * by reference select-code-and-page * ctry-info * ctry-info-len
if return-code not = 0 display "DosGetCtryInfo failed - code: " return-code else display "Country code is: " ctry-code display "Code Page ID is: " code-page-id end-if stop run.
32-bit on Windows NT:
On the 32-bit COBOL system for Windows NT the Win32 API
routines can be treated as subprograms that can be called directly from
COBOL. The API routines should always be called with the correct call
convention.
For example, the following program makes use of an API routine to retrieve the current date and time.
special-names. call-convention 2 is winapi.
working-storage section. 01 system-time. 03 system-year pic 9(8) comp-5. 03 system-month pic 9(8) comp-5. 03 system-day-of-week pic 9(8) comp-5. 03 system-day pic 9(8) comp-5. 03 system-hour pic 9(8) comp-5. 03 system-minute pic 9(8) comp-5. 03 system-second pic 9(8) comp-5. 03 system-millisecond pic 9(8) comp-5.
procedure division. call "cob32api" call winapi "GetSystemTime" using by reference system-time display "Day of week is: " system-day-of-week display "Day of month is: " system-day stop run.
As for assembler calls, if you are animating a program that is making calls to API routines and if the API routines may affect the user screen (for example, VIO calls) you should use the FLASH-CALLS Animator directive to ensure that the user screen is correctly updated.
32-bit on OS/2 V2:
OS/2
On the 32-bit COBOL system for OS/2 V2 the DOS, WIN, GPI, DEV
and DRG APIs are all called without the need to specify a call convention
as they all use the OS/2 system linkage call convention which is the
default for COBOL programs.
For example, the following program makes use of a DOS API routine to retrieve the current country information.
working-storage section. 01 ctry-info. 03 ctry-code pic x(4) comp-5. 03 code-page-id pic x(4) comp-5. 03 filler pic x(36). 01 ctry-info-len pic x(4) comp-5 value 44. 01 select-code-and-page. 03 select-code pic x(4) comp-5 value 0. 03 select-page-id pic x(4) comp-5 value 0.
procedure division. call "DosQueryCtryInfo" using by value 40 size 4, by reference select-code-and-page, ctry-info, ctry-info-len.
if return-code not = 0 display "DosQueryCtryInfo failed - code: " return-code else display "Country code is: " ctry-code display "Code Page ID is: " code-page-id end-if stop run.
This COBOL system provides three .dll files to allow the various system APIs to be called from .int or .gnt programs:
cob32api.dll should be called if you need to use any of the DOS APIs
cob32win.dll should be called if you need to use any of the WIN, GPI, DEV or DRG APIs
cob32chr.dll should be called if you need to use any of the 16-bit KBD, VIO or MOU APIs.
The KBD, VIO and MOU APIs are all 16-bit APIs which use the pascal
linkage convention. CALL-CONVENTION 35 must be used when calling these
functions. For example, the following program makes use of a VIO API
routine to read the first line of text on the screen:
special-names. call-convention 35 is pascal16.
working-storage section. 01 line-buf pic x(80). 01 line-length pic x(2) comp-5 value 80. 01 line-row pic x(2) comp-5 value 0. 01 line-col pic x(2) comp-5 value 0. 01 viohandle pic x(2) comp-5 value 0.
procedure division. call pascal16 "VIOREADCHARSTR" using by reference line-buf by reference line-length by reference line-row by reference line-col by value viohandle display line-buf stop run.
To call OS/2 API routines from standard .int and .gnt programs without linking, you use the file cob32api.dll. To make these routines available you must make an explicit call to cob32api.dll before calling the first API in your application. The COBOL statement:
call "cob32api"
makes the OS/2 API routines available to your application. For example:
call "DosBeep" using by value 500 size 4 by value 500 size 4
could now be used to call the OS/2 DosBeep function.
32-bit on OS/2:
_Optlink is a calling convention that is an alternative to the
_System calling convention. _Optlink is the default calling convention by
some 32-bit compilers on OS/2 (for example IBM's C Set++). _Optlink calls
programs faster than the _System calling convention, as up to three
parameters can be passed in registers, instead of via the stack.
If your program needs to call a program that uses the _Optlink calling convention, or if your program is called by a program using _Optlink, you need to use call convention 16 in your program. For example, the following program calls a C function using the _Optlink calling convention:
special-names. call-convention 16 is optlink.
working-storage section. 01 a pic x(4) comp-5 value 1. 01 b pic x(4) comp-5 value 2. 01 c pic x(4) comp-5 value 3.
procedure division. call optlink "printvals" using by value a by reference b by value c stop run.
printvals.c is coded as:
#include <stdio.h> #include <stdlib.h> printvals (int a, int *b, int c) { printf ("a = %d, b=%d, c=%d\n", a, *b, c); }
printvals.c is compiled using IBM's C Set++ compiler using the command:
icc -c Mp -Sa printvals.c
printvals.dll is created using the command:
link386 /noi printvals, printvals.dll,, mfcmlib + os2386, printvals.def;
printvals.def contains the following lines:
library printvals data multiple nonshare loadoncall export printvals
Most of the IBM C Set++ library functions use the _Optlink linkage
convention, and so it is possible to call these functions directly from a
COBOL program using CALL-CONVENTION 16. For example, the following program
calls the C Set++ library functions _ultoa()
and _printf _ansi()
:
special-names. call-convention 16 is optlink.
working-storage section. 01 val pic x(4) comp-5 value 100. 01 printf-mask pic x(32) value "buffer = %s" & x"0A00". 01 radix pic x(4) comp-5 value 10. 01 buffer pic x(20). 01 pp procedure-pointer.
procedure division. set pp to entry "mfcmlib.dll" call optlink "_ultoa" using by value val by reference buffer by value radix call optlink "_printf_ansi" using by reference printf-mask by reference buffer stop run.
Note that the line:
set pp to entry "mfcmlib.dll"
is only required if you wish to call C library functions from .int or .gnt programs.
Object COBOL provides a number of C functions to enable you to mix C and COBOL programs.
A C program can call a COBOL program in the same way as it would call another C program. In the following example of C code, the COBOL program name is called using two arguments:
name (argument-1, argument-2);
The following functions are provided for mixing C and COBOL programs in an application:
cobcall
cobcancel
cobexit
cobfunc
cobgetfuncaddr
cobtidy
Before exiting a COBOL program, you must call cobtidy or cobexit.
These functions are described in the following sections. UNIX-specific functions are described in the section UNIX-specific C Functions later in this chapter.
Enables C programs to call COBOL programs. Parameters are passed BY REFERENCE.
long cobcall (name, argc, argv) char *name; int argc; char **argv;
This routine is used to call the COBOL program name using the arguments given in argv. cobcall is a COBOL type call as defined in the ANSI '74 standard and behaves in the same way as if the COBOL subprogram had been called from COBOL.
This is equivalent to calling a COBOL program directly from C code. For example, the COBOL program name is called from C code using two arguments, as follows:
name (argument-1, argument-2);
Cancels the COBOL program name previously called. This leaves the data contained in this program in the initial state as defined for the COBOL CANCEL verb (see your Language Reference for details).
void cobcancel (name) char *name;
Closes down the global COBOL run environment. It terminates the program's run in the same way as if a COBOL STOP RUN statement had been executed, emptying buffers, closing files and freeing any data areas allocated by the COBOL system.
void cobexit (exitstatus) int exitstatus;
You must use the cobexit functions to exit from non-COBOL modules rather than just using "exit".
The cobfunc function has the same effect as specifying cobcall then cobcancel. That is, it calls the specified program and then cancels it, leaving the data contained in the program in its initial state.
int cobfunc (name, argc, argv) char *name; int argc; char **argv;
This function, unlike cobcall, causes the program to behave as if it had been called using C function rules rather than COBOL call rules. cobfunc returns the return code of the called program.
Returns a function pointer to a COBOL program or C function. This
function provides equivalent functionality to COBOL's SET proc-ptr
TO ENTRY "name"
syntax.
cobgetfuncaddr(type, name) int type char *name
type |
Indicates what is returned if the required program is not found. If bit 0 is set, the address of an error routine is returned. If bit 0 is not set, a null pointer is returned. Bits 1 through 31 are reserved and must be clear. |
name |
The null-terminated program-name to get the start address of. |
Tidies up the global COBOL run environment.
void cobtidy( );
You can call this function from non-COBOL modules to empty buffers, close files and free any data areas allocated by the COBOL system. You should call this function when all COBOL modules have been exited, and you do not intend to reenter them. You can use this function if you want to close down the COBOL system, but are not yet ready to exit. Do not call cobtidy( ) directly from a COBOL program, as this gives undefined results.
16-bit:
This section describes how to interface with the high-level
languages or APIs using the 16-bit COBOL system:
Compiling the non-COBOL objects, and the subsequent linking with the COBOL objects, is different for each language. In every case it is necessary to link in an additional object which is used to establish the environment for the non-COBOL object before entering that object. Currently, only one of the initialization objects can be included in each program. Hence, it is not possible to call, for example, Microsoft C and Microsoft FORTRAN routines from the same COBOL program, or any pair of programs to be linked together.
The following languages are compatible with this COBOL system:
Where COBOL is called from a program in an application where the main program is written in one of these languages, the static linked run-time system must be used.
For the other languages, the following rules must be observed:
"C_" | for a routine in Microsoft C V4 and V5 |
"F_" | for a routine in Microsoft FORTRAN V5.0 |
"_ _" | for a routine in Microsoft FORTRAN V5.1 |
"P_" | for a routine in Microsoft Pascal |
"L_" | for a routine in Lattice C |
"_" | for a routine in Microsoft C V6 and C/C++ V7 |
The Compiler removes the "x_" prefix from the name, and sets up the necessary registers and parameter ordering for the relevant non-COBOL environment. On returning from the routine, returned values are then handled correctly.
So, for example, the following COBOL statement should be used to call the Microsoft C V5 routine "fun1":
call "C_fun1" using p1, p2, p3.
For example you can code:
procedure division. call "_CPROG"
but you cannot code:
01 func usage procedure-pointer. procedure division. set func to entry "_CPROG" call func.
This section describes how you can interface your COBOL programs with routines written in Microsoft C V6.0 and Microsoft C/C++ V7.0. These releases of the Microsoft C compiler contain run-time code which enables you to mix C functions with COBOL subprograms in your application. You can link them with the COBOL run-time libraries and you can animate a COBOL program which calls C functions.
Note: The floating point support used by this COBOL system is compatible with Microsoft C V6.0. If you interface applications written in COBOL with applications written in Microsoft C/C++ V7.0 or greater, and you need to use floating point data items, you will have to create separate executables for the C and COBOL functions.
When mixing C functions with COBOL subprograms on DOS, each C function must be statically linked into an .exe file together with any COBOL programs that call the C function. Any COBOL subprograms or C functions that are further called by the C function must also be included. This .exe file can be either the main program or it can be dynamically loaded by another COBOL program. If it is dynamically loaded then the first call to the .exe must be to one of the COBOL subprograms inside it. Your application might contain one or more .exe files containing both COBOL subprograms and C functions.
If you link your application with the shared run-time library (coblib.lib), you must ensure that the main program is COBOL. If you use the static linked run-time library (lcobol.lib), the main program can be either COBOL or Microsoft C.
To create a mixed COBOL and C application compile the programs as follows:
Then, with a COBOL main program, link the application using the command:
link cobol-object[+cobol/c-objects]+mfcvintf+cvdosif+ cvdoslb,,,cobol-library+cobapi+c-libraries;
and with a C main program, use the command:
link c-object[+cobol/c-objects]+,,, c-libraries+lcobol+cobapi;
where the parameters are:
If you are working with the shared run-time system then it is necessary to ensure that enough DOS memory is freed up by the COBOL run-time in order to satisfy any memory requests made by the C run-time support. This can be done by using the COBPOOL environment variable as described in the chapter The COBOL Interfacing Environment.
The overall maximum number of files that can be opened by any program at one time is governed by the FILES command specified in your DOS system file config.sys. The maximum value that you can specify in the FILES command is 255. The C and COBOL run-time systems might impose lower limits.
The C run-time libraries restrict the number of files that can be opened by the C subprograms and held open at the same time to 100.
If you are using the shared run-time system, the maximum number of files that can be open at the same time (whether opened by C or COBOL) is 100. This limit can be increased up to 255 by using the /F switch (see your Object COBOL User Guide).
If you are running under DOS, see the chapter XM in your Object COBOL User Guide.
When using OS/2 , the procedure for creating statically linked routines is the same as for DOS except for the link step with a COBOL main program. On OS/2 the link step is:
link cobol-object[+cobol/c-objects]+mfc6intf+c6os2if+ c6os2lb,,,cobol-library+c-libraries+os2;
where the parameters are:
If you want the statically linked routines to be called dynamically, you need to include a .def file when linking in order to create a .dll format file which the operating system can load. Thus the link step would become:
link cobol-object[+cobol/c-objects]+mfc6intf+c6os2if+ c6os2lb/nod,,,cobol-library+c-libraries+os2, def-file;
where the parameter is:
def-file |
A .def file which defines the
entry point
as the first cobol-object-name and
contains lines of the form:
LIBRARY INITINSTANCE |
The Compiler directive DEFFILE automatically creates a .def file. See the chapter Directives for Compiler in your Object COBOL User Guide for details on DEFFILE.
On OS/2 it is also possible to create a dynamically loadable .dll file written entirely in Microsoft C. This is done by following the standard C procedure for creating a Microsoft C .dll file as documented in your Microsoft C User's Guide. This .dll file can then be called from COBOL using the standard CALL statement.
Note that Microsoft C/C++ V7.0 does not contain support for OS/2.
For statically linked calls to C routines from COBOL, no special syntax is required. However, you must ensure that the correct external-symbol name is inserted into the .obj file to correspond with the public symbol that is included in the C object file. For Microsoft C, the C compiler always produces a public name which consists of the function-name preceded by a single underscore.
If you are calling a statically linked C routine from COBOL you should, therefore, call a routine which has the same name the C function but preceded by an underscore. For example, to invoke a C function called CALC you should use:
call "_CALC" using ...
If a .dll C routine is called dynamically on OS/2 then the call must not be a static link and so the underscore in front of the name is not necessary.
If a C function needs to call a COBOL subprogram then static or dynamic linking can be used. For any function calls from C, the C compiler always inserts an external symbol-name into the C object file consisting of the routine-name preceded by an underscore. To resolve this with the COBOL subprogram entry point , either the COBOL subprogram must have a Program-ID consisting of the underscore-prefixed name, or else the source file for the COBOL subprogram should be the underscore-prefixed name with a .cbl extension.
If your application has a C main program, it is not necessary to link in the COBOL bindings. Hence, linking is achieved as described above, but without mfcvintf.obj, cvaaaif.obj and cvaaalb.obj.
On DOS you cannot dynamically link to a COBOL subprogram from C.
On OS/2 you can dynamically link a COBOL subprogram for calling from Microsoft C V6. You need to include a .def file and then link the applications as follows:
link cobol-object,,,lcobol+os2,def-file; implib cobol-implib-lib def-file; link c-object,,,c-libs+os2+cobol-implib-lib;
where the parameters are:
If you are creating a mixed-language Windows executable file with a main module written in Microsoft C V6, link your Microsoft C V6 main program, your COBOL subprograms and the interface module mfc6intw.obj .
For example, to link a C V6 main program, C6-obj, and a COBOL subprogram, cobol-obj, use:
link c6-obj+cobol-obj+mfc6intw,,, llibcew+libw+lcobolw+lcobol,def-file /nod/noe;
The order of the link libraries is important. llibcew.lib, supplied with the Microsoft SDK, must be specified before lcobol.lib.
When creating a mixed-language Windows executable file with a Microsoft C V7 main module, you have two options depending on whether you are writing a QuickWindows application or a native Windows application.
A QuickWindows application is a character-based application that runs in its own window in Windows. In this mode you link your Microsoft C V7 main program (compiled with the -Mq option), your COBOL subprograms and the mfc7qws.obj interface module with specific libraries.
For example, to link a C V7 main program, C7-obj, and a COBOL subprogram, cobol-obj, as a QuickWindows application, use:
link c7-obj+cobol-obj+mfc7qws,,, llibcewq+lcobol+lcoboldw+libw,def-file /nod/noe;
A native Windows application uses the Windows Application Programmer's Interface (API) to manage all the operating system requests. In this mode, you need to link your Microsoft C V7 main program, your COBOL subprograms and the mfc7wins.obj interface module with a different set of libraries.
For example, to link a C V7 main program, C7-obj, and a COBOL subprogram, cobol-obj, as a native Windows application, use:
link c7-obj+cobol-obj+mfc7wins,,, llibcew+lcobol+lcoboldw+libw,def-file /nod/noe;
Again, the order of the link libraries is important. llibcewq.lib or llibcew.lib, supplied with Microsoft C/C++ V7, must be specified before lcobol.lib.
To animate a COBOL program which calls C routines you should compile your program as normal using the ANIM directive (OPT"0" is also needed, but is set automatically when you use ANIM). When animating you need to use the FLASH-CALLS directive if any of the C functions being called write to the user screen.
When linking this program for animation you must link with the shared run-time system and include the Linker directive /NOD. For example, to link a COBOL program Cobprog with C subprogram Cprog for animation under DOS, use the command:
link cobprog+cprog+mfc6intf+c6dosif+c6doslb,,, coblib+cobapi+llibce/nod;
Windows V3:
For more information on debugging under Windows V3, refer to the chapter
Microsoft Windows Applications in your Programmer's Guide
to File Handling.
Windows NT:
For more information on debugging under Windows NT, refer to the chapter
Microsoft Windows NT Applications in your Programmer's
Guide to File Handling.
If you are using CodeView to debug your programs, note that the CodeView supplied with Microsoft C/C++ V7 does not have a COBOL expression evaluator; therefore, CodeView cannot look at the COBOL stack. You can, however, still set breakpoints in, and debug, the COBOL code.
The following restrictions apply when interfacing between C and COBOL programs:
nfree()
, nheapchk()
, nheapset()
,
nheapwalk()
, nmalloc()
and nmsize()
.
_outtext
_outmem
_floodfill
Your Microsoft C objects must be compiled with the option /Awlf (large model with ss not = ds) since that is the only model supported when interfacing with COBOL. Copy the DOS-only file minitc.obj into your working directory before linking. Link your COBOL and C objects/libraries as follows:
link [cobol-objects]+minitc+[c-objects],,, lcobol+cobapi+[c-libraries];
For Microsoft C V5.0, it is necessary to add the /NOE option when linking, to ensure the libraries are searched correctly.
link [cobol-objects]+minitc+[c-objects],,, lcobol+cobapi+[c-libraries]/noe;
Support is provided for standard and QuickWindows Visual C++ applications. Your Microsoft Visual C++ application must be compiled with the with the option /Awlf (large model with ss not = ds) since this is the only model supported when interfacing with COBOL.
If your application is a QuickWindows application, you must also enable QuickWindows support with the option /Mq. See your Microsoft Visual C++ documentation for details.
For a standard Visual C++ application, link your COBOL and Visual C++ objects/libraries as follows:
link mvc1wins+cobol/c-objects,,, llibcew+lcobolw+lcobol+libw,def-file/nod/noe;
where the parameters are:
mvc1wins |
The object file which starts your Visual C++ application for COBOL. |
cobol/c-objects
|
The remaining COBOL and C object modules that are required to be linked. |
llibcew |
A C library for Windows applications. |
lcobolw/lcobol |
Micro Focus run-time libraries for static linked Windows applications. |
libw |
Windows API support. |
def-file |
Your Windows definition file. |
For a QuickWindows application, link your COBOL and Visual C++ objects/libraries as follows:
link mvc1qws+cobol/c-objects,,, llibcewq+llibcew+lcobolw+lcobol+libw, def-file/nod/noe;
where:
mvc1qws |
The object file which starts your QuickWindows C++ application for COBOL. |
cobol/c-objects
|
The remaining COBOL and C object modules that are required to be linked. |
llibcewq/llibcew |
C libraries for Windows applications. |
lcobolw/lcobol |
Micro Focus run-time libraries for static linked Windows applications. |
libw |
Windows API support. |
def-file |
Your Windows definition file. |
Your FORTRAN objects must be compiled as large model, which is the default mode. Copy the DOS-only file minitf.obj into your working directory before linking. Link your COBOL and FORTRAN objects/libraries as follows:
link [cobol-objects]+[fortran-objects]+minitf,,, lcobol+cobapi+[fortran-libraries];
Note: When you use minitf.obj, the stack size is limited to 8K and cannot be increased when linking.
For Microsoft FORTRAN V5.1, follow the procedures shown for Microsoft C V6.0 earlier in this chapter, except use files f51aaaif.obj and f51aaalb.obj instead of c6aaaif.obj and c6aaalb.obj, where aaa is dos on DOS and os2 on OS/2.
For example, on DOS, you link the application with the command:
link cobol-object[+cobol/fortran-objs]+mfc6intf+ f51dosif+f51doslb,,, cobol-library+cobapi+fortran-libs;
where the parameters are:
cobol/fortran-objs
|
The remaining COBOL and FORTRAN object modules that need to be linked. |
fortran-libs |
The list of large model FORTRAN libraries. |
f51dosif.obj and f51doslb.obj
|
.obj files supplied with this COBOL system
that initialize the FORTRAN run-time system. |
The other parameters are as shown in the section Microsoft C V6.0 and C/C++ V7.0 earlier in this chapter.
Compile your FORTRAN programs with the options /ND_DATA and either /AL (large model) or /AH (huge model).
Copy the DOS-only file minitp.obj into your working directory before linking. Link your COBOL and Pascal objects/libraries as follows:
link [cobol-objects]+minitp+[pascal-objects],,, lcobol+cobapi+[pascal-libraries];
Note: When using minitp.obj, the stack size is limited to 8K and cannot be increased during linking.
Your Lattice C objects must be compiled with the option -mL (large model) as that is the only model supported when interfacing with COBOL.
Before linking, create the file linitc.obj in your working directory by copying either linitc31.obj or linitc32.obj to it, depending on whether you are using Lattice C V3.1x or V3.2x. Also, copy the file linitio.obj into your working directory. Link your COBOL and C objects/libraries as follows:
link [cobol-objects]+linitc+linitio+[c-objects],,, lcobol+cobapi+LC+[c-libraries];
The library lc.lib is supplied with your copy of Lattice C.
Before running your program you might want to allocate a memory pool for the C routines. If no pool is specified, 64K is allocated. If you want to specify a smaller/larger pool size then set up the environment variable POOL containing the size of the pool you want to be allocated in 1024-byte blocks. To allocate 10240 bytes for example, enter:
set pool 10
16-bit:
Programs created using the 16-bit COBOL system cannot directly interface
to C Set++, which uses 32-bit technology. For 16-bit code to call
32-bit code, and vice versa, a thunking
interface must exist between them which will translate calls from
16-bit to 32-bit and from 32-bit to 16-bit. A thunk interface is
transparent to both the calling and called program. See your OS/2
Technical Library Application Guide for a more detailed
explanation of thunking.
C Set++ provides a mechanism for calling and being called by 16-bit routines.
Note: The section Interfacing Between 16-bit and 32-bit Modules in the chapter The COBOL Interfacing Environment describes the thunking interface provided by Micro Focus. The following text describes the C Set++ interface.
For a C Set++ function to call a 16-bit COBOL program, the COBOL program
must be an exported function within a 16-bit .dll linked with lcobol.lib.
There are three calling conventions provided by C Set++: far16
cdecl
, far16 fastcall
, and far16 pascal
.
The easiest way to define a COBOL routine in C Set++ is to set up a
function prototype, specifying the _Far16
qualifier.
Subsequent calls to the function will cause C Set++ to embed the necessary
thunking code to allow the 16-bit function to be invoked.
For example, the C program ctocbl.c:
void _Far16 my16func(int *,int *,USHORT); int a=10; int b=20; USHORT c=30; main() { my16func(&a,&b,c); }
defines my16func
as a 16-bit function which is to be
called with three parameters. The first two are the addresses of two four
byte integers, equivalent to PIC X(4) COMP-5 BY REFERENCE parameters. The
last is the value of a two byte integer, equivalent to a PIC X(2) COMP-5
BY VALUE parameter.
Note: C Set++ generates an external reference to the 16-bit
function with a leading underscore (_my16func
in this
example).
my16func.cbl would look something like:
linkage section. 01 a pic x(4) comp-5. 01 b pic x(4) comp-5. 01 c pic x(2) comp-5.
procedure division using by reference a by reference b by value c. display "In 16-bit COBOL function" exhibit named a b c exit program .
The .def file used to link my16func
to a .dll
would look like:
LIBRARY my16func CODE LOADONCALL DATA MULTIPLE EXPORTS _MY16FUNC=MY16FUNC
The following commands could then be used to compile and link my16func.cbl to a 16-bit .dll, compile and link ctocbl.exe, and execute ctocbl.exe:
cobol my16bit; link /nod my16bit,my16bit.dll,,lcobol+os2286,my16bit; implib my16bit.lib my16bit.def icc -c -Ms ctocbl.c link386 /noi /nod /pm:vio ctocbl,ctocbl.exe,,dde4sbsi+my16bit+os2386; ctocbl
For a C Set++ program to be called from a 16-bit COBOL program, the C
Set++ program should be defined using the _Far16
qualifier,
and each of its parameters defined using the _Seg16
qualifier. The C program would then be compiled and linked to a .dll.
For example, the C program my32func.c:
#include <stdio.h> #include <stdlib.h> _Far16 _Cdecl my32func(int * _Seg16 a,int * _Seg16 b,int * _Seg16 c) { printf("a = %d, b = %d, c = %d\n",*a,*b,*c); }
defines the function my32func
as being callable from a
16-bit program and uses C calling convention. my32func
expects three four byte COMP-5 BY REFERENCE parameters to be passed to it.
Note: C Set++ generates a public symbol for the 32-bit function
with a leading underscore (_my32func
in this example).
The .def file used to link my32func
to a .dll
would look like:
LIBRARY my32func CODE LOADONCALL DATA MULTIPLE SEGMENTS CODE32 ALIAS EXPORTS my32func=_my32func
The program call32.cbl would call my32func
as
follows:
working-storage section. 01. 03 a pic x(4) comp-5 value 10. 03 b pic x(4) comp-5 value 20. 03 c pic x(4) comp-5 value 30. procedure division. call "my32func" using a b c exit program stop run .
The following commands could then be used to compile and link the
my32func
to a 32-bit .dll, create call32.gnt,
and execute call32.gnt:
icc -c -Sa my32func.c link386 /noi my32func,my32func.dll,,dde4sbsi+os2386,my32func; cobol call32 gnt; run call32
Programs written in IBM's REXX language can readily call 16-bit technology COBOL routines under OS/2. For example, the following REXX program calls a COBOL subprogram, passing parameters.
/* Rexx program that calls a COBOL routine */ temp = RxFuncDrop(REXXFUNC) if temp = 0 then say 'REXXFUNC DROPPED' retcode = RxFuncAdd(REXXFUNC,REXXFUNC,REXXFUNC); Arg1 = 25 Arg2 = 500 Arg3 = 1234567890 Arg4 = "Hello" /* REXXFUNC lists displays all the parameters passed to it and returns the value "DIR *.* " */ if retcode = 0 then do say 'REXXFUNC ADDED TO TABLE' REXXFUNC(Arg1, Arg2, Arg3, Arg4, "Last Parameter is Text!") say 'REXXFUNC EXECUTED' end; exit
The COBOL subprogram, rexxfunc.cbl, can be written as follows:
$set ans85 comp noalter defaultbyte(00) litval-size(2) mf(6) program-id. REXXFUNC. special-names. call-convention 3 is pascal. data division. working-storage section. 01 ws-rxstring. 05 ws-strlen pic S9(9) comp-5. 05 ws-strptr pointer. 01 ws-string pic x(250). 01 idx pic 99 comp. linkage section. 01 ls-name pic x(8). 01 ls-argc pic S9(4) comp-5. 01 ls-argv pointer. 01 ls-queue pointer. 01 ls-retstr pointer. 01 ARGV occurs 20 05 ARGV-strlen pic S9(9) comp-5. 05 ARGV-strptr pointer. 01 RXSTRING. 05 RXSTRING-strlen pic 9(9) comp-5. 05 RXSTRING-strptr pointer 01 STRING-BUFFER pic x(250). procedure division pascal using by reference ls-name, by value ls-argc, ls-argv, ls-queue, ls-retstr. * Display the Function Name display 'Function Name is = ' ls-name. * Display the Number of Arguments display 'Number of Arguments = ' ls-argc. * Display the Lengths and Contents of all Arguments set address of ARGV (1) to ls-argv. perform test before varying idx from 1 by 1 until idx greater ls-argc, move ARGV (idx) to ws-rxstring display 'Argument (' idx ') length = ' ws-strlen set address of string-buffer to ws-strptr move spaces to ws-string move string-buffer (1: ws-strlen) to ws-string display 'Argument (' idx ') string = ' ws-string end-perform.
* Return a Result to REXX set address of RXSTRING to ls-retstr. move zero to RXSTRING-strlen. set address of STRING-BUFFER to RXSTRING-strptr. move 'DIR *.* ' to STRING-BUFFER (1:8). move 8 to RXSTRING-strlen. goback.
Finally, you compile and link the COBOL subprogram as follows (note that you cannot link with coblib.lib in place of lcobol.lib):
cobol rexxfunc deffile; link rexxfunc,,,lcobol+doscalls,rexxfunc.def/nod;
OS/2:
You can access data longer than 64K allocated by a non-COBOL
function as long as it is allocated by the DOSAllocHuge OS/2 API function.
This facility is supported only under OS/2 and when using the shared
run-time system, coblib.dll.
16-bit:
The
mixed language support functions enable non-COBOL functions to
interface at a low-level with the 16-bit COBOL run-time system. The 16-bit
COBOL system provides:
This section shows how to develop mixed language applications in which non-COBOL programs call Micro Focus COBOL sub-programs while running on Microsoft Windows. The topic of COBOL programs calling non-COBOL subprograms is covered earlier in this chapter.
This section shows how to develop mixed language applications in which non-COBOL programs call Micro Focus COBOL sub-programs while running on Microsoft Windows. The topic of COBOL programs calling non-COBOL subprograms is covered earlier in this chapter.
This section assumes a knowledge of both the architecture of Microsoft Windows and COBOL programming.
In general there are two approaches in arranging for COBOL to interact with other languages:
Successfully static linking and then running an application written in two different languages is, in general, difficult and for some implementations, impossible. An example of two languages that can not be statically linked together is Borland C++ V3.1 and Micro Focus COBOL, but it is possible to use the two languages in one application if either of the two portions of the application are separated into a separate DLL.
Microsoft C V7 can be used in two modes:
The QuickWindows mode allows you to migrate standard C library programs
onto Windows. You select this mode by compiling your C program with the
option -Mq
. An example QuickWindows application is:
#include <stdio.h> int main(int argc,char **argv) { printf("Hello world"); return 0; }
The native mode requires you to understand more about the architecture of Windows itself. In this mode you must respond to messages explicitly. See your Microsoft Programmers Guide supplied with your C compiler for details.
The following example shows a simple Windows application that does not create any windows:
#include <windows.h> int PASCAL WinMain(HANDLE hInst, HANDLE hPrevInstance, LPSTR lpszCmd, int nCmdShow ) { MessageBox((HND)0, "Hello world", "COBOL demo", MB_OK ); return 0; }
Linking a C program to COBOL with Microsoft C V7 is very straightforward. Compile the COBOL and C parts of the application into .obj form and then link the application in either of the two following ways.
For a QuickWindows program:
cobol cobol_sub omf(obj); cl /c /G2 /Aulf /Mq /Gs C_filename.obj link C_filename.obj+cobol_sub+mfc7qws,exe_name,, llibcewq+lcoboldw+lcobol+libw, application.def /nod/noe;
For a native Windows program:
cobol cobol_sub omf(obj); cl /c /G2 /Aulf /W4 /Gsw C_filename.c link C_filename.obj+cobol_sub+mfc7wins,exe_name,, llibcew+lcoboldw+lcobol+libw, application.def /nod/noe;
For information on linking see your Object COBOL User Guide.
It is important that you use the options shown for compiling the
program; especially that selecting the type of memory model. COBOL
requires the application to use the large model, which is specified with
the /Aulf
option.
You can import a COBOL .dll into a C application very simply by creating a COBOL .dll and then using the Microsoft IMPLIB utility to generate a corresponding .lib for the .dll. Then link the C program with this .lib and the calls to COBOL subprograms from within the C program will be resolved by linking with that .lib. Once the application is started the COBOL .dll is automatically loaded.
The program should be compiled and linked as follows:
cobol cobol_sub omf(obj) litlink; link cobol_sub+libinit+cblwinl,cobol_dll,, lcoboldw+lcobol+cobw,dll_application.def/noe/nod; implib cobol_dll.lib cobol_dll cl /c /G2 /Aulf /Mq /Gsw C_filename.obj link C_filename.obj+cobol_sub+mfc7qws,exe_name,, llibcewq+libw,application.def /nod/noe;
The above method is for a QuickWindows application. For a native Windows
application use a similar method, just changing the compilation of the C
program to reflect the fact it is a native windows application and use the
mfc7wins
interface .obj.
Note: The file extension of the file has to be .dll; you cannot use the extension .dlw because the Microsoft .lib file generated by the Import utility does not understand the extension .dlw.
For a native Windows application, you should also export every entry point you wish to call from C, within the COBOL application .def file.
An alternative method to using the import utility to access the .dll, is to load the COBOL .dll itself and call the entry points directly. This way can be less convenient but does have the advantage that the COBOL .dll is only loaded and used when it is required.
The program should be compiled and linked as follows:
cobol cobol_sub omf(obj); link cobol_sub+libinit+cblwinl,cobol_dll,, lcoboldw+lcobol+cobw,dll_application.def/noe/nod; cl /c /G2 /Aulf /W4 /Gsw C_filename.c link C_filename.obj,exe_name,, llibcew+libw,application.def /nod/noe;
An example of this would be as follows:
#include <windows.h> int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmd, int nCmdShow ) { HINSTANCE hinstProg; FARPROC lpfnWelcome; FARPROC lpfnGoodMorn; char *Buffer1 = "Parameter1"; char *Buffer2 = "Parameter2"; hinstProg=LoadLibrary("cobdll.dlw"); /* Load COBOL DLL now */ if (hinstProg < HINSTANCE_ERROR) /* Have we loaded it? */ { char *Message = "Failed to load cprog.dlw\nReturnCode = %d"; char Buffer[255]; wsprintf(Buffer,Message,hinstProg); MessageBox(NULL,&Buffer,"Micro Focus",MB_OK | MB_ICONSTOP); } else { /* Find the address of a the COBOL functions, called: WelcomeFunction and GoodMorning */ lpfnWelcome = GetProcAddress(hinstProg,"WelcomeFunction"); lpfnGoodMorn = GetProcAddress(hinstProg,"GoodMorning"); if (lpfnWelcome == NULL) MessageBox(NULL,"WelcomeMessage Not Found in DLW", "Micro Focus",MB_OK | MB_ICONSTOP); else { (*lpfnWelcome)(Buffer1,Buffer2); (*lpfnGoodMorn)(Buffer1,(int)200); } FreeLibrary(hinstProg); } return 0; }
You can only mix COBOL with Borland C++ by calling COBOL .dlls from C as described earlier. You should link using the Borland C linker (TLINK) or link the application via the GUI.
The C program should be compiled, under Borland C, with the following options on:
Large module application DS != SS (Never)
A Microsoft Visual Basic application is capable of calling a COBOL .dll file, linked using the static linked run-time system, under Windows.
DOS:
Microsoft Visual Basic cannot be used with COBOL under DOS.
See the chapter Using GUIs From Third Party Tools in your Programmer's Guide to Creating User Interfaces for further details.
Support has been added for mixed Visual C++ and COBOL applications. The support provided is equivalent to that for Microsoft C V7, the only difference being that the names of the support modules include the version number 1 in place of the number 7. See the earlier section on Microsoft C V7 and COBOL for details on how to mix C and COBOL within an application.
To link an application using either version of Microsoft C and COBOL use one of the following methods as appropriate.
For a QuickWindows program using Microsoft C V7:
cobol cobol_sub omf(obj); cl /c /G2 /Aulf /Mq /Gs C_filename.obj link C_filename.obj+cobol_sub+mfc7qws,exe_name,, llibcewq+lcobol+lcoboldw+libw, application.def /NOE/NOD;
For a QuickWindows program using Microsoft Visual C++ V1.0:
cobol cobol_sub omf(obj); cl /c /G2 /Aulf /Mq /Gs C_filename.obj link C_filename.obj+cobol_sub+mvc1qws,exe_name,, llibcewq+lcobol+lcoboldw+libw, application.def /NOE/NOD;
The basic rules for interlanguage working with COBOL under Windows are as follows:
-Gr
with Microsoft C compilers,
as this requests parameter passing using registers. 16-bit:
The following library routine is available:
PC_STEP_SELECTOR | steps a COBOL data segment. |
Mixed language support routines should not be called from a COBOL program.
16-bit:
On the 16-bit COBOL system this routine provides the ability for a
non-COBOL function to address a HUGE COBOL parameter or a COBOL parameter
which crosses a segment boundary.
From assembler:
extrn PC_STEP_SELECTOR :far push @WORD selector CALL PC_STEP_SELECTOR ADD SP, 4
From C:
short int PC_STEP_SELECTOR(selector); short int *selector;
selector |
A pointer to a word |
selector |
A pointer to the selector/segment to be stepped. This value must be a valid selector/segment address of a COBOL Working-Storage Section data item. |
selector |
If the function is successful, the stepped selector is
returned in this parameter. |
From Assembler: Register AX |
The status: 0 no error >0 function failed. |
From C:RETURN-CODE |
The status: 0 no error >0 function failed. |
This routine is available only on the 16-bit COBOL system for DOS, Windows and OS/2. It is supported in both the coblib.lib and lcobol.lib run-time libraries.
The routine uses the C calling convention.
This part of the chapter describes interfacing with the UNIX operating system and how to combine COBOL and C programs on UNIX.
The COBOL run-time system sets the terminal to a mode suitable for COBOL. Calls to the operating system routine, system(), fail because they do not affect the mode, as terminal settings are not modified before or after the call.
You should replace your calls to system() with calls to "SYSTEM": this is a subroutine provided with this COBOL system so that your operating system can perform the same operations as system( ), but return the terminal to shell mode before executing the command. The format of this command is:
call "SYSTEM" using cmd-line
where the parameter is:
cmd-line |
A null-terminated command line |
Upon completion of the call "SYSTEM" statement, the terminal is reset to the mode suitable for COBOL. For example:
01 cmd-line pic x(3) value "sh" & x"00". 01 cmd-line2 pic x(30) value "cp f1 f2 >errfile 2>&1" & x"00". procedure division. display "Test" at 1101 call "SYSTEM" using cmd-line display "Back in program" at 1201 call "SYSTEM" using cmd-line2 display "Back in program" at 1301 stop run.
As COBOL is unaware of any output from either call "system" or call "SYSTEM", you must ensure that your screen is either not updated by a call or is redisplayed after execution of the call.
In the example above the first command-line executed is the sh command, which will update the screen with the system prompt and any commands that may be entered. The second command-line copies file f1 to file f2 and redirects both the standard output and the standard error to the file cp.log which your program can open in order to read any output generated by running the command. The order in which you make the redirections is significant.
The section Interfacing with C (32-bit) earlier in this chapter presents a number of C functions that enable you to mix C and COBOL programs. The functions in that section apply to all 32-bit COBOL systems. The functions in the following section are not portable to non-UNIX environments. Wherever possible, use the equivalent COBOL library routines. Refer to the chapter Library Routines for more details.
A C program can call a COBOL program in the same way as it would call another C program. In the following example of C code, the COBOL program name is called using two arguments:
name (argument-1, argument-2);
In addition to the functions specified in the section Interfacing with C (32-bit), the following functions are provided for mixing C and COBOL programs in a UNIX environment only:
cobinit
cobkeypad
Before calling a COBOL program, you must call cobinit.
Initializes the COBOL environment, before calling a COBOL program from a non-COBOL program.
cobinit( )
If your program runs a mixture of non-COBOL and COBOL code, and the main program is not written in COBOL, you must call cobinit before calling a COBOL program. If you do not, you might receive an initialization error when you enter your COBOL code.
Toggles the numeric keypad between local mode and transmit mode.
void cobkeypad(mode)
mode |
1 for transmit mode 0 for local mode. |
To function correctly, the smkx (transmit mode) and rmkx (local mode) entries must be present in the terminfo database for the terminal type you are using. By default, the run-time system puts the numeric keypad into transmit mode when smkx is present in your terminfo database.
The sample program account.cbl is located in $COBDIR/demo. It demonstrates a C program calling a COBOL program. It shows:
The following sections describe the functions cobsavenv and coblongjmp, which enable you to mix C and COBOL programs. They provide functions similar to the C function setjmp() and longjmp() (see your UNIX for details of setjmp() and longjmp()). The purpose of the cobsavenv and coblongjmp functions is to provide the capability of a non-local GO TO, for use in error or exception handling.
The cobsavenv function is called with a single parameter. This function saves the environment of the current COBOL program in the buffer provided by the parameter, and the return value should be passed to setjmp(), which immmediately returns zero.
A subsequent call to coblongjmp either from elsewhere in the program that called cobsavenv and setjmp(), or from one of its subprograms, causes execution to be resumed at the point immediately after the call to cobsavenv and setjmp().
After calling coblongjmp, setjmp() returns a non-zero value, thus enabling the value to be tested after the cobsavenv and setjmp() call.
The following restrictions apply when using these functions:
The parameter can be defined and used as follows:
#include <setjmp.h>
struct { int cobbuf[3]; char * cobbuf2[3]; jmp_buf cbuf; char * cobbuf3; } cobjmp_buf; * * * if (setjmp(cobsavenv(&cobjmp_buf)) != 0) { printf("Returned from coblongjmp\n"); } * * * coblongjmp(&cobjmp_buf);
Object COBOL supports a number of screen handling routines that you can use from C programs. These enable the run-time system and run-time support libraries to handle output from both C programs called from COBOL programs and from ACCEPT/DISPLAY operations performed by the calling COBOL programs. Normally if any screen handling is carried out outside the control of COBOL (for example, under the control of C) COBOL is not aware of the output from the screen handling operation when control returns to COBOL. The effect of subsequent screen handling operations could thus be undefined. The routines provided enable you to avoid this problem.
The following routines are currently supported and are described in the following sections:
cobaddch
cobaddstr
cobaddstrc
cobclear
cobcols
cobgetch
coblines
cobmove
cobprintf
cobscroll
When using these routines you must include the header file cobscreen.h , which is provided with this COBOL system. This file defines the attributes you can use, the type (cobchtype) and declares any external functions the routine needs. The type cobchtype defines a two-byte pair, with the first byte containing a character and the second the attribute for that character.
For those routines where attributes are allowed, you can use the bit-wise OR operator to combine any of the attributes defined in the cobscreen.h file (see the chapter Advanced Language Features for details of the CBL_OR routine). These attributes are listed below:
Attribute
|
Description
|
---|---|
A_NORMAL A_BOLD A_UNDER |
Normal, no attribute Bold or highlight Underline |
A_REVERSE A_BLINK A_DIM |
Reverse Blink Dim or lowlight |
Several of these routines have been replaced by COBOL system library routines, described in your Programmer's Guide to Creating User Interfaces, which you should use in preference.
Displays the specified character on the screen at the virtual cursor's current position.
void cobaddch (ch) cobchtype ch;
ch |
The required character. This can include attributes. |
Displays the specified string on the screen starting at the virtual cursor's current position.
int cobaddstr (s) cobchtype *s;
s |
The required string. This can be up to 255 characters long and can include attributes. The only control character that s can include is \n (new line). |
Displays the specified string on the screen starting at the virtual cursor's current position.
int cobaddstrc (c) char *c;
c |
The required string. This can be up to 255 characters long and cannot include attributes; the normal attribute is used. The only control character that s can include is \n (new line). |
Clears the screen and positions the cursor at line 0, column 0.
void cobclear ( )
The Library routine CBL_CLEAR_SCREEN has the same effect and should be used in preference to cobclear.
Returns the number of columns on the screen.
int cobcols ( )
The Library routine CBL_GET_SCR_SIZE has the same effect and should be used in preference to cobcols.
Gets a character from the keyboard.
int cobgetch ( )
The Library routine CBL_READ_KBD_CHAR has the same effect and should be used in preference to cobgetch.
Returns the number of lines on the screen.
int coblines ( )
The Library routine CBL_GET_SCR_SIZE has the same effect and should be used in preference to coblines.
Moves the virtual cursor to the specified line and column on the screen.
void cobmove (y, x) int y,x;
y |
The line number to move the virtual cursor to |
x |
The column number to move the virtual cursor to |
The Library routine CBL_PUT_SCR_POS has the same effect and should be used in preference to cobmove.
Displays the specified formatted string on the screen at the virtual cursor's current position.
int cobprintf (fmt) char *fmt;
fmt |
The required format in printf() style.
This can be a maximum of 255 characters long in its extended form, and
cannot include attributes. The only control character fmt
can contain is \n (new line). |
This routine returns either the number of arguments output or -1 (for an error condition).
Scrolls the screen display, starting and finishing at the specified lines, up one line.
void cobscroll (top,bot) int top,bot;
top |
The first line to be scrolled up one line. This must be two lines less than the physical screen size to prevent the top line from scrolling off the screen. |
bot |
The last line to be scrolled up one line |
In COBOL, the following syntax enables you to read and change the environment at run time.
DISPLAY ... UPON ENVIRONMENT-NAME ...
ACCEPT ... FROM ENVIRONMENT-NAME ...
You can also call the following routines from C to do the same things:
cobgetenv cobputenv cobrescanenv
Use the COBOL syntax in preference to the C routines.
Provides the same functionality as the C library call getenv().
char *cobgetenv(name) char *name;
name |
The string to search the environment for.
This environment string is in the following format:
NAME=VALUE where |
Allows you to dynamically change the environment at run time.
int cobputenv (string) char *string
string |
The value of string
is placed in the environment, which the run-time system then rescans for
file-name mapping variables. By convention, environment strings have the
format:
NAME=VALUE but the run-time system does not check that |
string
is passed into the C library call putenv(),
and so the value of string
cannot be modified or
freed (if at all) until the environment variable has been redefined using
another cobputenv. So, for example, if cobputenv is called from a COBOL
subprogram then the subprogram must not be canceled.
This routine returns a value of zero if the operation was successful; any other value indicates an unsuccessful operation. Illegal environment names lead to undefined results.
Causes the run-time system to rescan the environment for file-name mapping entries.
int cobrescanenv()
This routine is useful if the environment has been changed without the knowledge of the run-time system. It returns a value of zero if the call was successful; any other value indicates an unsuccessful call.
The following example demonstrates calling a C routine directly from a COBOL program using the cobgetenv routine. (This is only for example purposes. We recommend you do not use cobgetenv from COBOL.) It also shows how the C data item errno may be accessed.
* Example of direct calling of C routines from a COBOL program * using cobgetenv, a general library routine. $set rtncode-size(4) * The return code size of 4 bytes is required for * returning a pointer to set the compiler directive. working-storage section. 01 sleep-time pic 9(9) comp-5 value 10. 01 errno is external pic 9(9) comp-5.
* errno is the external Unix data item to which the error number * returned by a Unix System service Routine is assigned. 01 cobdir pic x(100) value spaces. 01 env-name pic x(100). 01 return-pointer usage pointer. linkage section. 01 name-buff pic x(100). * Linkage items have no physical storage but the names can be * used to reference addresses given by the SET verb. * Return-pointer is used to dereference the pointer and set * name-buf to point to the character string associated with the * pointer returned by the call to cobgetenv. procedure division. get-cobdir section. move 0 to errno * "cobgetenv" expects a pointer to an array of characters * terminated by a low-value. * COBOL can pass its parameters by REFERENCE, CONTENT or VALUE: * By REFERENCE passes to the function the address of the * parameter (in C a PIC X(n) would look like a char*, except it * would not be NULL terminated). * By CONTENT passes to the function the address of a * temporary data item (to which there is an implied move from * the parameter before the call is made). * The only difference between by CONTENT and by REFERENCE is * that the called module cannot effect the value of the * parameter as seen from the calling module. * By VALUE passes to the function the actual value of the * data item rather than its address. By VALUE should only be * used to call non-COBOL modules (because the PROCEDURE DIVISION * USING statement has no way of specifying that a VALUE * parameter is to be expected). If the size of the * parameter being passed exceeds 4 bytes then it is passed * as if BY REFERENCE had been specified, also any numeric * literals passed in this way are passed to the called * module as a 4 byte comp numeric in machine byte order (in C as * a long on a 32 bit machine). * Ensure that parameter to "cobgetenv" is NULL terminated. string "COBDIR" low-values delimited by size into env-name call "cobgetenv" using env-name returning return-pointer if return-pointer = null display "COBDIR not found" stop run end-if set address of name-buff to return-pointer * Function result of "cobgetenv" is a NULL terminated string, * COBOL requires SPACE termination. string name-buff delimited by low-values into cobdir display cobdir call "sleep" using by value sleep-time display "that was a nice sleep" stop run.
This section describes the calls you need to make if you want to use signal handling in your application, especially if you are mixing COBOL and C in your application.
The run-time system sets up default signal handlers for all signals whose operating system default action is to cause termination. These default handlers make sure that the COBOL system is properly cleaned up before terminating. Hence, any open files are closed (to prevent file corruption), the terminal is reset to a sane state, user posted exit and error procedures are executed, and so on.
The run-time system also uses signal handling to provide various functionality. For example, interrupt key detection, Animator Zoom interrupt key, Job Control, ALT/CTRL detection, and so on.
This COBOL system provides two routines that you can use to complement or override the signal handling used by the run-time system:
cobpostsighandler
cobremovesighandler
These routines allow multiple handlers for each signal and enable you to prioritize use of these handlers. You can use them from inside a C program only, not least because you need the include file signal.h for the signal values, which vary between platforms.
Use these routines instead of the operating system signal calls, (signal(), sigaction(), and so on) which provide only the ability to post a single signal handler for each call and so often prevent more than one application being able to work together reliably.
For example, if you use one of the operating system signal calls to post a signal handler before invoking a COBOL program, your signal handler is overridden. Whereas, if you use one of the operating system signal calls after invoking a COBOL program, the default run-time system handler, additional COBOL functionality and user posted signal handlers are all overridden, causing unexpected results.
Adds the specified handler to the list of handlers for the specified signal, at the specified priority.
void *cobpostsighandler (signal, priority, handler); int signal; int priority; int (*handler)();
signal |
The signal, as defined in the signal.h include file. |
priority |
The priority of handler
in the range 1 to 254, where 254 is the highest priority. Values 127 and
129 through 139 are reserved for use by Micro Focus. |
handler |
The name of your signal handler. This must be a C function returning an integer value. |
This routine returns a pointer that you can use to remove your signal handler later. If the return value is NULL, a signal handler was not posted for this signal. This could be due to lack of memory or the signal being "disabled" by the tunable signal_regime.
32-bit:
This routine is available with 32-bit COBOL systems only.
Removes a posted handler from the list of handlers for the appropriate signal.
void cobremovesighandler (sighandler); void *sighandler;
sighandler |
is the pointer returned when posting your signal handler using a previous cobpostsighandler call. |
There is no return value from this call.
32-bit:
This routine is available with 32-bit COBOL systems only.
You use the cobpostsighandler routine to post signal handlers.
The run-time system also uses the cobpostsighandler routine to post all of its signal handling. Default handlers are posted for all signals whose operating system default action causes termination. The default handlers either make sure that the COBOL system has been cleaned up before terminating, or cause the signal to be ignored. These default handlers assume that the signals were generated by the operating system due to a serious error or that a signal has been unexpectedly raised. Hence, they usually produce a run-time system message, such as 114 or 115.
If the same handler is posted twice, and neither of them is removed using the cobremovesighandler routine, the handler is executed twice (assuming the handler, and all handlers executed in between, do not return a value of zero).
If two handlers are posted with the same priority, the last one posted is executed first.
Once you have posted a handler, you do not need to repost it. The handler is called each time that signal is received (assuming that the first receipt of the signal does not cause termination). If you want to execute your handler only once, you must remove it, using the cobremovesighandler routine, in your signal handler.
While processing signal handlers, the signal is blocked. This prevents recursion if the same signal is received in rapid succession.
A signal handler must return normally. That is, you must not use any other function that terminates a signal handler function, such as longjmp(), and you must use the C syntax to return a value:
return(num);
If you do use another function to return, the signal remains blocked, preventing any further signals from being processed.
When a signal is received, the handler posted with the highest priority for that signal is called. Your handler should take any appropriate action (such as setting a flag to be acted on later) and then return. If the handler returns a non-zero value, the handler with the next highest priority for that signal is called. If the signal handler returns zero, no further signal handlers are processed.
The run-time system posts its default signal handlers with priority 127. So, to override them, or to process your signal handler before them, post your handler with priority 128. Use a priority of 126 (or less) if you want to make sure that your handler is processed after the default run-time system handler (if the default run-time system handler does not exit).
The run-time system provides various functionality using signal handlers. These handlers are posted with a priority in the range of 129 to 139.
A signal handler should do very little. A signal can be generated at any time so the routine that was being executed could be in an "unsafe" state (eg. in the middle of modifying global variables) and so trying to execute it in your signal handler could cause problems. The routine being executed could be a C system routine such as malloc().
There are a small subset of system C routines that are safe to call from signal handlers. Do not try to call any other C system routines, or any COBOL routines, from your signal handler. See your system documentation for more information on the safe C system routines.
Some signals are generated by the operating system when a serious error has occurred. Catching these signals can cause unexpected and potentially dangerous results. You should not catch any of the following signals:
SIGBUS
SIGSEGV
SIGEMT
SIGILL
SIGIOT / SIGABRT
SIGSYS
SIGFPE
SIGTRAP
Preventing the run-time system from processing certain signals can break some run-time system functionality. If you catch any of these signals (with a priority of 140 or more), your signal handler must return a non-zero value so that the run-time system's handler is also executed. The signals concerned include:
SIGCHLD
SIGPIPE
SIGUSR1
SIGUSR2
SIGVTALRM
SIGWINCH
SIGCONT
SIGTSTP
SIGTTIN
SIGTTOU
Note Micro Focus reserves the right to change their default signal handlers or use extra signals in the future.
The following example illustrates setting up a handler for the SIGALRM signal.
#include <stdio.h> #include <signal.h> int mysigcatch(sig) int sig;
{ cobprintf("Here is new signal handler\n"); return(0); /* Do not process any further handlers */ } void mysigexit(sighand) void *sighand; { cobprintf("Cancelling handler\n"); cobremovesighandler(sighand); /* Remove the handler */ } main(argc, argv) int argc; char *argv[]; { void *sighandle; extern void *cobpostsighandler(); sighandle = cobpostsighandler(SIGALRM, 128, mysigcatch); cobfunc("cobolprog", argc, argv); /* call a cobol program using cobfunc function */ alarm(1); /* raise the signal */ pause(); /* wait for the signal */ sleep(4); mysigexit(sighandle); cobexit(0); /* Cobexit - close down COBOL run-time environment */ }
The cobpostsighandler routine enables two or more handlers to be posted for the same signal. When that signal is generated by the operating system (such as a SIGINT generated when the interrupt key is pressed), each handler can take appropriate action and then let other handlers be executed (by returning a non-zero value). Alternatively, they can decide to make the signal "ignored" by returning a value zero to prevent other handlers from being executed. However, so that your handler can work with other handlers for the same signal, a handler of priority 140 (or more) should return non-zero to let other handlers have the opportunity to also be notified. A handler of priority 128 can return zero if you do not want the run-time system default action to be executed (which may cause termination).
When you raise a signal (such as by using alarm() to raise a SIGALRM signal, or when raising a signal to a different run-unit or application), then it is probable that only your signal handler wants to be called and other posted signal handlers are not expecting the signal. Hence, in this case, you should set a global resource before raising the signal and then check that resource in your signal handler. If the resource is set (as expected), then the signal was raised by you, so you can take the appropriate action and return zero to prevent other handlers from being unexpectedly called. If the resource is unset, then someone else (or something else, such as the operating system) raised the signal and so you can take no action and should let other handlers execute by returning a non-zero value.
Examples of global resources are global variables (if in the same run-unit), shared memory, pipes, files, and so on. Hence, in the above example, we could have set a global variable before raising the alarm() signal. We would then need to check the global variable in the signal handler, mysigcatch. If it was set, we would carry out our action, reset the variable and return zero. However, if the global variable had not been set, then some other code is likely to have raised the signal. Hence, we would have not wanted to carry out our action and would instead need to return a non-zero value immediately. This allows the appropriate action to be taken in some other handler.
If you have any signal handlers that are posted using an operating system signal call, such as signal() or sigaction(), change them to use the cobpostsighandler routine. This is so that your handler and any default run-time system handler, additional COBOL functionality and user posted signal handlers can all co-exist without one overriding the other, causing unexpected results.
The cobpostsighandler routine interface is very similar to the signal() interface. The two parameters you pass to signal() are also passed to the cobpostsighandler routine, plus a priority.
The differences between signal() and the cobpostsighandler routine are:
The return value from cobpostsighandler is either a pointer or NULL. You use this pointer to remove your handler later using cobremovesighandler. If the return value is NULL, the handler was not posted for the signal.
You do not need to repost a handler that you posted using the cobpostsighandler routine; it stays posted. If you want your handler to be executed only once, remove it using the cobremovesighandler routine.
If you are using third party software that posts a signal handler using an operating system signal call, such as signal() or sigaction(), unexpected results may occur. For example, if the third party software posts its handler before COBOL has been invoked, then when COBOL is invoked the third party's handler might be overridden by a run-time system/COBOL handler. If the the third party subsequently raises a signal, then a 115 error may occur.
To overcome this, you can use the run-time tunable signal_regime. This tunable prevents handlers from being posted for the specified signal if a signal handler is posted before the first COBOL invocation. For more information on this tunable see the chapter Run-Time Configuration, in the Object COBOL User Guide.
If handlers are prevented from being posted for a signal, due to this tunable, the cobpostsighandler routine returns NULL. Hence, the default run-time system handlers and any additional COBOL functionality achieved using the signal is not available. It also means that you should check the value returned from any the cobpostsighandler routine calls for NULL.
Use of the signal_regime tunable is recommended only for use with third party software. You should always use the cobpostsighandler routine in your own code.
On some platforms, the operating system function sigaction() is available. It is more robust than signal() when signals are being received in rapid succession or when a machine is heavily loaded. The cobpostsighandler routine uses sigaction() by default.
You can force the cobpostsighandler routine to use signal() instead of sigaction() by using the signal_interface tunable. For more information on this tunable see the chapter Run-Time Configuration in the Object COBOL User Guide.
Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names
used herein are protected by international law.
The COBOL Interfacing Environment | Installf Facility |