SAS 9.1.3 Integration Technologies » Developer's Guide


MSMQ Functional Interface
Writing MSMQ Applications
MSMQ Code Samples
MSMQ CALL Routines
MSMQCREATEQUEUE
MSMQDELETEQUEUE
MSMQOPENQUEUE
MSMQCLOSEQUEUE
MSMQPATHTOFORMAT
MSMQINSTTOFORMAT
MSMQHNDLTOFORMAT
MSMQSENDMSG
MSMQRECEIVEMSG
MSMQCREATECURSOR
MSMQCLOSECURSOR
MSMQBEGINTRANS
MSMQCOMMITTRANS
MSMQABORTTRANS
MSMQRELEASETRANS
MSMQLOCATE
MSMQGETQPROP
MSMQSETQPROP
MSMQGETQSEC
MSMQSETQSEC
MSMQGETSCONTEXT
MSMQFREESCONTEXT
MSMQMAP
MSMQSETPARMS
MSMQGETPARMS
MSMQFREE
Application Messaging

MSMQ Code Samples

This section provides examples of using the MSMQ interface with DATA step code to illustrate the semantics of sending a message to a queue and receiving the same message from the queue.

Additional DATA step code examples are provided to show how to send and receive text files, as well as send and receive binary files.

Please note that when a SAS DATA step ends, all resources consumed by this DATA step are automatically freed. That is, all internal SAS handles are automatically freed. When using the SAS Macro Language to interface with MSMQ, care should be taken to ensure that all resources are freed programmatically. Unlike the DATA step, resources consumed by the SAS Macro Language are never implicitly freed during SAS execution.

DATA Step Coding Examples

Sending a Message to a Queue

This example sends a message to a queue. Note that it assumes that the queue "respq" has been created prior to this example.

   data _null_;
   length rc 8;
   length msg $ 200;
   length Qid hQueue transobj 8;
   length msgid $ 40;
   length hData hMap 8;
   length parm1 parm2 parm3 8;
   length parm4 $ 50;

   hQueue=0;
   hMap=0;
   hData=0;

   put '-------- Obtain formatname from pathname ------';
   Qid=0;
   rc=0;
   call msmqpathtoformat("pcpad\testq", Qid, rc);
   if rc ^= 0 then do;
      if rc = input('03000EC0'x, ib4.) then do;
         /* C00E0003 - MSMQ QUEUE_NOT_FOUND error */
         /* so create it...                       */
         put 'Queue does not exist so creating it...';
         call msmqcreatequeue(Qid, rc, "PATHNAME,LABEL", 
            "pcpad\testq", "Test Queue");
         if rc ^= 0 then do;
            put 'MSMQCreateQueue: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;
         else put 'MSMQCreateQueue: succeeded';
      end;
      else do;
         put 'MSMQPathToFormat: failed';
         msg = sysmsg();
         put msg;
         goto exit;
      end;
   end;
   else put 'MSMQPathToFormat: succeeded';


   put '----------- Open queue for sending -----------';
   call msmqopenqueue(Qid, "SEND", "SHARE", hQueue, rc);
   if rc ^= 0 then do;
      put 'MSMQOpenQueue: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;
   else put 'MSMQOpenQueue: succeeded';


   put '----------- Generate map descriptor -----------';
   /* data will not be aligned */
   desc1="SHORT";
   desc2="LONG";
   desc3="DOUBLE";
   desc4="CHAR,,50"; /* blank pad to 50 bytes */
   call msmqmap(hMap, rc, desc1, desc2, desc3, desc4);
   if rc ^= 0 then do;
      put 'MSMQMap: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;
   else put 'MSMQMap: succeeded';


   put '--- Generate data descriptor - actual data ----';
   parm1=100;
   parm2=9999;
   parm3=9999.9999;
   parm4="This is a test.";
   call msmqsetparms(hData, hMap, rc, parm1, 
      parm2, parm3, parm4);
   if rc ^= 0 then do;
      put 'MSMQSetParms: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;
   else put 'MSMQSetParms: succeeded';


   put '------------ Send message to queue ------------';
   transobj=0;
   msgid="";
   call msmqsendmsg(hQueue, hData, transobj, rc,
      "BODY_TYPE,CORRELATIONID,LABEL,MSGID,
      PRIV_LEVEL,RESP_QUEUE",
      999, "0102030405060708090A0B0C0D0E0F1011121314",
      "Secret test message", msgid, 
         "PRIVATE", "pcpad\respq");
   if rc ^= 0 then do;
      put 'MSMQSendMsg: failed';
      msg = sysmsg();
      put msg;
   end;
   else do;
      put 'MSMQSendMsg: succeeded';

      /* display MSMQ-generated MSGID */
      put 'msgid is ' msgid;
   end;


   exit:
   if hQueue ^= 0 then do;
      put '----------------- Close queue ---------------';
      call msmqclosequeue(hQueue, rc);
      if rc ^= 0 then do;
         put 'MSMQCloseQueue: failed';
         msg = sysmsg();
         put msg;
      end;
      else put 'MSMQCloseQueue: succeeded';
   end;

   if Qid ^= 0 then do;
      call msmqfree(Qid);
      put 'Qid handle freed';
   end;

   if hMap ^= 0 then do;
      call msmqfree(hMap);
      put 'Map descriptor handle freed';
   end;

   if hData ^= 0 then do;
      call msmqfree(hData);
      put 'Data descriptor handle freed';
   end;


