Microsoft KB Archive/64354

How to Use Named Pipes in a Protected Mode COBOL 4.00 Program

PSS ID Number: Q64354 Article last modified on 01-03-1992

4.00 OS/2

Summary: Microsoft COBOL version 4.00 can create protected mode programs that use named pipes. Named pipes are data structures used for interprocess communications (IPC). Their use involves calling several different OS/2 API functions. Below are two sample COBOL programs that demonstrate the use of named pipes. This information applies to Microsoft COBOL Professional Development System (PDS) version 4.00 for MS OS/2.

More Information: Named pipes can be used for communication between unrelated processes running on the same system or between processes running on different machines on a local area network. Their names have the following form: For a local pipe: .ext For a remote pipe: \machine.ext Here, “machine” is the name of the remote computer. Also, “.ext” is optional. In a typical application, one program (called the server) will create one or more instances of a named pipe, and other programs (called clients) will connect to those instances. Data can then be transferred between the server and its clients, but not between the clients directly (although, a client may also be a server for another named pipe). The minimal OS/2 API calls involved in programming named pipes are the following:

DosMakeNmPipe Creates an instance of the named pipe. DosConnectNmPipe Makes a pipe instance available to a client. DosDisconnectNmPipe Disconnects a client from its pipe instance. DosPeekNmPipe Gets the status of a pipe instance. DosRead Gets data from a pipe instance. DosWrite Puts data into a pipe instance. DosClose Relinquishes the handle to a pipe instance.

DosOpen Connects a client to a pipe instance. DosPeekNmPipe Gets the status of a pipe instance. DosRead Gets data from a pipe instance. DosWrite Puts data into a pipe instance. DosClose Relinquishes the handle to a pipe instance.

For more information about calling OS/2 API functions from COBOL, see Chapter 14, “Interfacing with OS/2 API Routines,” in the “Microsoft COBOL Compiler 4.0: Operating Guide.” For more information about named pipes and other IPC functions, see Chapter 13, “Interprocess Communication,” in “Advanced OS/2 Programming” by Ray Duncan (Microsoft Press, 1989). Following are two sample programs that demonstrate how to use named pipes with COBOL (local only). Run each program in a separate OS/2 screen group and switch between sessions to see the results. As you key in data from the server session, it will appear in all the client screen groups. Likewise, any data keyed in from a client session will appear in the server screen group. Remember to always run the server first. Note that COBOL’s default calling convention is the reverse of the convention used by the API functions. This can be overridden using the SPECIAL-NAMES paragraph, but it is not done in these examples. Note: To run these example programs across a LAN Manager network, CLIENT.CBL must be modified to allow a pipe name with a machine name preceding &quot;&quot;. Also, the machine running SERVER.CBL will have to share IPC$. To compile and link the programs, enter the following from the OS/2 command prompt (the compile lines assume you are not using a COBOL.DIR file): cobol server; link server,,,coblib os2; cobol client link client,,,coblib os2;

