5.8 Transfer of Function Addresses

To be able to call the application functions the Dialog Manager has to know the addresses of the application functions. To get these addresses a structure named DM_FuncMap is defined. This structure cannot be used in COBOL because COBOL is not able to transfer addresses of functions to any other function. The transfer of the function addresses has to be written in C. On passing on the function addresses, two types of function have to be distinguished.

5.8.1 Functions without Records as Parameters

In this case, the transfer of the function address can follow the C source file that was generated by the program gencobfx: by calling the generated C functions from the COBOL main program.

Therefore the following steps are necessary:

  1. definition of the functions in the dialog script
  2. structuring the input file for generating the C-module
  3. generating the C module with gencobfx
  4. compiling the C module
  5. calling the generated C functions from the COBOL main program.

5.8.1.1 Structure of the Function Definition File

The function definition file that is necessary to link COBOL functions to the DM can be generated automatically. The input file structure is system-independent. However, the way the C source file is to be maintained depends on the system.

The file has to contain all COBOL functions that are to be called directly by the DM. The first column has to contain the function name in the dialog file, the second column can contain the function name in the COBOL program. The script takes the first name to generate the COBOL function name if the second column for a function is missing.

5.8.1.2 Generating the Function Definition File

5.8.1.2.1 Unix

On Unix, you can use a program named gencobfx to generate the function definition file. One of the arguments has to be a file that contains all names of your functions. This file can contain comments. The line which is to be a comment has to begin with *.

The syntax of the script is as follows:

gencobfx -mf|-mfvis [-o outfile] [-f func-entry] descriptionfile

-mf

By indicating this parameter a function file is generated which is suitable for the use with the Micro Focus COBOL compiler.

-mfvis

By indicating this parameter a function file is generated which is suitable for the use with the Micro Focus Visual COBOL compiler.

outfile

By indicating this parameter the function table can be stored in any file. Usually, the DM takes the name of the description file and replaces the characters after the point with "c".

func-entry

By indicating this parameter you can specify the function name that has to be called by your COBOL main program. This function links the functions to the DM by calling DM_BindCallBacks (see manual “C Interface - Functions”). DM usually takes the name BindFuncs.

descriptionfile

This file has to contain the names of all functions.

5.8.1.2.2 Microsoft Windows

On Microsoft Windows, you can use a program named gencobfx.exe to generate the function definition file. One of the arguments has to be a file that contains all names of your functions. This file can contain comments. The line which is to be a comment has to begin with "*".

The syntax of the script is as follows:

gencobfx.exe -mf|-mfvis [-o outfile] [-f func-entry] descriptionfile

-mf

By indicating this parameter a function file is generated which is suitable for the use with the Micro Focus COBOL compiler.

-mfvis

By indicating this parameter a function file is generated which is suitable for the use with the Micro Focus Visual COBOL compiler.

outfile

By indicating this parameter the function table can be stored in any file. Usually, the DM takes the name of the description file and replaces the characters after the point with c.

func-entry

By indicating this parameter you can specify the function name that has to be called by your COBOL main program. This function links the functions to the DM by calling DM_BindCallBacks (see manual “C Interface - Functions”). DM usually takes the name BindFuncs.

descriptionfile

This file has to contain the names of all functions.

5.8.1.3 Example

Function definition file

* Function definitions for tabdemo

TABLETEST

LOADTABLE

SAVETABLE

Generated C-file

#include "IDMuser.h"

 

extern DML_pascal DM_ENTRY tabletest();

extern DML_pascal DM_ENTRY loadtable();

extern DML_pascal DM_ENTRY savetable();

 

static struct {

    char *funcname;

    void (*address)();

} bindfuncs_FuncMap[] = {

    { "TABLETEST", (DM_EntryFunc) tabletest },

    { "LOADTABLE", (DM_EntryFunc) loadtable },

    { "SAVETABLE", (DM_EntryFunc) savetable },

};

 

struct CobolStatus {

    unsigned short errcode;

    unsigned short options;

};

 

void bindfuncs (cobstatus, dialogID)

struct CobolStatus *cobstatus;

DM_ID *dialogID;

{

    cobstatus->errcode = !DM_BindCallBacks

                        (bindfuncs_FuncMap,

                        sizeof(bindfuncs_FuncMap) /

                        sizeof(bindfuncs_FuncMap[0]),

                        *dialogID, cobstatus->options);

    cobstatus->options = 0;

}

5.8.1.4 BindThruLoader Functionality

