C# .NET Interface

This chapter describes an example program that uses functions used by a C# .NET interface.

A C# .NET interface that spports Unicode is similar to a Visual Basic .NET interface. For information about functions used by a C# .NET interface, refer to Visual Basic .net Interface (Unicode).

1. Overview

A C# .NET interface has interface modules that define functions' prototypes to call a client library.

If the following interface modules are installed, functions provided by a Tmax client library can be called and used. For information about the functions, refer to an example program for managing employees in Client Program.

Module Description

Atmi.cs

Module that defines ATMI functions' prototypes.

Fdl.cs

Module that defines field key functions' prototypes.

Tx.cs

Module that defines transaction-related functions' prototypes.

WinApi.cs

Module that defines prototypes of functions provided by Windows.

TmaxApi.cs

Module that defines prototypes of functions for RQ, unrequested messages, etc.

For information about prototypes and descriptions of ATMI and field key functions, refer to Tmax Reference Guide and Tmax Application Development Guide. For information about how to use a C# interface, refer to an example program in the next section.

2. Example Program

The following describes an example program that queries, modifies, deletes, and adds names, positions, managers in charge, joining dates, salaries, contracted periods, and departments with a key of an employee number. Filed key buffers are used in the program.

2.1. Program Organization

Each program consists of the following files.

  • Common program

    File Description

    demo.f

    Defines field key buffers.

    tmconfig.m

    Tmax configuration file.

  • Client program

    File Description

    4GL_Sample.sln

    Client program that consists of Form1.cs and a Tmax library.

  • Server program

    File Description

    emp_c.pc

    Server program that provides services (Oracle source).

    emp_c.mk

    Makefile.

2.2. Program Description

The following describes each program.

  • Client program

    Item Description

    Tmax library connection

    Atmi.cs, Fdl.cs, Tx.cs, WinApi.cs, and TmaxApi.cs are added.

    Tmax connection

    A connection is established whenever a service operates and ended after the service completes.

    Buffer

    'fdl' files need to be created by compiling FIELD KEY buffers and field key files with the fdlc utility.

    Communication

    Synchronous communication is made by using pb_tpcall().

    Transaction

    Transactions for queries, modifications, deletions, and additions are handled.

  • Server program

    Item Description

    Service

    FDLSELECT, FDLUPDATE, FDLDELETE, and FDLINSERT are written.

    Database

    Oracle database is used. Database information (XA method) is specified in SVRGROUP of a system configuration file.

2.3. Common Program

DataBase EMP Table

The following is an example EMP table created in a database.

EMPNO              NUMBER                NOT NULL          P1
ENAME              VARCHAR(16)
JOB                VARCHAR(16)
MGR                NUMBER
HIREDATE           DATE
SAL                NUMBER(7,2)
COMM               NUMBER(7,2)
DEPTNO             NUMBER
Field Key Buffer Definition

The following is an example file that defines a field key buffer.

<demo.f>

#For tmax demo employee program
EMPNO               7500                long                -                -
ENAME               7501                string              -                -
JOB                 7502                string              -                -
MGR                 7503                long                -                -
DATE                7504                string              -                -
SAL                 7505                float               -                -
COMM                7506                float               -                -
DEPTNO              7507                long                -                -
E_TYPE              9009                long                -                -
E_CODE              9010                long                -                -
E_MSG               9011                string              -                -
E_TMP               9012                long                -                -
Tmax Configuration

The following is an example Tmax configuration file.

<tmconfig.m>

*DOMAIN
dom1                SHMKEY = 70000, MAXUSER = 200, MINCLH = 1, MAXCLH = 5,
                    TPORTNO = 8888, BLOCKTIME = 200, TXTIME = 200
*NODE
tmax1               TMAXDIR = "/home/tmax",
                    APPDIR = "/home/tmax/appbin",
                    PATHDIR = "/home/tmax/path",
                    TLOGDIR =  "/home/tmax/log/tlog",
                    SLOGDIR = "/home/tmax/log/slog"
                    ULOGDIR = "/home/tmax/log/ulog"
*SVRGROUP
svg1                NODENAME = tmax1, DBNAME = ORACLE,
                    OPENINFO = "ORACLE_XA+Acc=P/scott/tiger+SesTm=60",
                    TMSNAME = svg1_tms
*SERVER
emp_c               SVGNAME = svg1, MIN = 1

*SERVICE
FDLSELECT           SVRNAME = emp_c
FDLUPDATE           SVRNAME = emp_c
FDLDELETE           SVRNAME = emp_c
FDLINSERT           SVRNAME = emp_c

2.4. Client Program

Employee Management Program

The following is an initial screen that consists of 1 data window, 8 singleline editor, and 5 buttons.

image

The following describes each button.

  • Search

    Click the [Search] button after entering 'Employee Number' to display data with the entered employee number ±50 in the data window.

    The following shows an example result.

    image

  • Modification

    Click the [Modify] button after entering 'Employee Number' and new data to replace existing data with the new data.

  • Deletion

    Click the [Delete] button after entering 'Employee Number' to delete the corresponding data.

  • Addition

    Click the [Add] button after entering all data for an employee to add the employee.

  • Exit

    Click the [Exit] button to exit the program.

This section describes 2 example program design sources: Unicode programming and general programming.

The following is an example of general programming source for managing employees.

<Form1.cs>

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

using AtmiNS;
using WinApiNS;
using FdlNS;
using TxNS;
using TmaxApiNS;

namespace _4GL_Sample
{
public class EmployeeMgr : System.Windows.Forms.Form
{
        private Atmi atmi = new Atmi();
        private WinApi winApi = new WinApi();
        private Fdl fdl = new Fdl();
        private Tx tx = new Tx();
        private TmaxApi tmaxApi = new TmaxApi();

        bool bTxRun, bConnect;
        int nSndBuf, nRcvBuf;
        public string[] EmpFKey =
        {"EMPNO","ENAME","JOB","MGR","DATE","SAL","COMM","DEPTNO"};
        public string[] ErrFKey = {"E_TYPE","E_CODE","E_MSG","E_TMP"};
        public string[] ColumnName =
        {"EmpNo","Name","Position","Mgr","JoinDate","Salary","COMM","Dept"};

