5.8 Übergabe der Funktionsadressen

Damit der Dialog Manager die Funktionen in der Anwendung aufrufen kann, benötigt er die Adressen dieser Funktionen. Um diese Adressen an den Dialog Manager zu übergeben, ist die Struktur DM_FuncMap definiert. Diese Struktur kann aber in COBOL nicht verwendet werden, da COBOL nicht in der Lage ist, die Adressen von Funktionen an andere Funktionen zu übergeben. Aus diesem Grund muss die Übergabe der Funktionsadressen in C geschrieben werden. Bei dieser Übergabe der Funktionsadressen müssen zwei Arten von Funktionen unterschieden werden.

5.8.1 Funktionen ohne Records als Parameter

In diesem Fall kann die Übergabe der Funktionsadresse durch das C-Source File, das von dem Programm gencobfx generiert wurde, erfolgen. Die Übergabe der Funktionsadresse erfolgt dann durch den Aufruf der generierten C-Funktionen von COBOL-Hauptprogrammen aus.

Dazu sind folgende Schritte notwendig:

  1. Definition der Funktionen im Dialogskript
  2. Aufbau der Eingabedatei zum Generieren des C-Moduls
  3. Generieren des C-Moduls durch gencobfx
  4. Übersetzen des C-Moduls
  5. Aufruf der generierten C-Funktion vom COBOL-Hauptprogramm aus.

5.8.1.1 Aufbau der Funktionsdefinitionsdatei

Die Funktionsdefinitionsdatei, die notwendig ist, um COBOL-Funktionen an den DM zu binden, kann automatisch erzeugt werden. Die Struktur der Eingabedatei ist systemunabhängig; die Art, die C-Source-Datei zu erhalten, ist systemabhängig.

Die Datei muss alle COBOL-Funktionen enthalten, die direkt vom DM aufgerufen werden sollen. Die erste Spalte muss den Namen der Funktion in der Dialogdatei enthalten, die zweite Spalte kann den Namen der Funktion im COBOL-Programm enthalten. Wenn die zweite Spalte für eine Funktion fehlt, nimmt das Skript den ersten Namen, um den Namen der COBOL-Funktion zu erzeugen.

5.8.1.2 Erzeugen der Funktionsdefinitionsdatei

5.8.1.2.1 Unix

Auf Unix können Sie ein Programm namens gencobfx verwenden, um die Funktionsdefinitionsdatei zu erzeugen. Eines der Argumente muss eine Datei sein, die alle Namen der Funktionen enthält. Diese Datei kann Kommentare enthalten; die Zeile, die ein Kommentar sein soll, muss mit einem * beginnen.

Die Syntax des Skripts sieht aus wie folgt:

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

-mf

Durch Angabe dieses Parameters wird eine Funktionsdatei erzeugt, die für den Einsatz zusammen mit dem Micro Focus COBOL-Compiler geeignet ist.

-mfvis

Durch Angabe dieses Parameters wird eine Funktionsdatei erzeugt, die für den Einsatz mit Micro Focus Visual COBOL geeignet ist.

outfile

Durch Angabe dieses Parameters kann die Funktionstabelle in jeglicher Datei gespeichert werden. Normalerweise übernimmt der DM den Namen der Beschreibungsdatei und ersetzt die Zeichen nach dem Punkt mit c.

func-entry

Durch Angabe dieses Parameters können Sie den Namen der Funktion spezifizieren, die von Ihrem COBOL-Hauptprogramm aufgerufen werden muss. Diese Funktion bindet durch Aufrufen von DM_BindCallBacks die Funktionen an den DM. Normalerweise nimmt der DM den Namen BindFuncs.

descriptionfile

Diese Datei muss die Namen aller Funktionen enthalten.

5.8.1.2.2 Microsoft Windows

Auf Microsoft Windows können Sie ein Programm namens gencobfx.exe verwenden, um die Funktionsdefinitionsdatei zu erzeugen. Eines der Argumente muss eine Datei sein, die alle Namen Ihrer Funktionen enthält. Diese Datei kann Kommentare enthalten. Die Zeile, die ein Kommentar sein soll, muss mit einem "*" beginnen.

Die Syntax des Skripts sieht aus wie folgt:

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

-mf

Durch Angabe dieses Parameters wird eine Funktionsdatei erzeugt, die für den Einsatz zusammen mit dem Micro Focus COBOL-Compiler geeignet ist.

-mfvis

Durch Angabe dieses Parameters wird eine Funktionsdatei erzeugt, die für den Einsatz mit Micro Focus Visual COBOL geeignet ist.

outfile

