Problem with receiving MSMQ message body

KaitsuKaitsu Member Posts: 22
Sending MSMQ messages works just fine with 'Microsoft Message Queue 3.0 Object Library' automation object but there are problems with the body of received message which always seems to be empty. Neither DOMDocument type body nor text type body does not seem to work. I am using the following code to receive the message:

varTransaction := 0;
varWantDestinationQueue := 0;
varWantBody := 1;
varReceiveTimeOut := 30000;
varWantConnectorType := 0;

ReceiveMessage := ReceiveQueue.Receive(
varTransaction,
varWantDestinationQueue,
varWantBody,
varReceiveTimeOut,
varWantConnectorType);

Comments

  • DenSterDenSter Member Posts: 8,307
    your ReceiveMessage object is empty? Have you verified that the message has a value in the queue itself? You're looking for the ReceiveMessage.Body object, which is a variant. Load the body into an MSDOM object (MSDOM.LoadXML(FORMAT(Message.Body))) should work.
  • KaitsuKaitsu Member Posts: 22
    I have verified that there is value in message by enabling queue journal.
    When reading MSDOM object (I am using 'Microsoft XML, v3.0'.DOMDocument Automation variable) with FORMAT(Message.Body)) gives the following error:
    "This data type is not supported by C/SIDE. You can access data from any of the following data types VT_VOID, VT_I2,..."
    Reading text variant with FORMAT(Message.Body)) just gives an empty string.
  • DenSterDenSter Member Posts: 8,307
    I tried to compress the code, assuming that the body is a text type variant. Here's a more complete code snippet:
    CREATE(MSDOM);
    
    MyVariant := MyMessage.Body;
    IF MyVariant.ISTEXT THEN
      // use LoadXML when you have a string to load
      MSDOM.loadXML(MyVariant)
    ELSE
      // use Load if you have another object type to load
      MSDOM.load(MyVariant);
    
    CLEAR(MSDOM);
    
    MSDOM is 'Microsoft XML, v3.0'.DOMDocument30
    MyMessage is 'Microsoft Message Queue 3.0 Object Library'.MSMQMessage

    If this doesn't work then I'd suggest you revise the code that sends the message to make sure the body of the message body contains either a string or an MSDOM object.
  • KaitsuKaitsu Member Posts: 22
    It just does not work. :(
    If body is text (In computer management / message queuing it looks like this: 54 00 45 00 53 00 54 00 T.E.S.T.) I don't get any errors. After loadXML(MyVariant) I try MSDOM.Save but I only get empty xml file.
    If body is xml object like this
    (
    11 0F D9 F6 73 9C D3 11 B3 ..ÙösœÓ.³
    2E 00 C0 4F 99 0B B4 3C 78 ..ÀO&#153;.´<x
    6D 6C 3E 3C 6F 75 74 3E 3C ml><out><
    6C 6F 63 61 74 69 6F 6E 3E location>
    3C 78 63 6F 6F 72 64 3E 33 <xcoord>3
    33 32 38 34 33 33 3C 2F 78 328433</x
    63 6F 6F 72 64 3E 3C 79 63 coord><yc
    6F 6F 72 64 3E 36 38 32 35 oord>6825
    30 35 31 3C 2F 79 63 6F 6F 051</ycoo
    72 64 3E 3C 2F 6C 6F 63 61 rd></loca
    74 69 6F 6E 3E 3C 2F 6F 75 tion></ou
    74 3E 3C 2F 78 6D 6C 3E 0D t></xml>.
    0A) .
    I get the following error with load:
    "Could not invoke the member load.... The number of elements provided is different from the number of arguments accepted by the method or property".
  • DenSterDenSter Member Posts: 8,307
    It might error out at the "ÙösœÓ.³" part, which does not look like XML to me. Do you have any control over what is sent into the queue? Maybe you can try to send the XML as a string.

    The dots between the letters is because the text string is encoded as a double byte character stream, and the LoadXML method should be able to handle that.
  • KaitsuKaitsu Member Posts: 22
    Messages are sent using C++ program and MSXML::IXMLDOMDocumentPtr and IMSMQMessagePtr
    Actually it looks like MyVariant is always empty no matter what I send to the queue.

    I can send xml as double byte text but MyVariant is still empty.
  • DenSterDenSter Member Posts: 8,307
    That program must use the same object type, or it will fail. I'm not a C++ programmer at all, but the 'Microsoft XML, v3.0'.DOMDocument30 should be available in there as well. I would probably take this question into a C++ forum and ask what type to use.
  • KaitsuKaitsu Member Posts: 22
    It would be enough if just simple string came through. No need for xml really. But either body of the message is empty or assigning it to variant fails.
  • DenSterDenSter Member Posts: 8,307
    Just as an example:
    If you set a SQL Server field to data type text, Navision will not recognize it. You try to assign a SQL Server type text to a text field in NAV, it will error out.

    I know there are many types of strings in C++, and you're going to have to try each one of them until you find the one that NAV recognizes as a text variable. Then, you can put XML inside the string and load it into an MSDOM object using the LoadXML method.
  • KaitsuKaitsu Member Posts: 22
    Even when I send a string from Navision and then read it the body is empty. I am using the following code:
    IF ISCLEAR(SendQueueInfo) THEN
      CREATE(SendQueueInfo);
    
    IF ISCLEAR(ReceiveQueueInfo) THEN
      CREATE(ReceiveQueueInfo);
    
    IF ISCLEAR(DOMDocument) THEN
      CREATE(DOMDocument);
    
    ReceiveQueueInfo.PathName := '.\PRIVATE$\queue';
    ReceiveQueueInfo.Create();
    ReceiveQueue := ReceiveQueueInfo.Open(1, 0); // 1 = Receive access, 0 = Deny none
    
    SendQueueInfo.PathName := '.\PRIVATE$\queue';
    SendQueue := SendQueueInfo.Open(2, 0); // 2 = Send access, 0 = Deny none
    
    IF ISCLEAR(SendMessage) THEN
        CREATE(SendMessage);
    
    // Send
    SendMessage.Body := 'test';
    SendMessage.ResponseQueueInfo := ReceiveQueueInfo;
    SendMessage.Send(SendQueue);
    
    // Receive
    varTransaction := 0;
    varWantDestinationQueue := 0;
    varWantBody := 1;
    varReceiveTimeOut := 30000;
    varWantConnectorType := 0;
    
    ReceiveMessage := ReceiveQueue.Receive(
      varTransaction, 
      varWantDestinationQueue, 
      varWantBody,
      varReceiveTimeOut, 
      varWantConnectorType);
    
    MyVariant := ReceiveMessage.Body;
    
    IF MyVariant.ISTEXT THEN BEGIN
      MESSAGE(FORMAT(ReceiveMessage.Body));
      MESSAGE(FORMAT(MyVariant));
    END
    ELSE
      MESSAGE('Not text');
    
    ReceiveQueueInfo.Delete();
    
  • KaitsuKaitsu Member Posts: 22
    Oops... The problem was with the Receive function parameters. They were like this:

    varTransaction := 0;
    varWantDestinationQueue := 0;
    varWantBody := 1;
    varWantConnectorType := 0;
    [-X

    when they should have been like this:

    varTransaction := false;
    varWantDestinationQueue := false;
    varWantBody := true;
    varWantConnectorType := false;

    Thanks for the help anyway. It works now. \:D/
  • DenSterDenSter Member Posts: 8,307
    You know I didn't even look at those :oops:

    Good job making that work.
  • KaitsuKaitsu Member Posts: 22
    There is one more problem with receiving messages. You need to verify that received message is the reply for the query you send. It should work like this:

    REPEAT
    ReceiveMessage := ReceiveQueue.Receive(
    varTransaction,
    varWantDestinationQueue,
    varWantBody,
    varReceiveTimeOut,
    varWantConnectorType);
    UNTIL ReceiveMessage.CorrelationId = SendMessage.Id;

    But code above does not work because Ids that are variants cannot be compared with = operator. Is there a way to compare them in Navision? (FORMAT() does not work.)
  • DenSterDenSter Member Posts: 8,307
    Put the value into a Variant type variable and use the functions. for instance:
    IF MyVariant.ISTEXT THEN
      MyText := MyVariant;
    
    You might be able to do something like:
    CASE TRUE OF
      MyVariant.ISTEXT: MyText := MyVariant;
      MyVariant.ISINTEGER: MyInteger := MyVariant;
    ELSE
      ERROR('incompatible data type');
    END;
    
    I haven't tested the second code snippet, but that's how I'd start out.
  • KaitsuKaitsu Member Posts: 22
    The problem is that it is neither text nor integer type.
  • DenSterDenSter Member Posts: 8,307
    Well text and integers are not the only datatypes supported in a Variant variable. It was a code snippet, an example to look at and expand on yourself. Open your object browser and see what other types are available.
  • KaitsuKaitsu Member Posts: 22
    I mean none of the ISTEXT, ISINTEGER, ISAUTOMATION etc. functions available returns true.
  • DenSterDenSter Member Posts: 8,307
    Then like I said before, you will have to find a data type to use in the C++ code that is compatible with a Navision data type.
  • KaitsuKaitsu Member Posts: 22
    Message id is given internally in 'Microsoft Message Queue 3.0 Object Library'.MSMQMessage object and i just heard it is of type array of bytes.

    So i guess 'correlation id' must be handled somehow within the xml object in the message body then...
Sign In or Register to comment.