home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / IMHAPI10.ZIP / HAPIREXX.C < prev    next >
C/C++ Source or Header  |  1991-12-07  |  15KB  |  388 lines

  1. /*****************************************************************************
  2.  *
  3.  *  HAPIREXX.C creates a DLL for use with REXX.  Specifically, HapiRexx 
  4.  *             contains two external REXX functions, MkHaPipe and ToHapi
  5.  *             to create a named pipe, start IMHAPI and commnunicate to
  6.  *             IMHAPI over that pipe.
  7.  *
  8.  *             While REXX can work directly with named pipes (via 'stream()',
  9.  *             ' linein()' and 'lineout()' functions), it can't (as far as 
  10.  *             I know) create a pipe.  If that's possible I'd appreciate
  11.  *             learning how.  Otherwise, since IMHAPI (in version 1.0)
  12.  *             can't create one either, we're forced to have an external
  13.  *             function (MkHaPipe) create a pipe and then use
  14.  *             another function use it.  If it were possible to have REXX 
  15.  *             functions use the pipe created by MkHaPipe, it would be great
  16.  *             but I couldn't get that to work either.  So, again, another
  17.  *             external function is needed, ToHapi.  If there is a means
  18.  *             to get around these REXX limitations, please share it with
  19.  *             me.  My electronic and physical addresses are listed below. 
  20.  *             
  21.  *             MkHaPipe creates a named pipe (from the parameter it is passed), 
  22.  *             then starts IMHAPI.EXE, pointing IMHAPI to the newly created pipe
  23.  *             and, if successful, exits, passing back the pipe handle number 
  24.  *             for that named pipe.  
  25.  *             
  26.  *             ToHapi engages in a converation with IMHAPI via the
  27.  *             pipe created by MkHaPipe.  ToHapi expects two parameters, 
  28.  *             the pipe handle number passed back by MkHapiRexx and the 
  29.  *             command intended for IMHAPI.  It waits for a response and 
  30.  *             returns the result to the REXX program which called it.
  31.  *             
  32.  *             IMHAPI is a program which allows a user to issue EHLLAPI
  33.  *             commands either interactively (from command line prompt or
  34.  *             via a pipe) or from a file of commands.
  35.  *             
  36.  *             IMHAPI.DOC should be included with this file set.  Please
  37.  *             consult that for more information on IMHAPI.
  38.  *             
  39.  *             The HAPIREXX.DLL file must be copied into a file that is
  40.  *             in the LIBPATH concatenation defined in the CONFIG.SYS file 
  41.  *             of a user's machine.
  42.  *             These functions must also be registered with the REXX program
  43.  *             which intends to use them.  That is accomplished with the 
  44.  *             REXX statements:
  45.  *                  CALL RxFuncAdd 'MkHaPipe',     'HAPIREXX', 'MKHAPIPE'
  46.  *                  CALL RxFuncAdd 'ToHapi',       'HAPIREXX', 'TOHAPI'  
  47.  *             MkHaPipe must be called before ToHapi is used and ToHapi 
  48.  *             must use a handle suppiled by MkHaPipe or errors will result!
  49.  *             The pipe and IMHAPI process can be closed by calling ToHapi with 
  50.  *             the command 'closepipe' as the second parameter.
  51.  *
  52.  *             MkHaPipe can return the following messages:
  53.  *               MKPIPERR: Invalid Pipe Parameter.
  54.  *               MKPIPERR: Not Enough Memory to Open Pipe.
  55.  *               MKPIPERR: Pipe Unopened - Out of Structures.
  56.  *               MKPIPERR: Pipe Unopened - Path Not Found.
  57.  *               MKPIPERR: Pipe Busy.
  58.  *               MKPIPERR: Unknown Pipe Error: <OS/2 Error Code>
  59.  *               CREPGMER: Unable to start IMHAPI.EXE, request failed with 
  60.  *                         return code: <OS/2 Error Code>
  61.  *               NOCONECT: Unable to establish connection to IMHAPI via the pipe.
  62.  *
  63.  *             ToHapi can return the following messages:
  64.  *               INCOPARM: ToHapi requires two parameters.
  65.  *               NOTNUMER: ToHapi requires a numeric pipe handle for its first parameter.
  66.  *               TRPIPERR: Bad Pipe
  67.  *               TRPIPERR: Interrupt Waiting for Pipe
  68.  *               TRPIPERR: Time Out Waiting for Pipe
  69.  *               TRPIPERR: Invalid Function
  70.  *               TRPIPERR: Unknown Pipe Error: <OS/2 Error Code>
  71.  *             
  72.  *
  73.  *             PLEASE NOTE:  This program is offered with NO warranties
  74.  *             or guarrantees of ANY kind, either expressed or implied.
  75.  *             Use of this program and any accompanying programs or materials 
  76.  *             is entirely at the risk of the user of those programs and 
  77.  *             materials.  The set of archived files and programs, of which 
  78.  *             this is a member, is offered as an means of sharing information 
  79.  *             and techniques about aspects of OS/2 programming and usage.
  80.  *             If there are any questions about this program or materials,
  81.  *             please contact the author (address below).
  82.  *             
  83.  *             I really would appreciate your comments on this program,
  84.  *             its operation with REXX and its general level of usefulness.
  85.  *             I can be reached at:
  86.  *             
  87.  *                          Paul Firgens
  88.  *                          461 Glenwood Heights
  89.  *                          Wisconsin Rapids, WI 54494-6264
  90.  *                          CompuServ Member ID: 73577,1234
  91.  *             
  92.  *             Thanks, in advance!
  93.  *             
  94.  *              Copyright (c) 1991, Paul Firgens, All Rights Reserved
  95.  *
  96.  *
  97.  *****************************************************************************
  98.  *             
  99.  *  This program was developed using the Lattice C compiler, ver. 6.05.
  100.  *  I know that's more than a little unusual, but it's all I had access to.
  101.  *  Basically, I found it worked fine, although with no other OS/2 C 
  102.  *  compiler to compare it to, a complete judgement is hard to provide.
  103.  *  At any rate, Lattice provides versions of the STRING.H functions
  104.  *  which specifically require far pointers as arguments and I chose to use
  105.  *  some of those (_fmemcpy, _fmemmove and _fstrcpy) for this program.
  106.  *  The '__private' keyword helps us follow Microsoft conventions
  107.  *  for OS/2 programs, apparently.  According to the Lattice docs, 
  108.  *  __private tells the compiler to initialize a DLL function's DS 
  109.  *  register to the DLL's DGROUP.
  110.  *  Since REXX and DLLs need these features, I used them here, yet used a 
  111.  *  '#define' to help state the function calls in forms that other C 
  112.  *  compilers could also use.  Hope it helps...
  113.  *             
  114.  *****************************************************************************
  115.  */
  116.  
  117. #if LATTICE
  118. #define memcpy  _fmemcpy
  119. #define memmove _fmemmove
  120. #define strcpy  _fstrcpy
  121. #define __APIENTRY __private APIENTRY 
  122. #else
  123. #define __APIENTRY APIENTRY 
  124. #endif
  125.    
  126. #define INCL_BASE
  127. #define INCL_DOSNMPIPES
  128. #define INCL_DOSFILEMGR
  129. #define INCL_ERRORS
  130. #define INCL_DOSPROCESS
  131.  
  132. #include <os2.h>
  133. #include <dos.h>
  134. #include <stdio.h>
  135. #include <string.h>
  136. #include <stdlib.h>
  137. #include <doscalls.h>
  138. #include <_string.h>
  139. #include <ctype.h>
  140. #include <rexxsaa.h>
  141.  
  142. #define COUNT_OUTBUF    4096
  143. #define COUNT_INBUF     4096
  144. #define DEF_TIMEOUT     5000L
  145. #define READ_BUFFER     4096
  146.  
  147. #define PIPE_ACCESS_DUPLEX  0x0002
  148. #define PIPE_ACCESS_IN      0x0000
  149. #define PIPE_ACCESS_OUT     0x0001
  150. #define PIPE_WRITEBEHIND    0x0000
  151. #define PIPE_NOWRITEBEHIND  0x4000
  152. #define PIPE_INHERIT        0x0000
  153. #define PIPE_NOINHERIT      0x0080
  154. #define PIPE_WAIT           0x0000
  155. #define PIPE_NOWAIT         0x8000
  156. #define PIPE_BYTE_MODE      0x0000
  157. #define PIPE_STREAM_MODE    0x0400
  158. #define PIPE_BYTE_READ      0x0000
  159. #define PIPE_STREAM_READ    0x0100
  160.  
  161.  
  162. /*****************************************************************************
  163.  *
  164.  * MkHaPipe: create a pipe, start an async process and return the handle
  165.  *           which points to the pipe.  The handle is returned as    
  166.  *           a numeric character rather than as a binary integer.       
  167.  *
  168.  *****************************************************************************
  169.  */
  170.  
  171. SHORT __APIENTRY  MkHaPipe(
  172.       PSZ       name,             /* name of function       */
  173.       USHORT    argc,             /* argument count         */
  174.       PRXSTRING argv,             /* argument list          */
  175.       PSZ       QueueName,        /* current active queue   */
  176.       PRXSTRING retval)           /* return value           */
  177.  
  178. {
  179.  
  180.     short   rc, c; 
  181.     HPIPE   hp;    
  182.     char    pdream[255];
  183.     char    smsg[8];
  184.     CHAR        chFailName[100];
  185.     RESULTCODES rescResults;
  186.     
  187.     rc = c = 0;
  188.     memset(retval->strptr, '\0', 249);  /* NULL out the area from REXX */
  189.  
  190.     /* string together the command line that IMHAPI expects to find */
  191.     memset(pdream, '\0', 255);
  192.     memmove(pdream, "IMHAPI", 6);
  193.     memmove((PSZ)&pdream[7], argv[0].strptr, (USHORT)argv[0].strlength); 
  194.         
  195.     /* Create a named pipe... */
  196.     if((rc = DosMakeNmPipe((PSZ)&pdream[7],
  197.             &hp,
  198.             PIPE_NOWRITEBEHIND | PIPE_NOINHERIT | PIPE_ACCESS_DUPLEX, 
  199.             PIPE_NOWAIT | PIPE_STREAM_MODE | PIPE_STREAM_READ | 1,
  200.             COUNT_OUTBUF, COUNT_INBUF, DEF_TIMEOUT)))
  201.     {   
  202.         switch(rc) 
  203.         {
  204.         case (ERROR_INVALID_PARAMETER):
  205.             sprintf(retval->strptr, "MKPIPERR: Invalid Pipe Parameter.");
  206.             break;
  207.         case (ERROR_NOT_ENOUGH_MEMORY):
  208.             sprintf(retval->strptr, "MKPIPERR: Not Enough Memory to Open Pipe.");
  209.             break;
  210.         case (ERROR_OUT_OF_STRUCTURES):
  211.             sprintf(retval->strptr, "MKPIPERR: Pipe Unopened - Out of Structures.");
  212.             break;
  213.         case (ERROR_PATH_NOT_FOUND):
  214.             sprintf(retval->strptr, "MKPIPERR: Pipe Unopened - Path Not Found.");
  215.             break;
  216.         case (ERROR_PIPE_BUSY):
  217.             sprintf(retval->strptr, "MKPIPERR: Pipe Busy.");
  218.             break;
  219.         default:
  220.             sprintf(retval->strptr, "MKPIPERR: Unknown Pipe Error: %u.", rc);
  221.             break;
  222.         }
  223.     }
  224.     else  
  225.     {
  226.         rc = 0;
  227.         /* start IMHAPI to process messages from the pipe */
  228.         rc = DosExecPgm(chFailName, 
  229.             sizeof(chFailName), 
  230.             2, 
  231.             pdream, 
  232.             0, 
  233.             &rescResults, 
  234.             "imhapi.exe"); 
  235.  
  236.         /* if the DosExecPgm call fails tell the REXX pgm about it and close the
  237.          * pipe
  238.          */
  239.         if(rc)
  240.         {
  241.             sprintf(retval->strptr, "CREPGMER: Unable to start IMHAPI.EXE, request failed with return code: %u\n", rc);
  242.             retval->strlength = strlen(retval->strptr);
  243.             DosClose(hp);
  244.             return(0);
  245.         }
  246.         
  247.         /* once IMHAPI is going, attempt to connect via the pipe - try 25 times */
  248.         do 
  249.         {
  250.             rc = DosConnectNmPipe(hp);
  251.             if (rc) 
  252.             {
  253.                /* sprintf(smsg, "  waiting for connection: %u.\r\n\0", rc);
  254.                 * VioWrtTTY(smsg,strlen(smsg),0);
  255.                 */
  256.                 DosSleep(250L);
  257.                 c++;
  258.             }
  259.         }
  260.         while ( (c<25) && rc ); 
  261.         
  262.         /* if the connection can't be made, close the pipe and tell REXX */
  263.         if (c>=25) 
  264.         {
  265.             sprintf(retval->strptr, "NOCONECT: Unable to establish connection to IMHAPI via the pipe.\n");
  266.             retval->strlength = strlen(retval->strptr);
  267.             DosClose(hp);
  268.             return(0);
  269.         }
  270.   
  271.         /* everything looks OK so make a numeric digit out of the pipe handle */
  272.         memset(smsg, '\0', 8);
  273.         memset(retval->strptr, '\0', 249);
  274.         sprintf(smsg, "%u " , hp);
  275.         memmove(retval->strptr, smsg, strlen(smsg)); 
  276.        
  277.     }
  278.  
  279.     retval->strlength = strlen(retval->strptr);
  280.     return(0);
  281.  }
  282.  
  283. /*****************************************************************************
  284.  *
  285.  * ToHapi: receive command from REXX, send it down the pipe, wait for
  286.  *         answer and return result to REXX
  287.  *
  288.  *****************************************************************************
  289.  */
  290.  
  291. SHORT __APIENTRY ToHapi(
  292.       PSZ       name,             /* name of function       */
  293.       USHORT    argc,             /* argument count         */
  294.       PRXSTRING argv,             /* argument list          */
  295.       PSZ       QueueName,        /* current active queue   */
  296.       PRXSTRING retval)           /* return value           */
  297.       
  298. {
  299.     unsigned    rc, c;
  300.     char        parm1[8];
  301.     char        parm2[256];
  302.     HPIPE       hp;
  303.     SHORT       sBytesReceived;
  304.     PCH         psReceivedBuf;
  305.     SEL         ReceivedSel;
  306.     
  307.     /* get some space to hold the results returned from the pipe */
  308.     DosAllocSeg(READ_BUFFER, &ReceivedSel, 0); 
  309.     psReceivedBuf = MAKEP(ReceivedSel,0);
  310.  
  311.     hp = c = 0;
  312.     
  313.     if (argc < 2)
  314.     {
  315.         sprintf(retval->strptr, "INCOPARM: ToHapi requires two parameters.\n");
  316.         retval->strlength = strlen(retval->strptr);
  317.         return(0);
  318.     }
  319.         
  320.     memset(parm1, '\0', 8);
  321.     memset(parm2, '\0', 256);
  322.     memset(psReceivedBuf, '\0', READ_BUFFER);
  323.     
  324.     /* collect the parms, and convert the pipe handle digit to a binary no. */
  325.     memmove(parm1, argv[0].strptr, (USHORT)argv[0].strlength); 
  326.     
  327.     if (!(isdigit(parm1[0])))
  328.     {
  329.         sprintf(retval->strptr, (PSZ)"NOTNUMER: ToHapi requires a numeric pipe handle for its first parameter.\n");
  330.         retval->strlength = strlen(retval->strptr);
  331.         return(0);
  332.     }
  333.     
  334.     hp = atoi(parm1); 
  335.     memmove(parm2, argv[1].strptr, (USHORT)argv[1].strlength);
  336.  
  337.     /* check the second parm, if it is "closepipe", shut the pipe down (this 
  338.      * will also terminate IMHAPI) and return to REXX....
  339.      */
  340.     if(!(strcmp(parm2, "closepipe")) )
  341.     {
  342.         DosClose(hp);
  343.         return(0);
  344.     }
  345.     /* otherwise, send the second parm off to IMHAPI and wait for a 
  346.      * response
  347.      */
  348.     else
  349.     {
  350.         memset(psReceivedBuf, '\0', READ_BUFFER);
  351.         rc = DosTransactNmPipe(hp, 
  352.             argv[1].strptr, 
  353.             (USHORT)argv[1].strlength, 
  354.             (PSZ)psReceivedBuf,
  355.             4096,
  356.             &sBytesReceived);
  357.         /* if there is an error, tell the REXX pgm about it */
  358.         if (rc)
  359.         {
  360.             switch(rc) 
  361.             {
  362.                 case(ERROR_BAD_PIPE):
  363.                     sprintf(retval->strptr, "TRPIPERR: Bad Pipe");
  364.                     break;
  365.                 case(ERROR_INTERRUPT):
  366.                     sprintf(retval->strptr, "TRPIPERR: Interrupt Waiting for Pipe");
  367.                     break;
  368.                 case(ERROR_SEM_TIMEOUT):
  369.                     sprintf(retval->strptr, "TRPIPERR: Time Out Waiting for Pipe");
  370.                     break;
  371.                 case(ERROR_INVALID_FUNCTION):
  372.                     sprintf(retval->strptr, "TRPIPERR: Invalid Function");
  373.                     break;
  374.                 default:
  375.                     sprintf(retval->strptr, "TRPIPERR: Unknown Pipe Error: %u", rc);
  376.                     break;
  377.             }
  378.         }
  379.         /* transaction completed and now return result to REXX */
  380.         else
  381.             retval->strptr = psReceivedBuf; 
  382.         retval->strlength = sBytesReceived;
  383.         return 0;
  384.     }
  385. }
  386.  
  387.  
  388.