run;

Receiving a Message From a Queue

This example receives a message from a queue.

   data _null_;
   length rc 8;
   length msg $ 200;
   length Qid hQueue transobj 8;
   length hMap 8;
   length arrivet auth size sentt 8;
   length correlid msgid $ 40;
   length label $ 80;
   length parm1 parm2 parm3 8;
   length parm4 $ 50;
   length hRespQ 8;
   length respq $ 80;
   length respQid 8;

   hQueue=0;
   hMap=0;
   hRespQ=0;
   respQid=0;

   put '-------- Obtain formatname from pathname ------';
   Qid=0;
   rc=0;
   call msmqpathtoformat("pcpad\testq", Qid, rc);
   if rc ^= 0 then do;
      put 'MSMQPathToFormat: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;
   else put 'MSMQPathToFormat: succeeded';


   put '----------- Open queue for receiving ---------';
   call msmqopenqueue(Qid, "RECEIVE", "SHARE", hQueue, rc);
   if rc ^= 0 then do;
      put 'MSMQOpenQueue: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;
   else put 'MSMQOpenQueue: succeeded';


   put '----------Receive message from queue ---------';
   transobj=0;
   hCursor=0;
   call msmqreceivemsg(hQueue, 0, "RECEIVE", hCursor, 
      transobj, rc, "ARRIVEDTIME,AUTHENTICATED,BODY_SIZE,
      CORRELATIONID,LABEL,MSGID,RESP_QUEUE,SENTTIME",
      arrivet, auth, size, correlid, label, msgid, 
      respq, sentt);
   if rc ^= 0 then do;
      put 'MSMQReceiveMsg: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;
   else do;
      put 'MSMQReceiveMsg: succeeded';
      /* convert MSMQ arrived time to 
         SAS datetime format */
      arrivet = 
         arrivet + 10*365*24*3600 + 3*24*3600 - 5*3600;
      put 'arrived time is' arrivet datetime.;
      if auth = 1 then put 'message was authenticated';
      else put 'message was not authenticated';
      put 'message body size is ' size;
      put 'correlation id is ' correlid;
      put 'label is ' label;
      put 'msg id is ' msgid;
      put 'resp_queue Qid handle is ' respq;
      /* convert MSMQ sent time to SAS datetime format */
      sentt = sentt + 10*365*24*3600 + 3*24*3600 - 5*3600;
      put 'sent time was' sentt datetime.;
   end;


   if size ^= 0 then do;
      put '---------- Generate map descriptor ----------';
      desc1="SHORT";
      desc2="LONG";
      desc3="DOUBLE";
      desc4="CHAR,,50";
      call msmqmap(hMap, rc, desc1, desc2, desc3, desc4);
      if rc ^= 0 then do;
      put 'MSMQMap: failed';
         msg = sysmsg();
         put msg;
         goto exit;
      end;
      else put 'MSMQMap: succeeded';

      call msmqgetparms(hMap, rc, parm1, 
         parm2, parm3, parm4);
      if rc ^= 0 then do;
         put 'MSMQGetParms: failed';
         msg = sysmsg();
         put msg;
         goto exit;
      end;
      else do;
         put 'MSMQGetParms: succeeded';
         put 'parm1 = ' parm1;
         put 'parm2 = ' parm2;
         put 'parm3 = ' parm3;
         put 'parm4 = ' parm4;
      end;
   end;
   else put 'No data was associated with the message';


   /* post a reply to the response queue if available */
   if respq ^= "" then do;
      call msmqpathtoformat(respq, respQid, rc);
      if rc ^= 0 then do;
         put 'MSMQPathToFormat: failed to 
            open response queue';
         msg = sysmsg();
         goto exit;
      end;

      call msmqopenqueue(respQid, "SEND", 
         "SHARE", hRespQ, rc);
      if rc ^= 0 then do;
         put 'MSMQOpenQueue: failed to 
            open response queue';
         msg = sysmsg();
         put msg;
         goto exit;
      end;

      hMap=0;
      call msmqsetparms(hData, hMap, rc, 
         "Message received OK");
      if rc ^= 0 then do;
         put 'MSMQSetParms: failed to 
            send response message';
         msg = sysmsg();
         put msg;
         goto exit;
      end;

      transobj=0;
      call msmqsendmsg(hRespQ, hData, transobj, rc);
      if rc ^= 0 then do;
         put 'MSMQSendMsg: failed to 
            send response message';
         msg = sysmsg();
         put msg;
      end;
      else put 'reply sent to the response queue';
   end;


   exit:
   if hQueue ^= 0 then do;
      put '----------------- Close queue ---------------';
      call msmqclosequeue(hQueue, rc);
      if rc ^= 0 then do;
         put 'MSMQCloseQueue: failed';
         msg = sysmsg();
         put msg;
      end;
      else put 'MSMQCloseQueue: succeeded';
   end;

   if hRespQ ^= 0 then do;
      put '------------ Close Response Queue -----------';
      call msmqclosequeue(hRespQ, rc);
      if rc ^= 0 then do;
         put 'MSMQCloseQueue: failed to 
            close response queue';
         msg = sysmsg();
         put msg;
      end;
      else put 'MSMQCloseQueue: succeeded 
         to close response queue';
   end;

   if Qid ^= 0 then do;
      call msmqfree(Qid);
      put 'Qid handle freed';
   end;

   if respQid ^= 0 then do;
      call msmqfree(respQid);
      put 'respQid handle freed';
   end;

   if hMap ^= 0 then do;
      call msmqfree(hMap);
      put 'Map descriptor handle freed';
   end;


   run;