SERVER.CBL
* SERVER.CBL creates 30 instances of the named pipe specified by * the user. As these instances are opened by client processes, * the server will display output from them and allow the user to * send output to them. When the server receives an ESC * character from a client, the client is disconnected and the * instance is made available to other clients. When the server * reads an ESC character from the keyboard, it sends this to * all the clients (which then close their instance) and destroys * the pipe and terminates. IDENTIFICATION DIVISION. PROGRAM-ID. Server. DATA DIVISION. WORKING-STORAGE SECTION. *  Parameters for DosMakeNmPipe. *  Global name of pipe. 01 PipeName         PIC X(256)       VALUE &quot;\PIPE\&quot;. *  Handles to the instances of the pipe. 01 Handles          PIC 9(4)  COMP-5 OCCURS 30 TIMES. *  Specifies bidirectional I/O. 01 OpenMode         PIC 9(4)  COMP-5 VALUE 2. *  Specifies that an infinite number of instances of pipe may *  be opened, allowed read mode is byte stream only, write mode *  is also byte stream, and no blocking will be used. 01 PipeSpecs        PIC 9(4)  COMP-5 VALUE 33023. *  Specifies 512 byte output buffer. 01 OutBuffer        PIC 9(4)  COMP-5 VALUE 512. *  Specifies 512 byte input buffer. 01 InBuffer         PIC 9(4)  COMP-5 VALUE 512. *  Timeout is irrelevant since there is no blocking. 01 Timeout          PIC 9(8)  COMP-5. *  Parameters for DosPeekNmPipe. *  Length of variable used to send and receive data is 1. 01 BufferLength     PIC 9(4)  COMP-5 VALUE 1. *  Receives number of bytes remaining in the pipe. 01 SizeInfo. 05 BytesWaiting  PIC 9(4)  COMP-5. 05 MessageSize   PIC 9(4)  COMP-5. *  Receives status of pipe (disconnected, listening, etc.). 01 PipeStatus       PIC 9(4)  COMP-5. *  Parameters for DosRead. *  Number of bytes desired to be read. 01 BytesToRead      PIC 9(4)  COMP-5 VALUE 1. *  Receives actual number of bytes read. 01 BytesRead        PIC 9(4)  COMP-5. *  Parameters for DosWrite. *  Number of bytes desired to be written. 01 BytesToWrite     PIC 9(4)  COMP-5 VALUE 1. *  Receives number of bytes actually written. 01 BytesWritten     PIC 9(4)  COMP-5. * Other parameters. * Used to refer to a particular instance (handle) of the pipe. 01 H                PIC 9(2)  COMP-5. * Used to receive data from pipe. 01 Buffer           PIC X.  *  Used to send data to pipe and read keyboard buffer. 01 KeyCode          PIC X.  *  Used to check if key is waiting in keyboard buffer. 01 KeyStatus        PIC 99    COMP-X. PROCEDURE DIVISION. *   Get the name of the pipe and terminate it with a null. DISPLAY &quot;Enter the name of the pipe:&quot;. ACCEPT PipeName(7:249). INSPECT PipeName REPLACING FIRST &quot; &quot; BY X&quot;00&quot;. *   Create 30 instances of pipe and put them in listening mode. PERFORM VARYING H FROM 1 BY 1 UNTIL H > 30 CALL &quot;__DosMakeNmPipe&quot; USING   BY VALUE     Timeout, BY VALUE    InBuffer, BY VALUE    OutBuffer, BY VALUE    PipeSpecs, BY VALUE    OpenMode, BY REFERENCE Handles(H), BY REFERENCE PipeName CALL &quot;__DosConnectNmPipe&quot; USING BY VALUE Handles(H) END-PERFORM. DISPLAY &quot;30 instances of the pipe have been created.&quot;. *   Loop until an ESC character (ASCII 27) is hit. PERFORM UNTIL KeyCode = X&quot;1B&quot; *      Get status of keyboard buffer. CALL X&quot;D9&quot; USING KeyStatus *      Read in a key if one is waiting in the buffer. IF KeyStatus NOT = 0 THEN CALL X&quot;83&quot; USING KeyCode END-IF *      Perform the loop for each instance of the pipe. PERFORM VARYING H FROM 1 BY 1 UNTIL H > 30 *         Get the status on the current pipe instance. CALL &quot;__DosPeekNmPipe&quot; USING BY REFERENCE PipeStatus, BY REFERENCE SizeInfo, BY REFERENCE BytesRead, BY VALUE    BufferLength, BY REFERENCE Buffer, BY VALUE    Handles(H) EVALUATE PipeStatus *         Check if current pipe instance is in connected mode. WHEN 3 *            Check if bytes are waiting to be read from pipe. IF BytesWaiting > 0 THEN *               Read one byte from the pipe. CALL &quot;__DosRead&quot; USING BY REFERENCE BytesRead, BY VALUE    BytesToRead, BY REFERENCE Buffer, BY VALUE    Handles(H) *               If client sent a carriage-return, display a  *                space instead, since in a text window OS/2 will *               actually display the carriage-return character *               (an eighth note). Any other data can be *                displayed normally. EVALUATE Buffer WHEN X&quot;0D&quot; DISPLAY &quot; &quot; WHEN OTHER DISPLAY Buffer WITH NO ADVANCING END-EVALUATE END-IF *            If a key was read, write it to the pipe instance. IF KeyStatus NOT = 0 THEN CALL &quot;__DosWrite&quot; USING BY REFERENCE BytesWritten, BY VALUE    BytesToWrite, BY REFERENCE KeyCode, BY VALUE    Handles(H) *               If the key read was ESC, close the instance. IF KeyCode = X&quot;1B&quot; THEN CALL &quot;__DosClose&quot; USING BY VALUE Handles(H) END-IF END-IF *         Check if current pipe instance is in closing mode. WHEN 4 *            Put the instance of the pipe in listening mode. A *             client process will then be able to use DosOpen to  *             connect to the instance. CALL &quot;__DosDisconnectNmPipe&quot; USING BY VALUE Handles(H) CALL &quot;__DosConnectNmPipe&quot;   USING BY VALUE Handles(H) END-EVALUATE END-PERFORM END-PERFORM. *   Beep and end. DISPLAY &quot; &quot;. DISPLAY &quot;The pipe has been destroyed.&quot;. CALL X&quot;E5&quot;. STOP RUN.

