Microsoft KB Archive/64590

How to Use Queues in a Protected Mode COBOL Program

PSS ID Number: Q64590 Article last modified on 11-19-1990

4.00 OS/2

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

More Information: Queues can be used for unidirectional communication between unrelated processes. Their names have the following form: .ext The “.ext” portion is optional. In a typical application, one program (called the owner) will create the queue, and other programs will open the queue. Data flow is in one direction, to the owner, and entails writing records to a shared memory segment. The records can be read in either the order that they arrive, the reverse order, or according to priority. The minimal OS/2 API calls involved in programming queues are the following:

For Other Processes
For more information about calling OS/2 API functions from COBOL, see Chapter 14, “Interfacing with OS/2 API Routines,” in “Microsoft COBOL Professional Development System 4.0: Operating Guide.” For more information about queues 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 queues with COBOL. The best way to see how this works is by running the programs in text windows so that as you enter data from the process that has opened (not created) the queue, you can see it appear in the window of the queue owner. Remember to always run the owner first. Note that COBOL’s default calling convention is the reverse of the convention used by the API functions. COBOL’s calling convention can be overridden using the SPECIAL-NAMES paragraph, but it is not done in these examples. 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 readque; link readque,,,coblib os2; cobol writeque; link writeque,,,coblib os2;

READQUE.CBL
* READQUE.CBL is the owner process. It creates the queue, * allocates the shared memory segment, and polls the queue for * records to read. Characters are displayed as they are read * in. When an escape character is read, the queue is destroyed * and the program ends. IDENTIFICATION DIVISION. PROGRAM-ID. ReadQue. DATA DIVISION. WORKING-STORAGE SECTION. *  DosCreateQueue parameters. *  Handle to the queue. 01 Handle         PIC  9(4)  COMP-5. *  Specifies FIFO reading order. 01 Ordering       PIC  9(4)  COMP-5 VALUE 0. *  Global name of the queue. 01 QueueName      PIC  X(21)        VALUE &quot;\QUEUES\&quot;. *  DosAllocShrSeg parameters. *  Size (in bytes) of the shared memory segment to allocate. 01 SegmentSize    PIC  9(4)  COMP-5 VALUE 512. *  Global name of the shared segment. 01 SegmentName    PIC  X(23)        VALUE &quot;\SHAREMEM\&quot;. *  Receives the segment address. 01 Selector       PIC  9(4)  COMP-5. *  DosReadQueue parameters. *  Receives queue record identification data. 01 RecordData     PIC  9(8)  COMP-5. *  Receives length of queue record. 01 RecordLength   PIC  9(4)  COMP-5. *  Receives address of queue record. 01 RecordAddress  PIC  9(8)  COMP-5. *  Specifies to read the first queue record. 01 RecordId       PIC  9(4)  COMP-5 VALUE 0. *  Specifies to wait until data is ready to be read from queue. 01 WaitFlag       PIC  9(4)  COMP-5 VALUE 0. *  Receives priority of queue record, irrelevant here. 01 Priority       PIC  9(2)  COMP-5. *  This parameter is only relevant if WaitFlag = 1. 01 NullPointer    PIC  9(8)  COMP-5. *  Other variables. *  Receives error code from API call. 01 ErrorCode      PIC S9(4)  COMP-5. *  Used in a call to X&quot;85&quot; to read data from record area. 01 RecordSegment  PIC  9(5). 01 RecordOffset   PIC  9(5). *  Receives the data read from the queue. 01 Byte           PIC X.   PROCEDURE DIVISION. *   Get the name of the queue and shared memory segment and *   terminate both of them with a null character. DISPLAY &quot;Enter the name of the queue:&quot;. ACCEPT QueueName(9:13). INSPECT QueueName REPLACING FIRST &quot; &quot; BY X&quot;00&quot;. MOVE QueueName(9:13) TO SegmentName(11:13). *   Create the queue and allocate the shared memory segment. CALL &quot;__DosCreateQueue&quot; USING BY REFERENCE QueueName, BY VALUE    Ordering, BY REFERENCE Handle. CALL &quot;__DosAllocShrSeg&quot; USING BY REFERENCE Selector, BY REFERENCE SegmentName, BY VALUE    SegmentSize. DISPLAY &quot;The queue has been created.&quot; *   Loop until an escape character is read from the queue. PERFORM UNTIL Byte = X&quot;1B&quot; *      Wait until a record is available, then read it. CALL &quot;__DosReadQueue&quot; USING BY VALUE    NullPointer, BY REFERENCE Priority, BY VALUE    WaitFlag, BY VALUE    RecordId, BY REFERENCE RecordAddress, BY REFERENCE RecordLength, BY REFERENCE RecordData, BY VALUE    Handle RETURNING   ErrorCode *      Report if an error occurred. IF ErrorCode NOT = 0 THEN DISPLAY &quot;ERROR reading queue: &quot; ErrorCode CALL X&quot;E5&quot; STOP RUN ELSE *         Retrieve the segment and offset parts of  *          RecordAddress and read the byte at that address. COMPUTE RecordOffset = RecordAddress / 65536 COMPUTE RecordAddress = RecordAddress * 65536 COMPUTE RecordSegment = RecordAddress / 65536 CALL X&quot;85&quot; USING RecordSegment, RecordOffset, Byte *         If a carriage-return was read, display a space *         instead since in a text window OS/2 will display *         the actual character for ASCII 13, an eighth note. IF Byte = X&quot;0D&quot; THEN DISPLAY &quot; &quot; ELSE DISPLAY Byte WITH NO ADVANCING END-IF END-IF END-PERFORM. *   Close the queue and end. CALL &quot;__DosCloseQueue&quot; USING BY VALUE Handle. DISPLAY &quot; &quot; DISPLAY &quot;The queue has been destroyed.&quot;. STOP RUN.