        public const int FIELD_NUM = 8;
        public const int ErrFLD_NUM = 4;
        public enum InputCheck {  Pri_Key, All };

        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.Label label3;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.Label label5;
        private System.Windows.Forms.Label label6;
        private System.Windows.Forms.Label label7;
        private System.Windows.Forms.Label label8;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.TextBox EditEmpNo;
        private System.Windows.Forms.TextBox EditName;
        private System.Windows.Forms.TextBox EditJob;
        private System.Windows.Forms.TextBox EditMgr;
        private System.Windows.Forms.TextBox EditDate;
        private System.Windows.Forms.TextBox EditSal;
        private System.Windows.Forms.TextBox EditComm;
        private System.Windows.Forms.TextBox EditDept;
        private System.Windows.Forms.Label LabelErr;
        private System.Windows.Forms.Button BtnSel;
        private System.Windows.Forms.Button BtnUpt;
        private System.Windows.Forms.Button BtnDel;
        private System.Windows.Forms.Button BtnIns;
        private System.Windows.Forms.Button BtnExit;
        private System.Windows.Forms.Button BtnBack;
        private System.Windows.Forms.DataGrid dataGrid;

        private DataSet ResultData;
        private DataTable tEmp;
        private DataColumn cEmpNo;
        private DataColumn cEName;
        private DataColumn cJob;
        private DataColumn cMgr;
        private DataColumn cDate;
        private DataColumn cSal;
        private DataColumn cComm;
        private DataColumn cDept;
        private System.ComponentModel.Container components = null;

        public EmployeeMgr()
        {
            bTxRun = false;
            bConnect =  false;
            nSndBuf = 0;
            nRcvBuf = 0;
            InitializeComponent();
            MakeDataSet();
        }

        private void ErrorProcess(string ErrMsg)
        {
            LabelErr.Text = ErrMsg;
            if( bTxRun == true )
            {
                 tx.TX_ROLLBACK();
                 bTxRun = false;
            }
            if( nRcvBuf != 0 )
                atmi.TPFREE(ref nRcvBuf);
            if( nSndBuf != 0 )
                atmi.TPFREE(ref nSndBuf);

                    if( bConnect == true )
                    {
                        atmi.TPEND();
                        bConnect = false;
                    }
        }

        private void SuccessProcess(string SucMsg)
        {
             LabelErr.Text = SucMsg;
                    if( bTxRun == true ) {
                        tx.TX_COMMIT();
                        bTxRun = false;
                     }
                     if( nRcvBuf != 0 )
                         atmi.TPFREE(ref nRcvBuf);
                     if( nSndBuf != 0 )
                         atmi.TPFREE(ref nSndBuf);
                     if( bConnect == true ) {
                         atmi.TPEND();
                         bConnect = false;
                     }
        }

        private void ClearWindow() {
             EditEmpNo.Clear();
             EditName.Clear();
             EditJob.Clear();
             EditMgr.Clear();
             EditDate.Clear();
             EditSal.Clear();
             EditComm.Clear();
             EditDept.Clear();
             tEmp.Clear();
        }

        private bool TmaxConnect(){
             tpstart_t  tpinfo = new tpstart_t();
             tpinfo.cltname = "star";
             tpinfo.usrname = "star";
             tpinfo.usrpwd  = "star";
             tpinfo.dompwd  = "star";
             tpinfo.flags   =  atmi.TPUNSOL_IGN;

             nRcvBuf = atmi.TPALLOC("TPSTART", null, 0);
             if( nRcvBuf == 0 )
                 return false;

             atmi.FilltpstartBuf(ref nRcvBuf, tpinfo);

             if( atmi.TPSTART(nRcvBuf) == -1 )
                 return false;

             return true;
       }
       private bool CheckInputData(InputCheck Level) {
             if(EditEmpNo.Text.Length == 0)
                return false;
             if(Level == InputCheck.Pri_Key )
                return true;
             else {
                if(EditName.Text.Length == 0)
                   return false;
                if(EditJob.Text.Length == 0)
                   return false;
                if(EditMgr.Text.Length == 0)
                   return false;
                if(EditDate.Text.Length != 8)
                   return false;
                if(EditSal.Text.Length == 0)
                   return false;
                if(EditComm.Text.Length == 0)
                   return false;
                if(EditDept.Text.Length == 0)
                   return false;
                return true;
              }
        }

        private bool PutMyData(InputCheck Level) {
             int nData;
             float fData;

             if(EditEmpNo.Text.Length != 0) {
                   nData = int.Parse(EditEmpNo.Text);
                   if( fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[0]),
                                   ref nData,0)< 0)
                        return false;
              }
             if(Level == InputCheck.Pri_Key )
                   return true;

             if(EditName.Text.Length != 0)
                   if(fdl.FBPUT(nSndBuf, fdl.FBGET_FLDKEY(EmpFKey[1]),
                                  EditName.Text, EditName.Text.Length) < 0)
                      return false;
             if(EditJob.Text.Length != 0)
                   if(fdl.FBPUT( nSndBuf, fdl.FBGET_FLDKEY(EmpFKey[2]),
                                      EditJob.Text, EditJob.Text.Length) < 0 )
                      return false;
             if(EditMgr.Text.Length != 0) {
                    nData = int.Parse(EditMgr.Text);
                    if(fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[3]),
                                 ref nData,0)< 0 )
                       return false;
             }
             if(EditDate.Text.Length == 8)
                    if(fdl.FBPUT( nSndBuf, fdl.FBGET_FLDKEY(EmpFKey[4]),
                       EditDate.Text, EditDate.Text.Length) < 0 )
                          return false;
             if(EditSal.Text.Length != 0){
                    fData = float.Parse(EditSal.Text);
                    if(fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[5]),
                                  ref fData,0)< 0 )
                       return false;
             }
             if(EditComm.Text.Length != 0) {
                    fData = float.Parse(EditComm.Text);
                    if(fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[6]),
                                 ref fData,0)< 0 )
                       return false;
             }
             if(EditDept.Text.Length != 0) {
                    nData = int.Parse(EditDept.Text);
                    if(fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[7]),
                                 ref nData,0)< 0)
                       return false;
             }
             return true;
        }

        private void MakeDataSet() {
             ResultData = new DataSet("dataGrid");

             tEmp = new DataTable("Employee");
             cEmpNo = new DataColumn(ColumnName[0],typeof(int));;
             cEName = new DataColumn(ColumnName[1],typeof(string));
             cJob = new DataColumn(ColumnName[2],typeof(string));
             cMgr = new DataColumn(ColumnName[3],typeof(int));
             cDate = new DataColumn(ColumnName[4],typeof(string));
             cSal = new DataColumn(ColumnName[5],typeof(float));
             cComm = new DataColumn(ColumnName[6],typeof(float));
             cDept = new DataColumn(ColumnName[7],typeof(int));

             tEmp.Columns.Add(cEmpNo);
             tEmp.Columns.Add(cEName);
             tEmp.Columns.Add(cJob);
             tEmp.Columns.Add(cMgr);
             tEmp.Columns.Add(cDate);
             tEmp.Columns.Add(cSal);
             tEmp.Columns.Add(cComm);
             tEmp.Columns.Add(cDept);

             ResultData.Tables.Add(tEmp);

             //DataRow newRow1 = tEmp.NewRow();
             dataGrid.SetDataBinding(ResultData, "Employee");
        }

        private void ReceiveError() {
             int nLeng = 0;
             object[] oEData = new object[ErrFLD_NUM];

             for(int i = 0; i < ErrFLD_NUM; i++) {
                 if(fdl.FBGET(nRcvBuf, fdl.FBGET_FLDKEY(ErrFKey[i]),
                              out oEData[i], ref nLeng) < 0 )
                     break;
             }
             ErrorProcess(oEData[2].ToString());
                 return;
        }
        protected override void Dispose( bool disposing ) {
             if(disposing) {
                if(components != null) {
                   components.Dispose();
                }
        }
        base.Dispose( disposing );
}