CLIENT.CBL
* CLIENT.CBL waits for an instance of a user-specified named * pipe to open [by looping on a call to DosOpen] and when it has * connected, it displays output from the server and allows the * user to send output to the server. When the client receives * an ESC character either from the keyboard or the server, it * closes its instance of the pipe and terminates. IDENTIFICATION DIVISION. PROGRAM-ID. Client. DATA DIVISION. WORKING-STORAGE SECTION. *  Parameters for DosOpen. *  Global name of pipe. 01 PipeName         PIC X(256)       VALUE &quot;\PIPE\&quot;. *  Handle to pipe. 01 Handle           PIC 9(4)  COMP-5. *  Receives action taken by DosOpen. 01 Action           PIC 9(4)  COMP-5. *  Since the pipe already exists and will not be replaced, *  the initial allocation in bytes is irrelevant. 01 Allocation       PIC 9(8)  COMP-5. *  Specifies to treat the pipe as normal file. 01 Attribute        PIC 9(4)  COMP-5 VALUE 0. *  Specifies to open the pipe if it exists, fail if not. 01 OpenFlag         PIC 9(4)  COMP-5 VALUE 1. *  Specifies bidirectional I/O with shared read/write privileges. 01 OpenMode         PIC 9(4)  COMP-5 VALUE 18. *  Reserved by OS/2, set to 0. 01 Reserved         PIC 9(8)  COMP-5 VALUE 0. *  Parameters for DosPeekNmPipe. *  Length of variable used to send and receive data is 1. 01 BufferLength     PIC 9(4)  COMP-5 VALUE 1. *  Receives number of bytes remaining in the pipe. 01 SizeInfo. 05 BytesWaiting  PIC 9(4)  COMP-5. 05 MessageSize   PIC 9(4)  COMP-5. *  Receives status of pipe (disconnected, listening, etc.) 01 PipeStatus       PIC 9(4)  COMP-5. *  Parameters for DosRead. *  Number of bytes desired to be read. 01 BytesToRead      PIC 9(4)  COMP-5 VALUE 1. *  Receives actual number of bytes read. 01 BytesRead        PIC 9(4)  COMP-5. *  Parameters for DosWrite. *  Number of bytes desired to be written. 01 BytesToWrite     PIC 9(4)  COMP-5 VALUE 1. *  Receives number of bytes actually written. 01 BytesWritten     PIC 9(4)  COMP-5. *  Other variables. *  Used to send and receive data to and from pipe. 01 Buffer           PIC X.  *   Used to check if key is waiting in keyboard buffer. 01 KeyStatus        PIC 99    COMP-X. *  Used to store any errors of API function. 01 ErrorCode        PIC S9(4) COMP-5. PROCEDURE DIVISION. *   Loop until a pipe instance is opened successfully. PERFORM UNTIL ErrorCode = 0 MOVE -1 TO ErrorCode *      Get the name of the pipe and terminate it with a null. DISPLAY &quot;Enter the name of the pipe:&quot; ACCEPT PipeName(7:249) INSPECT PipeName REPLACING FIRST &quot; &quot; BY X&quot;00&quot; PERFORM UNTIL (ErrorCode = 3) OR (ErrorCode = 0) CALL &quot;__DosOpen&quot; USING BY VALUE    Reserved, BY VALUE    OpenMode, BY VALUE    OpenFlag, BY VALUE    Attribute, BY VALUE    Allocation, BY REFERENCE Action, BY REFERENCE Handle, BY REFERENCE PipeName RETURNING   ErrorCode IF ErrorCode = 3 THEN DISPLAY &quot;Not a valid pipe.&quot; CALL X&quot;E5&quot; END-IF END-PERFORM END-PERFORM. DISPLAY &quot;The pipe has been opened.&quot;. *   Loop until an ESC key (ASCII 27) is hit. PERFORM UNTIL Buffer = X&quot;1B&quot; *      Get number of bytes waiting to be read from pipe. CALL &quot;__DosPeekNmPipe&quot; USING BY REFERENCE PipeStatus, BY REFERENCE SizeInfo, BY REFERENCE BytesRead, BY VALUE    BufferLength, BY REFERENCE Buffer, BY VALUE    Handle *      Check if there are bytes to read from the pipe. IF BytesWaiting > 0 THEN *         Read 1 byte from the pipe. CALL &quot;__DosRead&quot; USING BY REFERENCE BytesRead, BY VALUE    BytesToRead, BY REFERENCE Buffer, BY VALUE    Handle *         Display the byte read. If it is a carriage-return, *         display a space instead, since in a text window OS/2 *         will actually the display the carriage-return *         character (an eighth note). IF Buffer = X&quot;0D&quot; THEN DISPLAY &quot; &quot; ELSE DISPLAY Buffer WITH NO ADVANCING END-IF END-IF *      Check if key is waiting in keyboard buffer. CALL X&quot;D9&quot; USING KeyStatus *      If key is waiting, read it and write it to the pipe. IF KeyStatus NOT = 0 THEN CALL X&quot;83&quot; USING Buffer CALL &quot;__DosWrite&quot; USING BY REFERENCE BytesWritten, BY VALUE    BytesToWrite, BY REFERENCE Buffer, BY VALUE    Handle END-IF END-PERFORM. *   Close the pipe instance and end the program. CALL &quot;__DosClose&quot; USING BY VALUE Handle. DISPLAY &quot; &quot; DISPLAY &quot;The pipe has been closed.&quot; STOP RUN. Copyright Microsoft Corporation 1992.