Text File Processing Example

This example shows how to put a text file on a queue.

   data _null_;
   length rc 8;
   length msg $ 200;
   length Qid hQueue hmap 8;
   length appspec 8;
   length corrid $ 40;
   length record $ 256;
   length seqno 8 seqstr $ 4;

   /* send this file to the queue */
   infile 'd:\test.txt' length=reclen end=eof;

   put '--------- Obtain Formatname from Pathname -------';
   call msmqpathtoformat(".\testq", Qid, rc);
   if( rc ) then do;
      if( rc = input('03000EC0'x,ib4.) ) then do;
         put 'Queue does not exist so create it...';
         call msmqcreatequeue(Qid, rc, "pathname,label", 
            ".\testq", "test queue");
         if( rc ) then do;
            put 'MSMQCreateQueue: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;
      end;
      else do;
         put 'MSMQPathToFormat: failed';
         msg = sysmsg();
         put msg;
         goto exit;
      end;
   end;

   put '------------------ Open Queue ------------------';
   call msmqopenqueue(Qid, "SEND", "SHARE", hQueue, rc);
   if( rc ) then do;
      put 'MSMQOpenQueue: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   put '----------- Generate map descriptor -----------';
   /* longest record in file is 255 bytes+1 length byte... */
   /* therefore all messages on the queue pertaining to    */
   /* this file will be blank-padded for 256 bytes...      */
   call msmqmap(hmap, rc, "char,,256");
   if rc ^= 0 then do;
      put 'MSMQMap: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   /* designate that messages belong to a text file */
   appspec=100000;

   /* all of these messages will have 
      the same correlationid+seqno */
   corrid="46696c65212121"; /* File!!! */

   seqno = 0;


   do until(eof);
      input @;
      input record $varying256. reclen;

      call msmqsetparms(hdata, hmap, rc, record);
      if( rc ) then do;
         put 'MSMQSetParms: failed';
         msg = sysmsg();
         put msg;
         goto exit;
      end;

      /* add sequence # to correlationid */
      seqstr = put(seqno, hex4.);
      substr(corrid,15,4) = seqstr;
      seqno = seqno+1;

      put '--- Send message to queue ----';
      call msmqsendmsg(hQueue, hdata, 0, rc, 
         "appspecific,correlationid", appspec, corrid);
      if( rc ) then do;
         put 'MSMQSendMsg: failed';
         msg = sysmsg();
         put msg;
         goto exit;
      end;

      /* free data */
      call msmqfree(hdata);
   end;

   exit:
   if( hQueue ) then do;
      call msmqclosequeue(hQueue, rc);
      if( rc ) then do;
         put 'MSMQCloseQueue: failed';
         msg = sysmsg();
         put msg;
      end;
   end;

   if( Qid ) then
      call msmqfree(Qid);

   if( hmap ) then
      call msmqfree(hmap);

   stop;

   run;