#region Windows Form Designer generated code
/*Design*/
        …
#endregion

static void Main() {
       Application.Run(new EmployeeMgr());
}

private void EmployeeMgr_Load(object sender, System.EventArgs e) {
        const string EnvFile = "D:\\tmax.env";

        if(atmi.TMAXREADENV(EnvFile,"TMAX") == -1 )
                ErrorProcess("Failed to read a configuration file. -"+ EnvFile);
}

private void BtnExit_Click(object sender, System.EventArgs e) {
         Dispose();
}

private void BtnIns_Click(object sender, System.EventArgs e) {
         int nLeng = 0;

         if(CheckInputData( InputCheck.All ) == false) {
                 ErrorProcess("There is a field with no data.\n
                               Enter 8 characters (YYYYMMDD) for a joining date.");
                 return;
          }

          bConnect = TmaxConnect();
          if(bConnect == false )
                  ErrorProcess("Could not connect to a server.");

          if(bTxRun == false) {
                  if(tx.TX_BEGIN() < 0) {
                         ErrorProcess( "TX_BEGIN Error");
                         return;
                   }
                   bTxRun = true;
          }

          if(nSndBuf != 0 )
                   atmi.TPFREE(ref nSndBuf);
          if((nSndBuf = fdl.FBALLOC( 5, 1000) ) == 0 )
                   ErrorProcess("FBALLOC - Memory allocation error");
          if(nRcvBuf != 0 )
                   atmi.TPFREE(ref nRcvBuf);
          if((nRcvBuf = fdl.FBALLOC( 5, 1000) ) == 0 )
                   ErrorProcess("FBALLOC - Memory allocation error");
          if(PutMyData( InputCheck.All ) == false) {
                   ErrorProcess("An error occurred during a field key insertion.");
                   return;
           }
           if(atmi.TPCALL( "FDLINSERT", nSndBuf, 0, ref nRcvBuf,
              ref nLeng, atmi.TPNOFLAGS) < 0 ) {
                   ReceiveError();
                   return;
           }
           SuccessProcess( EditEmpNo.Text +" is inserted.");
}

private void BtnSel_Click(object sender, System.EventArgs e) {
         int nLeng = 0;
         object[] oData = new object[FIELD_NUM];

         if(CheckInputData( InputCheck.Pri_Key ) == false ) {
                  ErrorProcess("Enter an employee number.");
                  return;
         }

         bConnect = TmaxConnect();
         if(bConnect == false )
                  ErrorProcess("Could not connect to a server.");

         if(bTxRun == false ) {
                  if(tx.TX_BEGIN() < 0 ) {
                        ErrorProcess( "TX_BEGIN Error");
                        return;
                  }
                  bTxRun = true;
         }

         if(nSndBuf != 0 )
                  atmi.TPFREE(ref nSndBuf);
         if((nSndBuf = fdl.FBALLOC( 5, 1000) ) == 0 )
                  ErrorProcess("FBALLOC - Memory allocation error");
         if(nRcvBuf != 0)
                  atmi.TPFREE(ref nRcvBuf);
         if((nRcvBuf = fdl.FBALLOC( 5, 1000)) == 0)
                  ErrorProcess("FBALLOC - Memory allocation error");
         if ( PutMyData( InputCheck.Pri_Key ) == false) {
                  ErrorProcess("An error occurred during a field key insertion.");
                  return;
         }

         if(atmi.TPCALL("FDLSELECT", nSndBuf, 0, ref nRcvBuf,
                         ref nLeng, atmi.TPNOFLAGS) < 0 ) {
                  ReceiveError();
                  return;
         }

         int OccrN =  fdl.FBKEYOCCUR(nRcvBuf,fdl.FBGET_FLDKEY(EmpFKey[0]));
         for(int j=0; j< OccrNum; j++) {
                  DataRow OutputRow = tEmp.NewRow();
                  for(int i=0; i< FIELD_NUM; i++) {
                            if(fdl.FBGET_TU( nRcvBuf, fdl.FBGET_FLDKEY(EmpFKey[i]),
                               j, out oData[i], ref nLeng) < 0 )
                                       break;
                  OutputRow[ColumnName[i]] = oData[i];
                  }
                  tEmp.Rows.Add(OutputRow);
         }

         SuccessProcess("Search Result");
         dataGrid.Visible = true;
         BtnBack.Visible = true;
         dataGrid.RowHeadersVisible = false;
}

private void BtnUpt_Click(object sender, System.EventArgs e) {
         int nLeng=0;
         if(CheckInputData( InputCheck.Pri_Key ) == false ) {
                   ErrorProcess("There is a field with no data.\n
                                 Enter 8 characters (YYYYMMDD) for a joining date.");
                   return;
         }

         bConnect = TmaxConnect();
         if(bConnect == false )
                   ErrorProcess("Could not connect to a server.");

         if( bTxRun == false ) {
                   if(tx.TX_BEGIN() < 0 ) {
                             ErrorProcess( "TX_BEGIN Error");
                             return;
                   }
                   bTxRun = true;
         }

         if(nSndBuf != 0 )
                   atmi.TPFREE(ref nSndBuf);
         if((nSndBuf = fdl.FBALLOC( 5, 1000) ) == 0 )
                   ErrorProcess("FBALLOC - Memory allocation error");
         if(nRcvBuf != 0 )
                   atmi.TPFREE(ref nRcvBuf);
         if((nRcvBuf = fdl.FBALLOC( 5, 1000) ) == 0 )
                   ErrorProcess("FBALLOC - Memory allocation error");

         if(PutMyData( InputCheck.All ) == false) {
                   ErrorProcess("An error occurred during a field key insertion.");
                   return;
         }

         if(atmi.TPCALL("FDLUPDATE", nSndBuf, 0, ref nRcvBuf,
                        ref nLeng, atmi.TPNOFLAGS) < 0 ) {
                   ReceiveError();
                   return;
         }

         SuccessProcess(EditEmpNo.Text + "is modified.");
                        ClearWindow();
}

private void BtnDel_Click(object sender, System.EventArgs e) {
         int nLeng = 0;

         if( CheckInputData( InputCheck.Pri_Key ) == false ) {
                    ErrorProcess("Enter an employee number.");
                    return;
         }

         bConnect = TmaxConnect();
         if( bConnect == false )
                    ErrorProcess("Could not connect to a server.");

         if( bTxRun == false ) {
                    if( tx.TX_BEGIN() < 0 ) {
                             ErrorProcess( "TX_BEGIN Error");
                             return;
                    }
                    bTxRun = true;
         }
         if( nSndBuf != 0 )
                    atmi.TPFREE(ref nSndBuf);
         if( ( nSndBuf = fdl.FBALLOC( 5, 1000) ) == 0 )
                    ErrorProcess("FBALLOC - Memory allocation error");
         if( nRcvBuf != 0 )
                    atmi.TPFREE(ref nRcvBuf);
         if( ( nRcvBuf = fdl.FBALLOC( 5, 1000) ) == 0 )
                    ErrorProcess("FBALLOC - Memory allocation error");

         if( PutMyData( InputCheck.Pri_Key ) == false ) {
                    ErrorProcess("An error occurred during a field Key insertion.");
                    return;
         }

         if(atmi.TPCALL("FDLDELETE", nSndBuf, 0, ref nRcvBuf,
            ref nLeng, atmi.TPNOFLAGS) < 0) {
                    ReceiveError();
                    return;
         }

         SuccessProcess( EditEmpNo.Text + "has been deleted.");
         ClearWindow();

}

private void BtnBack_Click(object sender, System.EventArgs e) {
         dataGrid.Visible = false;
         BtnBack.Visible = false;
         ClearWindow();
}
}

The following is an example of Unicode (UTF-8) programming source for managing employees.

In general, it does not have to set anything but Atmi.SetServerEncoding (Encoding.UTF8). However, if a client uses a separate encoding, set the encoding by using SetClientEncoding(). To support 64-bit encoding, nSndBuf and nRcvBuf are declared as IntPtr instead of int.

<Form1.cs>

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

using AtmiNS;
using WinApiNS;
using FdlNS;
using TxNS;
using TmaxApiNS;

namespace _4GL_Sample
{
public class EmployeeMgr : System.Windows.Forms.Form
{
        Atmi.SetServerEncoding(Encoding.UTF8);
        private Atmi atmi = new Atmi();
        private WinApi winApi = new WinApi();
        private Fdl fdl = new Fdl();
        private Tx tx = new Tx();
        private TmaxApi tmaxApi = new TmaxApi();

        bool bTxRun, bConnect;
        IntPtr nSndBuf, nRcvBuf;
        public string[] EmpFKey =
        {"EMPNO","ENAME","JOB","MGR","DATE","SAL","COMM","DEPTNO"};
        public string[] ErrFKey = {"E_TYPE","E_CODE","E_MSG","E_TMP"};
        public string[] ColumnName =
        {"EmpNo","Name","Position","Mgr","JoinDate","Salary","COMM","Dept"};

        public const int FIELD_NUM = 8;
        public const int ErrFLD_NUM = 4;
        public enum InputCheck {  Pri_Key, All };

        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.Label label3;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.Label label5;
        private System.Windows.Forms.Label label6;
        private System.Windows.Forms.Label label7;
        private System.Windows.Forms.Label label8;
        private System.Windows.Forms.GroupBox groupBox1;
        private System.Windows.Forms.TextBox EditEmpNo;
        private System.Windows.Forms.TextBox EditName;
        private System.Windows.Forms.TextBox EditJob;
        private System.Windows.Forms.TextBox EditMgr;
        private System.Windows.Forms.TextBox EditDate;
        private System.Windows.Forms.TextBox EditSal;
        private System.Windows.Forms.TextBox EditComm;
        private System.Windows.Forms.TextBox EditDept;
        private System.Windows.Forms.Label LabelErr;
        private System.Windows.Forms.Button BtnSel;
        private System.Windows.Forms.Button BtnUpt;
        private System.Windows.Forms.Button BtnDel;
        private System.Windows.Forms.Button BtnIns;
        private System.Windows.Forms.Button BtnExit;
        private System.Windows.Forms.Button BtnBack;
        private System.Windows.Forms.DataGrid dataGrid;

        private DataSet ResultData;
        private DataTable tEmp;
        private DataColumn cEmpNo;
        private DataColumn cEName;
        private DataColumn cJob;
        private DataColumn cMgr;
        private DataColumn cDate;
        private DataColumn cSal;
        private DataColumn cComm;
        private DataColumn cDept;
        private System.ComponentModel.Container components = null;

        public EmployeeMgr()
        {
            bTxRun = false;
            bConnect =  false;
            nSndBuf = IntPtr.Zero;
            nRcvBuf = IntPtr.Zero;
            InitializeComponent();
            MakeDataSet();
        }

        private void ErrorProcess(string ErrMsg)
        {
            LabelErr.Text = ErrMsg;
            if( bTxRun == true )
            {
                 tx.TX_ROLLBACK();
                 bTxRun = false;
            }
            if( nRcvBuf != IntPtr.Zero )
                atmi.TPFREE(ref nRcvBuf);
            if( nSndBuf != IntPtr.Zero )
                atmi.TPFREE(ref nSndBuf);

                    if( bConnect == true )
                    {
                        atmi.TPEND();
                        bConnect = false;
                    }
        }

        private void SuccessProcess(string SucMsg)
        {
             LabelErr.Text = SucMsg;
                    if( bTxRun == true ) {
                        tx.TX_COMMIT();
                        bTxRun = false;
                     }
                     if( nRcvBuf != IntPtr.Zero )
                         atmi.TPFREE(ref nRcvBuf);
                     if( nSndBuf != IntPtr.Zero )
                         atmi.TPFREE(ref nSndBuf);
                     if( bConnect == true ) {
                         atmi.TPEND();
                         bConnect = false;
                     }
        }

        private void ClearWindow() {
             EditEmpNo.Clear();
             EditName.Clear();
             EditJob.Clear();
             EditMgr.Clear();
             EditDate.Clear();
             EditSal.Clear();
             EditComm.Clear();
             EditDept.Clear();
             tEmp.Clear();
        }

        private bool TmaxConnect(){
             tpstart_t  tpinfo = new tpstart_t();
             tpinfo.cltname = "star";
             tpinfo.usrname = "star";
             tpinfo.usrpwd  = "star";
             tpinfo.dompwd  = "star";
             tpinfo.flags   =  atmi.TPUNSOL_IGN;

             nRcvBuf = atmi.TPALLOC("TPSTART", null, 0);
             if( nRcvBuf == IntPtr.Zero)
                 return false;

             atmi.FilltpstartBuf(ref nRcvBuf, tpinfo);

             if( atmi.TPSTART(nRcvBuf) == -1 )
                 return false;

             return true;
       }
       private bool CheckInputData(InputCheck Level) {
             if(EditEmpNo.Text.Length == 0)
                return false;
             if(Level == InputCheck.Pri_Key )
                return true;
             else {
                if(EditName.Text.Length == 0)
                   return false;
                if(EditJob.Text.Length == 0)
                   return false;
                if(EditMgr.Text.Length == 0)
                   return false;
                if(EditDate.Text.Length != 8)
                   return false;
                if(EditSal.Text.Length == 0)
                   return false;
                if(EditComm.Text.Length == 0)
                   return false;
                if(EditDept.Text.Length == 0)
                   return false;
                return true;
              }
        }

        private bool PutMyData(InputCheck Level) {
             int nData;
             float fData;

             if(EditEmpNo.Text.Length != 0) {
                   nData = int.Parse(EditEmpNo.Text);
                   if( fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[0]),
                                   ref nData,0)< 0)
                        return false;
              }
             if(Level == InputCheck.Pri_Key )
                   return true;

             if(EditName.Text.Length != 0)
                   if(fdl.FBPUT(nSndBuf, fdl.FBGET_FLDKEY(EmpFKey[1]),
                                  EditName.Text, EditName.Text.Length) < 0)
                      return false;
             if(EditJob.Text.Length != 0)
                   if(fdl.FBPUT( nSndBuf, fdl.FBGET_FLDKEY(EmpFKey[2]),
                                      EditJob.Text, EditJob.Text.Length) < 0 )
                      return false;
             if(EditMgr.Text.Length != 0) {
                    nData = int.Parse(EditMgr.Text);
                    if(fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[3]),
                                 ref nData,0)< 0 )
                       return false;
             }
             if(EditDate.Text.Length == 8)
                    if(fdl.FBPUT( nSndBuf, fdl.FBGET_FLDKEY(EmpFKey[4]),
                       EditDate.Text, EditDate.Text.Length) < 0 )
                          return false;
             if(EditSal.Text.Length != 0){
                    fData = float.Parse(EditSal.Text);
                    if(fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[5]),
                                  ref fData,0)< 0 )
                       return false;
             }
             if(EditComm.Text.Length != 0) {
                    fData = float.Parse(EditComm.Text);
                    if(fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[6]),
                                 ref fData,0)< 0 )
                       return false;
             }
             if(EditDept.Text.Length != 0) {
                    nData = int.Parse(EditDept.Text);
                    if(fdl.FBPUT(nSndBuf,fdl.FBGET_FLDKEY(EmpFKey[7]),
                                 ref nData,0)< 0)
                       return false;
             }
             return true;
        }

        private void MakeDataSet() {
             ResultData = new DataSet("dataGrid");

             tEmp = new DataTable("Employee");
             cEmpNo = new DataColumn(ColumnName[0],typeof(int));;
             cEName = new DataColumn(ColumnName[1],typeof(string));
             cJob = new DataColumn(ColumnName[2],typeof(string));
             cMgr = new DataColumn(ColumnName[3],typeof(int));
             cDate = new DataColumn(ColumnName[4],typeof(string));
             cSal = new DataColumn(ColumnName[5],typeof(float));
             cComm = new DataColumn(ColumnName[6],typeof(float));
             cDept = new DataColumn(ColumnName[7],typeof(int));

             tEmp.Columns.Add(cEmpNo);
             tEmp.Columns.Add(cEName);
             tEmp.Columns.Add(cJob);
             tEmp.Columns.Add(cMgr);
             tEmp.Columns.Add(cDate);
             tEmp.Columns.Add(cSal);
             tEmp.Columns.Add(cComm);
             tEmp.Columns.Add(cDept);

             ResultData.Tables.Add(tEmp);

             //DataRow newRow1 = tEmp.NewRow();
             dataGrid.SetDataBinding(ResultData, "Employee");
        }

        private void ReceiveError() {
             int nLeng = 0;
             object[] oEData = new object[ErrFLD_NUM];

             for(int i = 0; i < ErrFLD_NUM; i++) {
                 if(fdl.FBGET(nRcvBuf, fdl.FBGET_FLDKEY(ErrFKey[i]),
                              out oEData[i], ref nLeng) < 0 )
                     break;
             }
             ErrorProcess(oEData[2].ToString());
                 return;
        }
        protected override void Dispose( bool disposing ) {
             if(disposing) {
                if(components != null) {
                   components.Dispose();
                }
        }
        base.Dispose( disposing );
}