If BindThruLoader is used then gencobfx is no longer needed and the call of BindFuncs can be omitted.

The functionality is enabled through:

Alternatively the following version may be used, which is more portable:

77  ACTION  PIC 9(4)  BINARY VALUE 0.

MOVE DMF-CobolBindForLoader TO ACTION.
CALL "DMcob_Control" USING DM-STDARGS DIALOG-ID ACTION.

Although calling DMcob_Control is possible for all COBOL variants, there will still be some bindings where the dynamic connection does not work.

Note

If an application object is used in the dialog, then the functionality must be enabled at the application object and not at the dialog:

77  APPL-ID  PIC 9(9)  BINARY VALUE 0.

CALL "DMcob_PathToID" USING DM-STDARGS APPL-ID NULL-OBJECT "Appl@".

This APPL-ID has to be specified instead of the DIALOG-ID (see above).

Availability

DMF-CobolBindForLoader is available since IDM version A.06.01.d

5.8.2 Functions with Records as Parameters

In this case, the transfer of the function addresses follows automatically by calling the initialization function in the record module.

To do so, the following steps are necessary:

  1. definition of the records in the dialog script
  2. definition of the functions in the dialog script
  3. generating the C-module by the simulator with the option +writetrampolin
  4. compiling the C-module
  5. calling the generated C-functions from the COBOL main program
  6. linking of the program

5.8.2.1 Generating the Trampoline Module

To supply functions for dialogs with records by an application, the C-modules generated by the DM have to be translated and linked. The generation is necessary for every module which exists in the dialog and which contains definitions for functions. These modules are generated by calling the simulation with the option +writetrampolin:

idm +writetrampolin <outfile> <dialogfile>

The indicated dialog script may be a module.

This statement generates the necessary modules out of a dialog script for calling the functions. According to the kind of functions which use such records, the respective header files (C and/or COBOL) are generated.

When implementing these functions, the generated header file has to be included in the respective module with the following statement:

COPY

If such functions and records are used in an application, these records have to be initialized by calling the function

cobRecInit<ModuleName>

The initialization should usually be carried out before the function call BindFuncs!

If such structures are used in DM applications, i.e. if the distributed DM is used, the application for which the files are to be generated has to be indicated in addition.

The name of the initialization function is set up by the application name. Thus,

cobRecInit<ApplicationName>

has to be called.

idm  +writetrampolin <contfile> +application <ApplicationName> <dialogscript>

To generate a copy file that also contains National Character (Micro Focus Visual COBOL only), this has to be specified with the option -mfviscob-u .

5.8.2.2 Compiling the C Module

When compiling the generated C module, a flag has to be set according to the used COBOL.

COBOL Compiler

Flag for C Compiler

Micro Focus COBOL

-DUFCOB

Micro Focus Visual COBOL

-DMFVISCOB

On the PC platforms Microsoft Windows the switch -DUFCOB_LINK has to be set additionally when using the Micro Focus COBOL compiler.

5.8.2.3 Example

Dialog File

dialog RecTest

{

  .reffont MyFont;

}

 

function cobol void WriteAddr(record Address input);

function cobol void ReadAddr(record Address output, integer Pos input output);

 

font MyFont "fixed";

 

record Address

{

  string[25] Name       shadows W1.Lname.E.content;

  string[15] FirstName  shadows W1.Lfirstname.E.content;

  string[25] City       shadows W1.Lcity.E.content;

  string[30] Street     shadows W1.Lstreet.E.content;

}

Generated COBOL Copy File

    01 RecAddress.

        02 Name pic X(25).

        02 FirstName pic X(15).

        02 City pic X(25).

        02 Street pic X(30).

Generated C Program

#include <IDMuser.h>

#include <IDMcobol.h>

#if !defined(offsetof)

#    define offsetof(TYPE,FLD)    ((int) &(((TYPE *) 0)->FLD))

#endif

 

#ifdef VISCOB

#    ifdef DOS

#        define WriteAddr WRITEADDR

#        define ReadAddr READADDR

#    else

#    define WriteAddr writeaddr

#        define ReadAddr readaddr

#    endif

#endif

 

#ifdef UFCOB

#    ifdef UFCOB_LINK

#        define WriteAddr WRITEADDR

#        define ReadAddr READADDR

#    else

#        define WriteAddr "WRITEADDR"

#        define ReadAddr "READADDR"

#    endif

#endif

 

#ifdef XLCOB

#        define WriteAddr writeaddr