Getting a Text File From a Queue

This example shows how to receive the first text file on a queue. The appspecific parameter is equal to 100000.

   filename output 'd:\testdup.txt';

   data _null_;
   length rc 8;
   length msg $ 200;
   length Qid hQueue hmap hCursor hCursor2 8;
   length corrid corrid2 filecorrid $ 40;
   length appspec 8;
   length action action2 $ 12;
   length record $ 256;
   length seqno 8;


   fileid = fopen('output', 'o', 256, 'v');
   if( fileid = 0 ) then do;
      put 'Error opening output file...';
      goto exit;
   end;

   put '--------- Obtain Formatname from Pathname -------';
   call msmqpathtoformat(".\testq", Qid, rc);
   if( rc ) then do;
      put 'MSMQPathToFormat: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   put '------------------ Open Queue ------------------';
   call msmqopenqueue(Qid, "RECEIVE", "SHARE", hQueue, rc);
   if( rc ) then do;
      put 'MSMQOpenQueue: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   call msmqcreatecursor(hQueue, hCursor, rc);
   if( rc ) then do;
      put 'MSMQCreateCursor failed';
      msg = sysmsg();
      put msg;
   end;

   /* peek first to see if belongs to the file you want */
   action="PEEK_CURRENT";

   seqno=0;

   recv:
   call msmqreceivemsg(hQueue, 0, action, hCursor, 0, rc,
      "APPSPECIFIC,CORRELATIONID", appspec, corrid);
   if( rc ) then do;
      if( rc = input('1B000EC0'x,ib4.) ) then do;
         put 'reached end of queue';
         goto exit;
      end;

      put 'MSMQReceiveMsg: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   /* default action */
   action="PEEK_NEXT";

   if( appspec = 100000 ) then do;
      /* file processing... */
      outofseq=0;

      if( filecorrid = "" ) then do;
         /* file begins at this message */

         /* write all correlating messages to this file */
         filecorrid = substr(corrid,1,14);

         put '--------- Generate map descriptor ---------';
         /* all file messages were sent to the queue as 
            256 bytes blank-padded */
         call msmqmap(hmap, rc, "char,,256");
         if( rc ) then do;
            put 'MSMQMap: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;
      end;

      /* make sure message belongs to this file */
      if( substr(corrid,1,14) = filecorrid ) then do;
         if( seqno ^= input(substr(corrid,15,4), 
               hex4.) ) then do;
            /* this message is out of sequence 
               so search for it */
            outofseq=1;

            call msmqcreatecursor(hQueue, hCursor2, rc);
            if( rc ) then do;
               put 'MSMQCreateCursor failed';
               msg = sysmsg();
               put msg;
            end;

            action2="PEEK_CURRENT";
   peeknxt:
            call msmqreceivemsg(hQueue, 0, action2, 
               hCursor2, 0, rc, "CORRELATIONID", corrid2);
            if( rc ) then do;
               if( rc = input('1B000EC0'x,ib4.) ) then do;
                  put 'Error: reached end of queue while 
                     searching for out-of-sequence msg';
                  goto exit;
               end;

               put 'MSMQReceiveMsg: failed';
               msg = sysmsg();
               put msg;
               goto exit;
            end;

            if( seqno ^= input(substr(corrid2,15,4),
               hex4.) ) then do;
               action2="PEEK_NEXT";
               goto peeknxt;
            end;
         end;

         /* increment sequence number for next 
            expected message */
         seqno=seqno+1;

         /* retrieve record from internal buffer */
         call msmqgetparms(hmap, rc, record);
         if( rc ) then do;
            put 'MSMQGetParms: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;

         put 'write record to file';
         rc = fput(fileid, record);
         if( rc ) then do;
            put 'Error writing to output file buffer...';
            goto exit;
         end;

         /* flush it to disk */
         rc = fwrite(fileid);
         if( rc ) then do;
            put 'Error writing to output file...';
            goto exit;
         end;


         /* now remove it from the queue... 
            don't care about receiving body */
         body=0;
         if( outofseq ) then do;
            call msmqreceivemsg(hQueue, 0, "RECEIVE", 
               hCursor2, 0, rc, "body", body);

            /* close this cursor */
            call msmqclosecursor(hCursor2, rc);
         end;
         else do;
            call msmqreceivemsg(hQueue, 0, "RECEIVE", 
               hCursor, 0, rc, "body", body);
         end;

         /* we are now pointing at the next message */
         action="PEEK_CURRENT";
      end;
   end;

   /* finish retrieving all messages belonging 
      to this file */
   goto recv;


   exit:
   if( hQueue ) then do;
      call msmqclosequeue(hQueue, rc);
      if( rc ) then do;
         put 'MSMQCloseQueue: failed';
         msg = sysmsg();
         put msg;
      end;
   end;

   if( Qid ) then
      call msmqfree(Qid);

   if( hmap ) then
      call msmqfree(hmap);

   /* close file */
   rc = fclose(fileid);
   if( rc ) then put 'Error closing output file';

   run;