#region Windows Form Designer generated code
/*Design*/
        …
#endregion

static void Main() {
       Application.Run(new EmployeeMgr());
}

private void EmployeeMgr_Load(object sender, System.EventArgs e) {
        const string EnvFile = "D:\\tmax.env";

        if(atmi.TMAXREADENV(EnvFile,"TMAX") == -1 )
                ErrorProcess("Failed to read a configuration file. -"+ EnvFile);
}

private void BtnExit_Click(object sender, System.EventArgs e) {
         Dispose();
}

private void BtnIns_Click(object sender, System.EventArgs e) {
         int nLeng = 0;

         if(CheckInputData( InputCheck.All ) == false) {
                 ErrorProcess("There is a field with no data.\n
                               Enter 8 characters (YYYYMMDD) for a joining date.");
                 return;
          }

          bConnect = TmaxConnect();
          if(bConnect == false )
                  ErrorProcess("Could not connect to a server.");

          if(bTxRun == false) {
                  if(tx.TX_BEGIN() < 0) {
                         ErrorProcess( "TX_BEGIN Error");
                         return;
                   }
                   bTxRun = true;
          }

          if(nSndBuf != IntPtr.Zero )
                   atmi.TPFREE(ref nSndBuf);
          if((nSndBuf = fdl.FBALLOC( 5, 1000) ) == IntPtr.Zero )
                   ErrorProcess("FBALLOC - Memory allocation error");
          if(nRcvBuf != IntPtr.Zero )
                   atmi.TPFREE(ref nRcvBuf);
          if((nRcvBuf = fdl.FBALLOC( 5, 1000) ) == IntPtr.Zero )
                   ErrorProcess("FBALLOC - Memory allocation error");
          if(PutMyData( InputCheck.All ) == false) {
                   ErrorProcess("An error occurred during a field Key insertion.");
                   return;
           }
           if(atmi.TPCALL( "FDLINSERT", nSndBuf, 0, ref nRcvBuf,
              ref nLeng, atmi.TPNOFLAGS) < 0 ) {
                   ReceiveError();
                   return;
           }
           SuccessProcess( EditEmpNo.Text +"is inserted.");
}

private void BtnSel_Click(object sender, System.EventArgs e) {
         int nLeng = 0;
         object[] oData = new object[FIELD_NUM];

         if(CheckInputData( InputCheck.Pri_Key ) == false ) {
                  ErrorProcess("Enter an employee number.");
                  return;
         }

         bConnect = TmaxConnect();
         if(bConnect == false )
                  ErrorProcess("Could not connect to a server.");

         if(bTxRun == false ) {
                  if(tx.TX_BEGIN() < 0 ) {
                        ErrorProcess( "TX_BEGIN Error");
                        return;
                  }
                  bTxRun = true;
         }

         if(nSndBuf != IntPtr.Zero )
                  atmi.TPFREE(ref nSndBuf);
         if((nSndBuf = fdl.FBALLOC( 5, 1000) ) == IntPtr.Zero )
                  ErrorProcess("FBALLOC - Memory allocation error");
         if(nRcvBuf != IntPtr.Zero)
                  atmi.TPFREE(ref nRcvBuf);
         if((nRcvBuf = fdl.FBALLOC( 5, 1000)) == IntPtr.Zero)
                  ErrorProcess("FBALLOC - Memory allocation error");
         if ( PutMyData( InputCheck.Pri_Key ) == false) {
                  ErrorProcess("An error occurred during a field Key insertion.");
                  return;
         }

         if(atmi.TPCALL("FDLSELECT", nSndBuf, 0, ref nRcvBuf,
                         ref nLeng, atmi.TPNOFLAGS) < 0 ) {
                  ReceiveError();
                  return;
         }

         int OccrN =  fdl.FBKEYOCCUR(nRcvBuf,fdl.FBGET_FLDKEY(EmpFKey[0]));
         for(int j=0; j< OccrNum; j++) {
                  DataRow OutputRow = tEmp.NewRow();
                  for(int i=0; i< FIELD_NUM; i++) {
                            if(fdl.FBGET_TU( nRcvBuf, fdl.FBGET_FLDKEY(EmpFKey[i]),
                               j, out oData[i], ref nLeng) < 0 )
                                       break;
                  OutputRow[ColumnName[i]] = oData[i];
                  }
                  tEmp.Rows.Add(OutputRow);
         }

         SuccessProcess("Search Result");
         dataGrid.Visible = true;
         BtnBack.Visible = true;
         dataGrid.RowHeadersVisible = false;
}

private void BtnUpt_Click(object sender, System.EventArgs e) {
         int nLeng=0;
         if(CheckInputData( InputCheck.Pri_Key ) == false ) {
                   ErrorProcess("There is a field with no data.\n
                                 Enter 8 characters (YYYYMMDD) for a joining date.");
                   return;
         }

         bConnect = TmaxConnect();
         if(bConnect == false )
                   ErrorProcess("Could not connect to a server.");

         if( bTxRun == false ) {
                   if(tx.TX_BEGIN() < 0 ) {
                             ErrorProcess( "TX_BEGIN Error");
                             return;
                   }
                   bTxRun = true;
         }

         if(nSndBuf != IntPtr.Zero )
                   atmi.TPFREE(ref nSndBuf);
         if((nSndBuf = fdl.FBALLOC( 5, 1000) ) == IntPtr.Zero )
                   ErrorProcess("FBALLOC - Memory allocation error");
         if(nRcvBuf != IntPtr.Zero )
                   atmi.TPFREE(ref nRcvBuf);
         if((nRcvBuf = fdl.FBALLOC( 5, 1000) ) == IntPtr.Zero )
                   ErrorProcess("FBALLOC - Memory allocation error");

         if(PutMyData( InputCheck.All ) == false) {
                   ErrorProcess("An error occurred during a field Key insertion.");
                   return;
         }

         if(atmi.TPCALL("FDLUPDATE", nSndBuf, 0, ref nRcvBuf,
                        ref nLeng, atmi.TPNOFLAGS) < 0 ) {
                   ReceiveError();
                   return;
         }

         SuccessProcess(EditEmpNo.Text + "is modified.");
                        ClearWindow();
}

private void BtnDel_Click(object sender, System.EventArgs e) {
         int nLeng = 0;

         if( CheckInputData( InputCheck.Pri_Key ) == false ) {
                    ErrorProcess("Enter an employee number.");
                    return;
         }

         bConnect = TmaxConnect();
         if( bConnect == false )
                    ErrorProcess("Could not connect to a server.");

         if( bTxRun == false ) {
                    if( tx.TX_BEGIN() < 0 ) {
                             ErrorProcess( "TX_BEGIN Error");
                             return;
                    }
                    bTxRun = true;
         }
         if( nSndBuf != IntPtr.Zero )
                    atmi.TPFREE(ref nSndBuf);
         if( ( nSndBuf = fdl.FBALLOC( 5, 1000) ) == IntPtr.Zero )
                    ErrorProcess("FBALLOC - Memory allocation error");
         if( nRcvBuf != IntPtr.Zero )
                    atmi.TPFREE(ref nRcvBuf);
         if( ( nRcvBuf = fdl.FBALLOC( 5, 1000) ) == IntPtr.Zero )
                    ErrorProcess("FBALLOC - Memory allocation error");

         if( PutMyData( InputCheck.Pri_Key ) == false ) {
                    ErrorProcess("An error occurred during a field Key insertion.");
                    return;
         }

         if(atmi.TPCALL("FDLDELETE", nSndBuf, 0, ref nRcvBuf,
            ref nLeng, atmi.TPNOFLAGS) < 0) {
                    ReceiveError();
                    return;
         }

         SuccessProcess( EditEmpNo.Text + "has been deleted.");
         ClearWindow();

}

private void BtnBack_Click(object sender, System.EventArgs e) {
         dataGrid.Visible = false;
         BtnBack.Visible = false;
         ClearWindow();
}
}

2.5. Server Program

Service Program

The following is an example service program.

<emp_c.pc>

#include <stdio.h>
#include <ctype.h>
#include <tuxinc/macro.h>
#include "../../fdl/demo_fdl.h"

EXEC SQL include sqlca.h;
EXEC SQL INCLUDE ORACA;
EXEC ORACLE OPTION (ORACA=YES);
EXEC ORACLE OPTION (RELEASE_CURSOR=YES);

#define INP   1
#define ORA   2
#define TMX   3
#define APP   4

EXEC SQL begin declare section;
int  h_empno;
char h_ename[11];
char h_job[10];
int  h_mgr;
char h_date[11];
float h_sal;
float h_comm;
int  h_deptno;
EXEC SQL end declare section;

void svc_error(long type, long err_code, char *msg, long tmp);

FDLINSERT( TPSVCINFO *msg ) {
        FBUF *rcvbuf;
        int i, occurrence;
        rcvbuf = (FBUF *)msg->data;
        h_empno = h_mgr = h_sal = h_comm = h_deptno = 0;

        memset( h_ename, 0x00, sizeof( h_ename ) );
        memset( h_job, 0x00, sizeof( h_job ) );
        memset( h_date, 0x00, sizeof( h_date ) );

        occurrence = fbkeyoccur(rcvbuf, EMPNO);

        for (i=0; i< occurrence; i++){
             fbget_tu (rcvbuf, EMPNO, i, (char *)&h_empno, 0);
             fbget_tu (rcvbuf, MGR,   i, (char *)&h_mgr, 0);
             fbget_tu (rcvbuf, SAL,   i, (char *)&h_sal, 0);
             fbget_tu (rcvbuf, COMM,  i, (char *)&h_comm, 0);
             fbget_tu (rcvbuf, DEPTNO,i, (char *)&h_deptno, 0);
             fbget_tu (rcvbuf, ENAME, i, (char *)h_ename, 0);
             fbget_tu (rcvbuf, JOB  , i, (char *)h_job, 0);
             fbget_tu (rcvbuf, DATE , i, (char *)h_date, 0);

        EXEC SQL INSERT
        INTO emp(empno, ename, job, mgr, hiredate, sal,comm, deptno)
        VALUES (:h_empno, :h_ename, :h_job, :h_mgr,
                to_date(:h_date,'yyyymmdd'), :h_sal, :h_comm, :h_deptno);
        }

        if(sqlca.sqlcode != 0)
              goto LB_DBERROR;

        EXEC SQL WHENEVER SQLERROR
              goto LB_DBERROR;

        tpreturn(TPSUCCESS, 0L, (char *)rcvbuf, 0L, 0L);

        LB_DBERROR :
             EXEC SQL WHENEVER SQLERROR CONTINUE;
             svc_error(ORA, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, 0) ;
}


FDLDELETE( TPSVCINFO *msg )
{
        FBUF *rcvbuf;
        int i, occurrence;

        rcvbuf = ( FBUF *)msg->data;
        occurrence = fbkeyoccur(rcvbuf, EMPNO);

        for (i=0; i< occurrence; i++){
             fbget_tu (rcvbuf, EMPNO, i, (char *)&h_empno , 0);

        EXEC SQL DELETE
        FROM emp
        WHERE empno = :h_empno;
        }

        if(sqlca.sqlcode != 0)
                goto LB_DBERROR;

        EXEC SQL WHENEVER SQLERROR
                goto LB_DBERROR;

        EXEC SQL WHENEVER NOT FOUND
                goto LB_DBERROR;

        tpreturn(TPSUCCESS, 0L, (char *)rcvbuf, 0L, 0L);

        LB_DBERROR :
                EXEC SQL WHENEVER SQLERROR CONTINUE;
                svc_error(ORA, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, 0);
}

FDLSELECT( TPSVCINFO *msg )
{
        FBUF *rcvbuf;
        FLDLEN fldlen;
        int i=0, ROWMEM=200, CHKROW=500;

        rcvbuf = (FBUF *)msg->data;

        if((rcvbuf=(FBUF *)tprealloc((char *)rcvbuf,ROWMEM*CHKROW))==NULL){
            rcvbuf=(FBUF *)msg->data;
            goto LB_TMAXERROR ;
        }

        h_empno = h_mgr = h_sal = h_comm = h_deptno = 0;

        memset( h_ename, 0x00, sizeof( h_ename ) );
        memset( h_job, 0x00, sizeof( h_job ) );
        memset( h_date, 0x00, sizeof( h_date ) );

        fbget_tu( rcvbuf, EMPNO, 0, (char *)&h_empno, &fldlen);

        EXEC SQL DECLARE DB_CUR CURSOR FOR
        SELECT  nvl(empno,0), nvl(ename,' '), nvl(job,' '),
                nvl(to_char(hiredate,'yyyymmdd'),' '),  nvl(mgr,0),
                nvl(sal,0), nvl(comm,0), nvl(deptno,0)
        FROM  emp
        WHERE empno >= :h_empno-50 AND empno <= :h_empno+50;
        EXEC SQL OPEN DB_CUR;

        if(sqlca.sqlcode != 0)
              goto LB_DBERROR;
        EXEC SQL WHENEVER SQLERROR
              goto LB_DBERROR ;
        EXEC SQL WHENEVER NOT FOUND
              Do break ;

        while(1) {
              EXEC SQL FETCH DB_CUR
              INTO    :h_empno,
                      :h_ename,
                      :h_job,
                      :h_date,
                      :h_mgr,
                      :h_sal,
                      :h_comm,
                      :h_deptno;

                fbchg_tu(rcvbuf, EMPNO,  i,(char *)&h_empno, 0);
                fbchg_tu(rcvbuf, MGR,    i,(char *)&h_mgr, 0);
                fbchg_tu(rcvbuf, SAL,    i,(char *)&h_sal, 0);
                fbchg_tu(rcvbuf, DEPTNO, i,(char *)&h_deptno, 0);
                fbchg_tu(rcvbuf, COMM,   i,(char *)&h_comm, 0);
                fbchg_tu(rcvbuf, ENAME,  i,(char *)h_ename, 0);
                fbchg_tu(rcvbuf, JOB,    i,(char *)h_job, 0);
                fbchg_tu(rcvbuf, DATE,   i,(char *)h_date, 0);

                i++;
        }

        if (i < 1)
                goto LB_DBERROR;

        EXEC SQL CLOSE DB_CUR;

        tpreturn(TPSUCCESS, 0L, (char *)rcvbuf, 0L, 0L);

        LB_DBERROR :
                EXEC SQL WHENEVER SQLERROR CONTINUE;
                EXEC SQL CLOSE DB_CUR ;
                svc_error(ORA, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, 0L) ;

        LB_TMAXERROR :
                EXEC SQL WHENEVER SQLERROR CONTINUE;
                EXEC SQL CLOSE DB_CUR ;
                svc_error(TMX, tperrno, "", 0L) ;
}


FDLUPDATE( TPSVCINFO *msg ) {
        FBUF *rcvbuf ;
        int i, occurrence;
        rcvbuf = (FBUF *)msg->data;
        h_empno = h_mgr = h_sal = h_comm = h_deptno = 0;

        memset( h_ename, 0x00, sizeof( h_ename ) );
        memset( h_job, 0x00, sizeof( h_job ) );
        memset( h_date, 0x00, sizeof( h_date ) );

        occurrence = fbkeyoccur(rcvbuf, EMPNO);

        for (i=0; i< occurrence; i++) {
             fbget_tu (rcvbuf, EMPNO, i, (char *)&h_empno, 0);
             fbget_tu (rcvbuf, ENAME, i, (char *)h_ename, 0);
             fbget_tu (rcvbuf, JOB, i, (char *)h_job, 0);
             fbget_tu (rcvbuf, MGR, i, (char *)&h_mgr, 0);
             fbget_tu (rcvbuf, SAL, i, (char *)&h_sal, 0);
             fbget_tu (rcvbuf, COMM, i, (char *)&h_comm,0);
             fbget_tu (rcvbuf, DEPTNO, i, (char *)&h_deptno,0);
             fbget_tu (rcvbuf, DATE, i, (char *)h_date, 0 );

        EXEC SQL UPDATE emp
        SET ename = nvl(:h_ename, ename),
            job   = nvl(:h_job, job),
            mgr   = :h_mgr,
            hiredate  = nvl(to_date(:h_date,'yyyymmdd'),hiredate),
            sal   = :h_sal,
            comm  = :h_comm,
            deptno = :h_deptno
        WHERE empno = :h_empno;

        if(sqlca.sqlcode != 0)
               goto LB_DBERROR;

        EXEC SQL WHENEVER SQLERROR
               goto LB_DBERROR;

        EXEC SQL WHENEVER NOT FOUND
               goto LB_DBERROR;
        }
        tpreturn(TPSUCCESS, 0L, (char *)rcvbuf, 0L, 0L);

        LB_DBERROR :
                EXEC SQL WHENEVER SQLERROR CONTINUE;
                svc_error(ORA, sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc, 0L) ;
}

/*********************************************************************
 * Error Handling: If a service error occurs, the error will be entered in a buffer and then sent to a client.
 ********************************************************************/
void svc_error(long type, long err_code, char *msg,long tmp) {
        FBUF *transf;
        char *svcname;
        char err_msg[100];
        char temp[100];
        int i = 0;

        printf("type     ==>[%ld]\n", type);
        printf("err_code ==>[%ld]\n", err_code);
        printf("msg      ==>[%s]\n", msg);
        strcpy(err_msg, msg);

        if((transf = (FBFR *)tpalloc("FML", NULL, 0)) == NULL) {
            printf("tpalloc failed! errno = %d\n", tperrno);
        }

        switch(type) {
            case INP:
                switch(err_code) {
                       case -1000:
                             strcpy(err_msg, "The user has no privilege.");
                             break;
                       default:
                             strcpy(err_msg,
                                    "An input error message has not been registered.");
                }
                break;
            case ORA:
                if(strlen(err_msg)== 0)
                   strcpy(err_msg, sqlca.sqlerrm.sqlerrmc);
                   break;
            case TMX:
                if(strlen(err_msg)== 0) strcpy(err_msg, tpstrerror(tperrno));
                break;
            case APP:
                if(strlen(err_msg)== 0) {
                    /* An error message is set. ******/
                    switch(err_code) {
                           case -500:        /* SYSTEM error */
                                 strcpy(err_msg, "Failed to create a file.");
                                 break;
                           case -502:
                                 strcpy(err_msg, "Could not call an internal service.");
                                 break;
                           case -504:
                                 strcpy(err_msg, "Socket communication error.");
                                 break;
                           case -505:  /* When a change was made in another transaction */
                                 /* "[%s] was changed in another transaction after it was queried.
                                 \n\nHandle it after querying it again.": Handling in CLIENT */
                                 strcpy(err_msg,"does not exist.");
                                 break;
                           case -5002:
                                 strcpy(err_msg, "Contact with a technical team.");
                                 break;
                           default:
                                 strcpy(err_msg,
                                 "An application error message has not been registered.");
                    }
                }
                break;
        }

        /* ROLLBACK        */
        EXEC SQL WHENEVER SQLERROR CONTINUE;
        EXEC SQL ROLLBACK;

        fbchg_tu (transf, E_TYPE, i, (char *)&type,0);
        fbchg_tu (transf, E_CODE, i, (char *)&err_code,0);
        fbchg_tu (transf, E_MSG, i, (char *)err_msg,0);
        fbchg_tu (transf, E_TMP, i, (char *)&tmp,0);

        tpreturn(TPFAIL, 0, (char *)transf, 0L, 0L);
}
Makefile

The following is an example Makefile that builds emp_c.pc into a Tmax application.

<emp_c.mk>

include $(ORACLE_HOME)/precomp/lib/env32.mk
ORALIBDIR = $(LIBHOME)
ORALIB = -L/home/oracle/OraHome/lib32/ -lclntsh  -lld -lm
          `cat /home/oracle/OraHome/lib32/sysliblist`  -lm  -lc_r -lpthreads

TARGET = emp_c
APOBJS = emp_c.o
NSDLOBJ = $(TMAXDIR)/lib/sdl.o

#CC
CC=cc

#Oracle
LIBS    = -lsvr -loras
OBJS    = $(APOBJS) $(SVCTOBJ)
SVCTOBJ = $(TARGET)_svctab.o
CFLAGS  = -q32 -O -I$(TMAXDIR)
LDFLAGS = -brtl

APPDIR  = $(TMAXDIR)/appbin
SVCTDIR = $(TMAXDIR)/svct
TMAXLIBDIR  = $(TMAXDIR)/lib
 #
.SUFFIXES : .c
.c.o:
           $(CC) $(CFLAGS) $(LDFLAGS) -c $<
all: $(TARGET)

$(TARGET): $(OBJS)
           $(CC) $(CFLAGS) $(LDFLAGS) -L$(TMAXLIBDIR) -o $(TARGET)
           -L$(ORALIBDIR)
           $(ORALIB) $(OBJS) $(LIBS) $(NSDLOBJ)
           mv $(TARGET) $(TMAXDIR)/appbin

$(APOBJS): $(TARGET).pc
           proc iname=emp_c include=$(TMAXDIR) define=__LINUX_ORACLE_PROC__
           $(CC) $(CFLAGS) $(LDFLAGS) -c $(TARGET).c

$(SVCTOBJ):
           touch $(SVCTDIR)/$(TARGET)_svctab.c
           $(CC) $(CFLAGS) $(LDFLAGS) -c $(SVCTDIR)/$(TARGET)_svctab.c

#clean:
           -rm -f *.o core $(TARGET) $(TARGET).lis