Durch Angabe dieses Parameters kann die Funktionstabelle in jeglicher Datei gespeichert werden. Normalerweise übernimmt der DM den Namen der Beschreibungsdatei und ersetzt die Zeichen nach dem Punkt mit c.

func-entry

Durch die Angabe dieses Parameters können Sie den Namen der Funktion spezifizieren, die von Ihrem COBOL-Hauptprogramm aufgerufen werden muss. Diese Funktion bindet durch Aufrufen von DM_BindCallBacks die Funktionen an den DM. Normalerweise nimmt der DM den Namen BindFuncs.

descriptionfile

Diese Datei muss die Namen aller Funktionen enthalten.

5.8.1.3 Beispiel

* Function definitions for tabdemo
TABLETEST
LOADTABLE
SAVETABLE

Generierte C-Datei

#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-Funktionalität

Wenn BindThruLoader benutzt wird, dann wird gencobfx nicht mehr benötigt und der Aufruf von BindFuncs kann entfallen.

Eingeschaltet wird die Funktionalität mit:

Alternativ kann auch folgende Version verwendet werden, die portabler ist:

77  ACTION  PIC 9(4)  BINARY VALUE 0.

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

Auch wenn der Aufruf von DMcob_Control für alle COBOL-Varianten möglich ist, wird es Anbindungen geben, bei denen die dynamische Bindung dennoch nicht funktioniert.

Hinweis

Wenn im Dialog ein Application-Objekt verwendet wird, dann muss die Funktionalität am Application-Objekt und nicht am Dialog eingeschaltet werden:

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

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

Diese APPL-ID muss an Stelle der DIALOG-ID (siehe oben) angegeben werden.

Verfügbarkeit

DMF-CobolBindForLoader ist ab IDM-Version A.06.01.d verfügbar

5.8.2 Funktionen mit Records als Parametern

In diesem Fall erfolgt die Übergabe der Funktionsadressen automatisch durch den Aufruf der Initialisierungsfunktion in dem Recordmodul.

Dazu sind folgende Schritte notwendig:

  1. Definition der Records im Dialogskript
  2. Definition der Funktionen im Dialogskript
  3. Generieren des C-Moduls durch den Simulator mit der Option +writetrampolin
  4. Übersetzen des C-Moduls
  5. Aufruf der generierten C-Funktion vom COBOL-Hauptprogramm aus.
  6. Linken des Programms

5.8.2.1 Generierung des Trampolin-Moduls

Um Funktionen für Dialoge mit Records mit einer Applikation versehen zu können, müssen vom Dialog Manager generierte C-Module übersetzt und dazu gebunden werden. Diese Generierung ist für jedes im Dialog vorhandene Modul notwendig, das Definitionen für Funktionen beinhaltet. Die Generierung dieser Module erfolgt durch Aufruf der Simulation mit der Option +writetrampolin:

idm +writetrampolin <outfile> <dialogskript>

Dabei kann das angegebene Dialogskript ein Modul sein.

Dieses Statement generiert aus einem Dialogskript die notwendigen Module zum Aufruf von Funktionen. Je nach Art der Funktionen, die solche Records verwenden, werden die entsprechenden Header-Dateien (C und/oder COBOL) erzeugt.

Bei der Implementierung dieser Funktionen muss in das entsprechende Modul die erzeugte Header-Datei eingebunden werden. Dies geschieht durch das Statement:

COPY

Wenn solche Funktionen und Records in einer Applikation verwendet werden, müssen diese Records durch den Aufruf der Funktion

cobRecMInit<Modulname>

initialisiert werden.

Die Initialisierung sollte üblicherweise vor dem Funktionsaufruf BindFuncs erfolgen!

Werden solche Strukturen in Dialog Manager-Applikationen verwendet, wird also der verteilte Dialog Manager eingesetzt, muss noch zusätzlich die Applikation angegeben werden, für die die Dateien generiert werden sollen.

Der Name der Initialisierungsfunktion wird dann aus dem Namen der Applikation gebildet.

Also muss

cobRecMInit<ApplicationName>

aufgerufen werden.

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

Soll eine Copy-Strecke generiert werden, die auch National Character beinhaltet (nur Micro Focus Visual COBOL), dann muss dies durch die Option -mfviscob-u angefordert werden.

5.8.2.2 Übersetzung des C-Moduls

Bei der Übersetzung der generierten C-Modul:Übersetzunge muss je nach eingesetztem COBOL ein Flag gesetzt und bei der Kompilierung des C-Moduls angegeben werden.

COBOL Compiler

Flag für C Compiler

Micro Focus COBOL

-DUFCOB

Micro Focus Visual COBOL

-DMFVISCOB