Binary File Processing Example

This example shows how to put a binary file on a queue. It assumes that the queue named "adminq" has been created prior to this.

   data _null_;
   length rc 8;
   length msg $ 200;
   length Qid hQueue hmap 8;
   length appspec 8;
   length corrid $ 40;
   length msgbuf $ 256;
   length seqno 8 seqstr $ 4;


   /* read in as a stream of bytes */
   infile 'd:\test.exe' recfm=f lrecl=1 end=eof;

   put '--------- Obtain Formatname from Pathname -------';
   call msmqpathtoformat(".\testq", Qid, rc);
   if( rc ) then do;
      if( rc = input('03000EC0'x,ib4.) ) then do;
         put 'Queue does not exist so create it';
         call msmqcreatequeue(Qid, rc, "pathname,label", 
            ".\testq", "test queue:");
         if( rc ) then do;
            put 'MSMQCreateQueue: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;
      end;
      else do;
         put 'MSMQPathToFormat: failed';
         msg = sysmsg();
         put msg;
         goto exit;
      end;
   end;

   put '------------------ Open Queue ------------------';
   call msmqopenqueue(Qid, "SEND", "SHARE", hQueue, rc);
   if( rc ) then do;
      put 'MSMQOpenQueue: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   put '----------- Generate map descriptor -----------';
   /* send 256 byte messages to the queue */
   call msmqmap(hmap, rc, "char,,256");
   if( rc ) then do;
      put 'MSMQMap: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   /* designate messages belong to a binary file */
   appspec=100001;

   /* all of these messages will have the 
      same correlationid */
   corrid="42696e46696c65212121"; /* BinFile!!! */

   seqno = 0;

   i=1;
   do until(eof);
      /* read a byte at a time */
      input x $char1.;
      i+1;
      substr(msgbuf,i,1) = x;
      if i = 256 or eof then do;
         /* set length of this record embedded 
            as first byte of message */
         substr(msgbuf,1,1) = put(i-1,pib1.);

         call msmqsetparms(hdata, hmap, rc, msgbuf);
         if( rc ) then do;
            put 'MSMQSetParms: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;

         /* add sequence # to correlationid */
         seqstr = put(seqno, hex4.);
         substr(corrid,21,4) = seqstr;
         seqno = seqno + 1;

         put '--- Send message to queue ----';
         call msmqsendmsg(hQueue, hdata, 0, rc, 
            "appspecific,correlationid,acknowledge,
            admin_queue", appspec, corrid, 
            "nack_reach_queue", ".\adminq");
         if( rc ) then do;
            put 'MSMQSendMsg: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;

         /* free data */
         call msmqfree(hdata);

         /* reset message buffer entities */
         i=1;
         msgbuf="";

      end;
   end;


   exit:
   if( hQueue ) then do;
      call msmqclosequeue(hQueue, rc);
      if( rc ) then do;
         put 'MSMQCloseQueue: failed';
         msg = sysmsg();
         put msg;
      end;
   end;

   if( Qid ) then
      call msmqfree(Qid);

   if( hmap ) then
      call msmqfree(hmap);

   stop;

   run;