WRITEQUE.CBL
* WRITEQUE.CBL is the process that writes to the queue created * by READQUE.CBL. It opens the queue, gets the address of the * shared memory segment, and polls the keyboard for input. Keys * are written to the queue as they are read in. When an escape * character is read, the program closes the queue and ends. IDENTIFICATION DIVISION. PROGRAM-ID. WriteQue. DATA DIVISION. WORKING-STORAGE SECTION. *  DosOpenQueue parameters. *  Receives the process ID of the queue owner. 01 PIDofOwner    PIC  9(4)  COMP-5. *  Receives the handle to the queue. 01 Handle        PIC  9(4)  COMP-5. *  Global name of the queue. 01 QueueName     PIC  X(21)        VALUE &quot;\QUEUES\&quot;. *  DosGetShrSeg parameters. *  Global name of the shared memory segment. 01 SegmentName   PIC  X(23)        VALUE &quot;\SHAREMEM\&quot;. *  Receives the segment address. 01 Selector      PIC  9(4)  COMP-5. *  DosWriteQueue parameters. *  Request identification data. 01 RecordData    PIC  9(4)  COMP-5. *  Length of the record to write. 01 RecordLength  PIC  9(4)  COMP-5 VALUE 1. *  Offset of queue record inside shared memory segment. 01 RecordOffset  PIC  9(4)  COMP-5 VALUE 0. *  Queue record priority, irrelevant here. 01 Priority      PIC  9(4)  COMP-5. *  Other variables. *  Buffer area used to read from keyboard and write to queue. 01 KeyChar       PIC  X.  *   Receives error code from API call. 01 ErrorCode     PIC S9(4)  COMP-5. *  Used in call to X&quot;86&quot; to write data to record area. 01 Segment86     PIC  9(5). 01 Offset86      PIC  9(5)         VALUE 0. PROCEDURE DIVISION. *   Loop until a queue is opened successfully. PERFORM UNTIL ErrorCode = 0 *      Get the name of the queue and shared memory segment and *      terminate both of them with a null character. DISPLAY &quot;Enter the name of the queue:&quot; ACCEPT QueueName(9:13) INSPECT QueueName REPLACING FIRST &quot; &quot; BY X&quot;00&quot; *      Attempt to open the queue. CALL &quot;__DosOpenQueue&quot; USING BY REFERENCE QueueName, BY REFERENCE Handle, BY REFERENCE PIDofOwner, RETURNING   ErrorCode *      Report if an error occurred. IF ErrorCode NOT = 0 THEN DISPLAY &quot;ERROR opening queue: &quot; ErrorCode CALL X&quot;E5&quot; END-IF END-PERFORM *   Get the address of the shared memory segment. DISPLAY &quot;The queue has been opened.&quot;. MOVE QueueName(9:13) TO SegmentName(11:13). CALL &quot;__DosGetShrSeg&quot; USING BY REFERENCE Selector, BY REFERENCE SegmentName. MOVE Selector TO Segment86. *   Loop until the user hits an escape character. PERFORM UNTIL KeyChar = X&quot;1B&quot; *      When a key is read in, write it to the shared memory *      segment and then write the record to the queue. CALL X&quot;83&quot; USING KeyChar CALL X&quot;86&quot; USING Segment86, Offset86, KeyChar CALL &quot;__DosWriteQueue&quot; USING BY VALUE Priority, BY VALUE Selector, BY VALUE RecordOffset, BY VALUE RecordLength, BY VALUE RecordData, BY VALUE Handle RETURNING ErrorCode *      Report if an error occurred. IF ErrorCode NOT = 0 THEN DISPLAY &quot;ERROR writing to queue: &quot; ErrorCode CALL X&quot;E5&quot; STOP RUN END-IF END-PERFORM. *   Close the queue and end. CALL &quot;__DosCloseQueue&quot; USING BY VALUE Handle. DISPLAY &quot;The queue has been closed.&quot;. STOP RUN. Copyright Microsoft Corporation 1990.