PreviousThe COBOL Interfacing Environment Installf FacilityNext

Chapter 10: Interfacing and Mixed-language Programming

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.

10.1 Cancelling Non-COBOL Programs

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.

10.2 Interfacing to Assembler Subprograms

We recommend that you write your assembler subprograms to comply with the standard COBOL calling convention.

10.2.1 Assembler Subprograms on DOS

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.

10.2.2 Assembler Subprograms on Windows and OS/2 (16-bit)

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.

10.2.3 Assembler Subprograms on Windows NT and OS/2 (32-bit)

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
        ...
        program code
        ...
        mov         esi,[param1]    ; access parameter 1
        ...
        mov         esi,[param2]    ; access parameter 2 
        ...
        mov         eax,{return-code}  ; set up 
                                       ; return code
        ...

        pop         edi
        pop         esi         ; restored esi,edi
        pop         ebp         ; restored ebp
        ret

EXAMPLE endp

        CODE32      ends
        end

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

10.2.4 Invoking Assembler Subprograms from COBOL

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.

10.2.5 Animating Programs That Call Assembler Subprograms

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.

10.2.6 Memory Model Considerations

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.

10.2.7 Machine State At Transfer of Control

The following sections describe the state of the registers when an assembler program is called from a COBOL program.

10.2.7.1 Registers Used on the 16-bit COBOL System

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.

10.2.7.2 Registers Used on the 32-bit COBOL System for OS/2

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:

10.2.7.3 Registers Used on the 32-bit COBOL System for Windows NT

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.

10.3 Interfacing with Windows and OS/2 API Routines

The following sections show you how your programs can interface with the Windows and OS/2 API routines.

10.3.1 Interfacing with Windows API Routines (16-bit)

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.

10.3.2 Interfacing with OS/2 API Routines (16-bit)

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.

10.3.3 Interfacing with Win32 API Routines

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.

10.3.4 Interfacing with API Routines (32-bit)

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.

10.4 Interfacing with OS/2 Optlink Routines

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.

10.5 Interfacing with C (32-bit)

Object COBOL provides a number of C functions to enable you to mix C and COBOL programs.

10.5.1 C Functions

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.


cobcall

Enables C programs to call COBOL programs. Parameters are passed BY REFERENCE.

Syntax:
long cobcall (name, argc, argv)
char *name;
int argc;
char **argv;
Comments:

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); 

cobcancel

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).

Syntax:
void cobcancel (name)
char *name; 

cobexit

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.

Syntax:
void cobexit (exitstatus) 
int exitstatus;
Comments:

You must use the cobexit functions to exit from non-COBOL modules rather than just using "exit".


cobfunc

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.

Syntax:
int cobfunc (name, argc, argv)
char *name;
int argc; 
char **argv;
Comments:

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.


10.5.1.1 cobgetfuncaddr

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.

10.5.1.1.1 Syntax:
cobgetfuncaddr(type, name)
int type
char *name
10.5.1.1.2 Parameters:
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.

cobtidy

Tidies up the global COBOL run environment.

Syntax:
void cobtidy( );
Comments:

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.


10.6 Interfacing with High-level Languages (16-bit)

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:

     call "C_fun1" using p1, p2, p3.

10.6.1 Microsoft C V6.0 and C/C++ V7.0

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.


10.6.1.1 Microsoft C V6 and C/C++ V7 Subprograms on DOS

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:

cobol-object The main COBOL program.
cobol/c-objects The remaining COBOL and C object modules that are required to be linked.
mfcvintf.obj One of the files mfc6intf.obj for C V6 or mfc7intf.obj for C/C++ V7. These .obj files, supplied with your COBOL system, set up the interface between COBOL and C.
cvdosif.obj and cvdoslb.obj Files c6dosif.obj and c6doslb.obj for C V6 or c7dosif.obj file and c7doslb.obj for C/C++ V7. These .obj files are supplied with your COBOL system to initialize the C run-time library. They are DOS specific.
cobol-library One of the COBOL run-time libraries, coblib.lib orlcobol.lib.
cobapi The COBOL run-time DOS operating system support library.
c-libraries The list of large model DOS C run-time libraries required by the C functions.

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.

10.6.1.2 Microsoft C V6 Subprograms on OS/2

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:

cobol-object The main COBOL program.
cobol/c-objects The remaining COBOL and C object modules that are required to be linked.
mfc6intf An .obj file supplied with your COBOL system which sets up the interface between COBOL and C.
c6os2if and c6os2lb .obj files supplied with your COBOL system which initialize the C run-time library. These modules are OS/2 specific.
cobol-library One of the COBOL run-time libraries, coblib.lib orlcobol.lib.
c-libraries The list of large model OS/2 C run-time libraries required by the C functions.
os2 The standard OS/2 API library, os2.lib. doscalls.lib can be used instead in most cases.

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
PROTMODE
DATA NONSHARED
EXPORTS cobol-object-name @1

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.

10.6.1.3 Invoking Microsoft C V6 and C/C++ V7 Subprograms from COBOL

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.

10.6.1.4 Invoking COBOL Subprograms from Microsoft C V6 and C/C++ V7 on DOS and from Microsoft C V6 on OS/2

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.

10.6.1.4.1 Dynamic Linking

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:

cobol-object The main COBOL program.
lcobol The COBOL run-time library lcobol.lib.
os2 The standard OS/2 API library, os2.lib.
def-file A .def file which defines the entry point as the first cobol-object name.
cobol-implib-lib A small library, created by the operating system utility IMPLIB from the .def file, which enables .dll files to be dynamically loaded.
c-object The C object module required to be linked.
c-libs The list of large model OS/2 C run-time libraries required by the C functions.

10.6.1.5 Invoking COBOL Subprograms from Microsoft C V6 on Windows

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.

10.6.1.6 Invoking COBOL Subprograms from Microsoft C/C++ V7 on Windows

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.

10.6.1.7 Animating Programs Which Call Microsoft C V6 and C/C++ V7 Subprograms

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.

10.6.1.8 Restrictions

The following restrictions apply when interfacing between C and COBOL programs:

10.6.2 Microsoft C V4 and V5

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;

10.6.3 Microsoft Visual C++ V1.0 on Windows

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.

10.6.4 Microsoft FORTRAN V5.0

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.


10.6.5 Microsoft FORTRAN V5.1

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).

10.6.6 Microsoft Pascal

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.


10.6.7 Lattice C V3.1 and V3.2

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

10.6.8 IBM C Set++

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 yourOS/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

10.6.9 IBM REXX/2

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;

10.7 Accessing Non-COBOL Data (OS/2)

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.

10.8 Mixed Language Support Functions

16-bit:
The mixed language support functions enable non-COBOL functinos to interface at a low-level with the 16-bit COBOL run-time system. The 16-bit COBOL system provides:

10.8.1 Mixed Language Support for Microsoft Windows V3.x

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.

10.8.1.1 Microsoft C V7 and COBOL

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;
}
10.8.1.1.1 Linking a Microsoft C V7 Program to COBOL

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.

10.8.1.1.2 Importing a COBOL .dll Into C

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.

10.8.1.1.3 Calling a COBOL .dll from C

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;
}

10.8.1.2 Borland C++ V3.1 and COBOL

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)

10.8.1.3 Microsoft Visual Basic V2 and V3

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.

10.8.1.4 Microsoft Visual C++ V1.0

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;

10.8.1.5 General Guidelines for Mixed Language Applications

The basic rules for interlanguage working with COBOL under Windows are as follows:

10.8.2 Mixed Language Support Library Routines on 16-Bit

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.


PC_STEP_SELECTOR

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.

Syntax:

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;
Parameters:
selector A pointer to a word
On Entry:
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.
On Exit:
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.

Comments:

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.


10.9 UNIX

This part of the chapter describes interfacing with the UNIX operating system and how to combine COBOL and C programs on UNIX.

10.9.1 Interfacing with the UNIX Operating System

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.

10.9.2 Interfacing with High-level Languages on UNIX

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.

10.9.3 UNIX-specific C Functions

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.


cobinit

Initializes the COBOL environment, before calling a COBOL program from a non-COBOL program.

Syntax:
cobinit( )
Comments:

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.


cobkeypad

Toggles the numeric keypad between local mode and transmit mode.

Syntax:
void cobkeypad(mode)
Parameters:
mode 1 for transmit mode
0 for local mode.
Comments:

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.


10.9.3.1 Sample Program

The sample program account.cbl is located in $COBDIR/demo. It demonstrates a C program calling a COBOL program. It shows:

10.9.4 Miscellaneous Functions

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.


cobsavenv and coblongjmp

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.

Comments:

The following restrictions apply when using these functions:


10.9.4.1 Example

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);

10.9.5 Screen Handling from C

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.


cobaddch

Displays the specified character on the screen at the virtual cursor's current position.

Syntax:
void cobaddch (ch)
cobchtype ch;
Parameters:
ch The required character. This can include attributes.

cobaddstr

Displays the specified string on the screen starting at the virtual cursor's current position.

Syntax:
int cobaddstr (s)
cobchtype *s;
Parameters:
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).

cobaddstrc

Displays the specified string on the screen starting at the virtual cursor's current position.

Syntax:
int cobaddstrc (c)
char *c;
Parameters:
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).

cobclear

Clears the screen and positions the cursor at line 0, column 0.

Syntax:
void cobclear ( )
Comments:

The Library routine CBL_CLEAR_SCREEN has the same effect and should be used in preference to cobclear.


cobcols

Returns the number of columns on the screen.

Syntax:
int cobcols ( )
Comments:

The Library routine CBL_GET_SCR_SIZE has the same effect and should be used in preference to cobcols.


cobgetch

Gets a character from the keyboard.

Syntax:
int cobgetch ( )
Comments:

The Library routine CBL_READ_KBD_CHAR has the same effect and should be used in preference to cobgetch.


coblines

Returns the number of lines on the screen.

Syntax:
int coblines ( )
Comments:

The Library routine CBL_GET_SCR_SIZE has the same effect and should be used in preference to coblines.


cobmove

Moves the virtual cursor to the specified line and column on the screen.

Syntax:
void cobmove (y, x) 
int y,x;
Parameters:
y The line number to move the virtual cursor to
x The column number to move the virtual cursor to
Comments:

The Library routine CBL_PUT_SCR_POS has the same effect and should be used in preference to cobmove.


cobprintf

Displays the specified formatted string on the screen at the virtual cursor's current position.

Syntax:
int cobprintf (fmt)
char *fmt;
Parameters:
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).
Comments:

This routine returns either the number of arguments output or -1 (for an error condition).


cobscroll

Scrolls the screen display, starting and finishing at the specified lines, up one line.

Syntax:
void cobscroll (top,bot)
int top,bot;
Parameters:

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

10.9.6 Environment Handling

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.


cobgetenv

Provides the same functionality as the C library call getenv().

Syntax:
char *cobgetenv(name) 
char *name;
Parameters:
name The string to search the environment for. This environment string is in the following format:
        NAME=VALUE

where NAME is the name specified in name. If NAME is not found, a NULL value is returned.


cobputenv

Allows you to dynamically change the environment at run time.

Syntax:
int cobputenv (string) 
char *string
Parameters:
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 in this format.

Comments:

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.


cobrescanenv

Causes the run-time system to rescan the environment for file-name mapping entries.

Syntax:
int cobrescanenv()
Comments:

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.


10.9.6.1 Example

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.

10.9.7 Signal Handling

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.


cobpostsighandler

Adds the specified handler to the list of handlers for the specified signal, at the specified priority.

Syntax:
void *cobpostsighandler (signal, priority, handler); 
int signal; 
int priority; 
int (*handler)(); 
Parameters:
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.
Comments:

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.


cobremovesighandler

Removes a posted handler from the list of handlers for the appropriate signal.

Syntax:
void cobremovesighandler (sighandler);
void *sighandler;
Parameters:
sighandler is the pointer returned when posting your signal handler using a previous cobpostsighandler call.
Comments:

There is no return value from this call.

32-bit:
This routine is available with 32-bit COBOL systems only.


10.9.7.1 Posting Signal Handlers

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.

Setting the Priority

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.

10.9.7.2 Writing Signal Handlers

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.


10.9.7.3 Example

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 */
}

10.9.7.4 Coping with More than One Handler for the Same Signal

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.

10.9.7.5 Converting Signal Handlers Written for the Signal Function

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:

10.9.7.6 Coping with Third Party Software that Uses Signals

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.

10.9.7.7 Comparing the Signal() and Sigaction() Functions

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 © 1998 Micro Focus Limited. All rights reserved.
This document and the proprietary marks and names used herein are protected by international law.
PreviousThe COBOL Interfacing Environment Installf FacilityNext