Getting a Binary File From a Queue

This example shows how to receive the first binary file on a queue.

   filename output 'd:\testdup.exe';

   data _null_;
   length rc 8;
   length msg $ 200;
   length Qid hQueue hmap hCursor hCursor2 8;
   length corrid corrid2 filecorrid $ 40;
   length appspec 8;
   length action action2 $ 12;
   length msgbuf stream $ 256;
   length len 8;
   length seqno 8;

   fileid = fopen('output', 'o', 0, 'b');
   if( fileid = 0 ) then do;
      put 'Error opening output file...';
      goto exit;
   end;

   put '--------- Obtain Formatname from Pathname -------';
   call msmqpathtoformat(".\testq", Qid, rc);
   if( rc ) then do;
      put 'MSMQPathToFormat: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   put '------------------ Open Queue ------------------';
   call msmqopenqueue(Qid, "RECEIVE", "SHARE", hQueue, rc);
   if( rc ) then do;
      put 'MSMQOpenQueue: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   call msmqcreatecursor(hQueue, hCursor, rc);
   if( rc ) then do;
      put 'MSMQCreateCursor failed';
      msg = sysmsg();
      put msg;
   end;

   /* peek first to see if belongs to the file you want */
   action="PEEK_CURRENT";

   seqno=0;

   recv:
   call msmqreceivemsg(hQueue, 0, action, hCursor, 0, rc,
      "APPSPECIFIC,CORRELATIONID", appspec, corrid);
   if( rc ) then do;
   if( rc = input('1B000EC0'x,ib4.) ) then do;
      put 'reached end of queue';
      goto exit;
   end;

      put 'MSMQReceiveMsg: failed';
      msg = sysmsg();
      put msg;
      goto exit;
   end;

   /* default action */
   action="PEEK_NEXT";

   if( appspec = 100001 ) then do;
      /* file processing */
      outofseq=0;

      if( filecorrid = "" ) then do;
         /* file begins at this message */

         /* write all correlating messages to this file */
         filecorrid = substr(corrid,1,20);

         put '--------- Generate map descriptor ---------';
         /* all file messages were sent to the queue as 
            256 bytes blank-padded */
         call msmqmap(hmap, rc, "char,,256");
         if( rc ) then do;
            put 'MSMQMap: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;
      end;

      /* make sure message belongs to this file */
      if( substr(corrid,1,20) = filecorrid ) then do;
         if( seqno ^= input(substr(corrid,21,4), hex4.) ) 
            then do;
            /* this message is out of sequence 
               so search for it */
            outofseq=1;

            call msmqcreatecursor(hQueue, hCursor2, rc);
            if( rc ) then do;
               put 'MSMQCreateCursor failed';
               msg = sysmsg();
               put msg;
               goto exit;
            end;

            action2="PEEK_CURRENT";
   peeknxt:
            call msmqreceivemsg(hQueue, 0, action2, 
               hCursor2, 0, rc, "CORRELATIONID", corrid2);
            if( rc ) then do;
               if( rc = input('1B000EC0'x, ib4.) ) then do;
                  put 'Error: reached end of queue while 
                     searching for out-of-sequence msg';
                  goto exit;
               end;

               put 'MSMQReceiveMsg: failed';
               msg = sysmsg();
               put msg;
               goto exit;
            end;

            if( seqno ^= input(substr(corrid2,21,4), hex4.) )
               then do;
               action2="PEEK_NEXT";
               goto peeknxt;
            end;
         end;

         /* increment sequence number for 
            next expected message */
         seqno=seqno+1;

         /* retrieve record from internal buffer */
         call msmqgetparms(hmap, rc, msgbuf);
         if( rc ) then do;
            put 'MSMQGetParms: failed';
            msg = sysmsg();
            put msg;
            goto exit;
         end;

         /* length of this stream is embedded 
            as 1st byte in msg */
         len = input(substr(msgbuf,1,1), pib1.);
         stream = substr(msgbuf,2);

         put 'write stream to file';
         rc = fput(fileid, substr(stream,1,len));
         if( rc ) then do;
            put 'Error writing to output file buffer...';
            goto exit;
         end;

         /* flush it to disk */
         rc = fwrite(fileid);
         if( rc ) then do;
            put 'Error writing to output file...';
            goto exit;
         end;


         /* now remove it from the queue... 
            don't care about receiving body */
         body=0;
         if( outofseq ) then do;
            call msmqreceivemsg(hQueue, 0, "RECEIVE", 
               hCursor2, 0, rc, "body", body);

            /* close this cursor */
            call msmqclosecursor(hCursor2, rc);
         end;
         else do;
            call msmqreceivemsg(hQueue, 0, "RECEIVE", 
               hCursor, 0, rc, "body", body);
         end;

         /* we are now pointing at the next message */
         action="PEEK_CURRENT";
      end;
   end;

   /* finish retrieving all messages belonging 
      to this file */
   goto recv;

   exit:
   if( hQueue ) then do;
      call msmqclosequeue(hQueue, rc);
      if( rc ) then do;
         put 'MSMQCloseQueue: failed';
         msg = sysmsg();
         put msg;
      end;
   end;

   if( Qid ) then
      call msmqfree(Qid);

   if( hmap ) then
      call msmqfree(hmap);

   /* close file */
   rc = fclose(fileid);
   if( rc ) then put 'Error closing output file';

   run;