Auf den PC-Plattformen unter Microsoft Windows muss bei Verwendung des Micro Focus COBOL-Compilers zusätzlich der Schalter -DUFCOB_LINK gesetzt sein.

5.8.2.3 Beispiel

Dialogdatei

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

Generierte COBOL Copy-Datei

01 RecAddress.
    02 Name pic X(25).
    02 FirstName pic X(15).
    02 City pic X(25).
    02 Street pic X(30).

Generiertes C-Programm

#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

typedef struct {
    char        Name[25];
    char        FirstName[15];
    char        City[25];
    char        Street[30];
} RecCobAddres;

static DM_RecordInfo RecCobInfoAddres[5] =
{
    {".Name",DT_string, offsetof(RecCobAddres,Name),25,0},
    {".FirstName",DT_string,offsetof(RecCobAddres,FirstName),15,0},
    {".City",DT_string,offsetof(RecCobAddres,City),25,0},
    {".Street",DT_string,offsetof(RecCobAddres,Street),30,0},
};

DeclCobol(WriteAddr)

static void DML_c DM_ENTRY RecFuncWriteAddr __1(
(DM_ID, arg0))
{
    RecCobAddress record0;
 
    DM_GetRecord(arg0,&record0,RecCobInfoAddres,
        sizeof(RecCobInfoAddres)/sizeof(DM_RecordInfo),
        DMF_Cobol);

    CallCobol1(;,WriteAddr,&record0);
}

DeclCobol(ReadAddr)
 
static void DML_c DM_ENTRY RecFuncReadAddr __2(
(DM_ID, arg0),
(DM_Integer*, Pos))
{
    RecCobAddress record0;
 
    CallCobol2(;,ReadAddr,&record0, Pos);
    DM_SetRecord(arg0,&record0,RecCobInfoAddres,
        sizeof(RecCobInfoAddres)/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 RecInitMRecTest __1((DM_ID, dialog))
{
    return DM_BindFunctions(RecMap, RecMapCount, dialog, 0, DMF_Silent);
}
void cobrecminitrectest __2((DM_ID*,  dialog), (boolean *, result))
{
    *result = RecInitMRecTest((DM_ID) *dialog);
}

5.8.3 Dynamische Anbindung von Record-Funktionen

Verfügbarkeit

Ab IDM-Version A.06.01.d

Mit dynamischer Anbindung ist die Bindungsart von Anwendungsfunktionen gemeint, welche kein explizites Setzen des Funktionspointers der Anwendungsfunktionen über die Funktionen DM_BindFunctions oder DM_BindCallBacks benötigt. Dazu gehören z.B. die Anbindung von Funktionen aus dynamischen Bibliotheken (Transport "dynlib") oder der Aufruf von COBOL-Funktionen über ihren Namen durch die „BindThruLoader-Funktionalität“. Da allerdings Anwendungsfunktionen mit Record-Parametern eine zusätzliche Stub-Funktion für das Umwandeln (Marshalling) der Record-Struktur benötigen, wurde bisher beim Aufruf dieser Record-Funktionen keine Struktur übertragen.

Ab IDM-Version A.06.01.d wird für dynamisch angebundene Record-Funktionen die Struktur der Record-Parameter ohne Stub-Funktion übertragen. Eine Nutzung solcher Record-Funktionen ist möglich, ohne C- oder COBOL-Code zu generieren. Es ist aber sinnvoll sich die Funktionsprototypen wie auch die Strukturdefinition über +writeheader <basefilename> generieren zu lassen.

Beispiel

dialog D
record RecAdr {
  string[80] Name := "";
  string[120] Strasse := "";
  string[40] Ort := "";
  integer PLZ := 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 "Applikation(en) nicht korrekt angebunden!";
  elseif not Search("Udo", RecAdr) then
    print "Udo nicht gefunden, f\374ge ihn hinzu";
    RecAdr.Name := "Udo";
    RecAdr.Strasse := "Meisenweg 7";
    RecAdr.Ort := "Wolkenstein";
    RecAdr.PLZ := 71723;
    New(RecAdr);
  else
    print "Udo gefunden, wohnt in: "+RecAdr.Ort;
  endif
  exit(();
}

Die Generierung der Prototypen kann nun anstatt mit +writeproto, +writefuncmap und +/-writetrampolin einfach mit +writeheader erfolgen:

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

Die eigentliche Implementierung in C und COBOL kann nun die Funktionsprototypen bzw. Record-Definitionen für RecRecAdr in adr.h (C-Headerdatei) und adr.cpy (COBOL Copy-Strecke) finden.

Soll eine Copy-Strecke generiert werden, die auch National Character beinhaltet (nur Micro Focus Visual COBOL), dann muss dies durch die Option -mfviscob-u angefordert werden.