#        define ReadAddr readaddr

#endif

 

typedef struct

{

    char        Name[25];

    char        FirstName[15];

    char        City[25];

    char        Street[30];

} RecCobAddress;

 

static DM_RecordInfo RecCobInfoAddress[5] =

{

 {".Name", DT_string, offsetof(RecCobAddress,Name), 25, 0 },

 {".FirstName",DT_string,offsetof(RecCobAddress,FirstName),
                                         15, 0 },

 {".City", DT_string, offsetof(RecCobAddress,City), 25, 0 },

 {".Street", DT_string, offsetof(RecCobAddress,Street), 30, 0 },

};

 

DeclCobol(WriteAddr)

 

static void DML_c DM_ENTRY RecFuncWriteAddr __1(

(DM_ID, arg0))

{

    RecCobAddress record0;

 

DM_GetRecord(arg0,&record0,RecCobInfoAddress,

    sizeof(RecCobInfoAddress)/sizeof(DM_RecordInfo),

    DMF_Cobol);

 

CallCobol1(;,WriteAddr,&record0);

}

 

DeclCobol(ReadAddr)

 

static void DML_c DM_ENTRY RecFuncReadAddr __2(

(DM_ID, arg0),

(long*, Pos))

{

    RecCobAddress record0;

 

    CallCobol2(;,ReadAddr,&record0, Pos);

 

DM_SetRecord(arg0,&record0,RecCobInfoAddress,

    sizeof(RecCobInfoAddress)/sizeof(DM_RecordInfo),

    DMF_Cobol);

}

 

#define RecMapCount (sizeof(RecMap) / sizeof(RecMap[0]))

 

static DM_FuncMap RecMap[] = {

    { "WriteAddr", (DM_EntryFunc) RecFuncWriteAddr },

    { "ReadAddr", (DM_EntryFunc) RecFuncReadAddr },

};

 

boolean RecInitRecTest __1((DM_ID, dialog))

{

    return DM_BindCallBacks(RecMap, RecMapCount, dialog,

          DMF_Silent);

}

 

void cobrecinitrectest __2((short *, dialog), (boolean *,

          result))

{

    *result = RecInitRecTest((DM_ID) *dialog);

}

5.8.3 Dynamic Binding of Record Functions

Availability

Since IDM version A.06.01.d

Dynamic binding refers to a binding type for application functions that does not require explicitly setting the function pointer of the application functions by means of the functions DM_BindFunctions or DM_BindCallBacks. This includes, for example, connecting functions from dynamic libraries (transport "dynlib") or calling COBOL functions by their names through the “BindThruLoader Functionality”. However, since application functions with record parameters require an additional stub function for marshalling the record structure, no structure has been transferred so far when these record functions were called.

As of IDM version A.06.01.d, the structure of the record parameters for dynamically bound record functions is transferred without a stub function. Such record functions can be used without generating a C or COBOL code. It is however useful to generate the function prototypes as well as the structure definition via +writeheader <basefilename>.

Example

dialog D
record RecAdr {
  string[80] Name := "";
  string[120] Street := "";
  string[40] City := "";
  integer ZIP := 0;
}

application Appl {
  .transport "dynlib";
  .exec "libadr.so";
  .active true;
  function boolean Search(string Pattern, record RecAdr output);
}

application ApplCobol {
  .local true;
  .active true;
  function cobol boolean New(record RecAdr) alias "NEWADR";
}

on dialog start {
  if not Appl.active orelse not ApplCobol.active then
    print "Application(s) not properly connected!";
  elseif not Search("Joe", RecAdr) then
    print "Joe not found, adding him";
    RecAdr.Name := "Joe";
    RecAdr.Street := "765 East Walnut Lane";
    RecAdr.City := "Oak Park";
    RecAdr.ZIP := 48237;
    New(RecAdr);
  else
    print "Joe found, lives in: "+RecAdr.City;
  endif
  exit(();
}

The prototypes can now simply be generated with +writeheader instead of +writeproto, +writefuncmap and +/-writetrampolin:

pidm adr.dlg +application Appl +writeheader adr       // generates adr.h
pidm adr.dlg +application ApplCobol +writeheader adr  // generates adr.cpy

The actual implementation in C and COBOL can now find the function prototypes or record definitions for RecRecAdr in adr.h (C header file) and adr.cpy (COBOL copy file).

To generate a copy file that also contains National Character (Micro Focus Visual COBOL only), this has to be specified with the option -mfviscob-u .