Handling Errors in Queued Components

Occasionally, a situation occurs in which a message cannot be successfully delivered to its intended destination, usually due to a problem with the system or configuration. For example, the message might be directed to a queue that does not exist or the destination queue might not be in a state to receive. The message mover is a tool that moves all failed Message Queuing messages from one queue to another so that they can be retried. The message mover utility is an Automation object that can be invoked with a VBScript.

Components Services Administrative Tool

Does not apply.

Visual Basic

The following sample code shows how to create a MessageMover object, set the required properties, and initiate the transfer. To use it from Visual Basic, add a reference to the COM+ Services Type Library.

Note

To use the MessageMover object, you must have Message Queuing installed on your computer and the application specified by AppName must have queuing enabled. For information about installing Message Queuing, see Help and Support on the Start menu.

 

Function MyMessageMover( _
  strSource As String, _
  strDest As String _
) As Boolean  ' Return False if any errors occur.

    MyMessageMover = False  ' Initialize the function.
    On Error GoTo My_Error_Handler  ' Initialize error handling.

    Dim lngMovedMessages As Long
    Dim objMessageMover As COMSVCSLib.MessageMover
    Set objMessageMover = CreateObject("QC.MessageMover")
    objMessageMover.SourcePath = strSource
    objMessageMover.DestPath = strDest
    lngMovedMessages = objMessageMover.MoveMessages

    MsgBox lngMovedMessages & " messages moved from " & _
      strSource & " to " & strDest

    MyMessageMover = True  ' Successful end to procedure
    Set objMessageMover = Nothing
    Exit Function

My_Error_Handler:  ' Replace with specific error handling.
    MsgBox "Error # " & Err.Number & " (Hex: " & Hex(Err.Number) _
      & ")" & vbNewLine & Err.Description
    Set objMessageMover = Nothing
    lngMovedMessages = -1
End Function

The following Visual Basic code shows how to call the MyMessageMover function.

Sub Main()
  ' Replace AppName with the name of a COM+ application.
  If Not MyMessageMover(".\private$\AppName_deadqueue", ".\AppName") Then
      MsgBox "MyMessageMover failed."
  End If
End Sub

The source path of the message is the final resting queue. It is the dead queue, which is a private Message Queuing queue and is called AppName_deadqueue. Messages are moved here if the transaction repeatedly aborts when attempted on the fifth retry queue. With the message mover tool, you can move the message back to the first queue, which is called AppName. For more information on retry queues, see Server-Side Errors.

If queue attributes permit, the message mover moves messages transitionally so that messages are not lost or duplicated in the event of failure during the move. The tool preserves all the message properties that can be preserved when moving messages from one queue to another.

If the messages are generated by COM+ Queued Components calls, the message mover utility preserves the original caller's security identifier as it moves messages between queues. If both the destination and source queues are transactional, the whole operation is done transitionally. If either the source or destination queues are not transactional, the operation does not run under a transaction. An unexpected failure (such as a crash) and restart of a non-transactional move could duplicate the message being moved at the time of the failure.

C/C++

The following sample code shows how to create a MessageMover object, set the required properties, and initiate the transfer. The ErrorDescription method is described at Interpreting Error Codes.

Note

To use the MessageMover object, you must have Message Queuing installed on your computer and the application specified by AppName must have queuing enabled. For information about installing Message Queuing, see Help and Support on the Start menu.

 

#include <windows.h>
#include <stdio.h>
#import "C:\WINDOWS\system32\ComSvcs.dll"
#include "ComSvcs.h"
#include "StrSafe.h"  

BOOL MyMessageMover (OLECHAR* szSource, OLECHAR* szDest) {
    IUnknown * pUnknown = NULL;
    IMessageMover * pMover = NULL;
    HRESULT hr = S_OK;
    BSTR bstrSource = NULL;
    BSTR bstrDest = NULL;
    unsigned int uMaxLen = 255;  // Maximum length of szMyApp

try {
    // Test the input strings to make sure they're OK to use.
    hr = StringCchLengthW(szSource, uMaxLen, NULL);
    if (FAILED (hr)) throw(hr);
    hr = StringCchLengthW(szDest, uMaxLen, NULL);
    if (FAILED (hr)) throw(hr);
    
    // Convert the input strings to BSTRs.
    bstrSource = SysAllocString(szSource);
    bstrDest = SysAllocString(szDest);

    // Create a MessageMover object and get its IUnknown.
    hr = CoCreateInstance(CLSID_MessageMover, NULL, 
      CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
    if (FAILED (hr)) throw(hr);    

    // Get the IMessageMover interface.
    hr = pUnknown->QueryInterface(IID_IMessageMover, (void**)&pMover); 
    if (FAILED (hr)) throw(hr);

    // Put the source and destination files.
    hr = pMover->put_SourcePath(bstrSource);
    if (FAILED (hr)) throw(hr);
    hr = pMover->put_DestPath(bstrDest);
    if (FAILED (hr)) throw(hr);

    // Move the messages.
    LONG lCount = -1;
    hr = pMover->MoveMessages(&lCount);
    if (FAILED (hr)) throw(hr);
    printf("%ld messages moved from %S to %S.\n", 
      lCount, bstrSource, bstrDest);

    // Clean up.
    SysFreeString(bstrDest);
    SysFreeString(bstrSource);
    pUnknown->Release();
    pUnknown = NULL;
    pMover->Release();
    pMover = NULL;
    return (TRUE);
}  // try

catch(HRESULT hr) {  // Replace with specific error handling.
    printf("Error # %#x: ", hr);
    ErrorDescription(hr);
    SysFreeString(bstrDest);
    SysFreeString(bstrSource);
    if (NULL != pUnknown) pUnknown->Release();
    pUnknown = NULL;
    if (NULL != pMover) pMover->Release();
    pMover = NULL;
    return (FALSE);
}catch(...) {
    printf("An unexpected exception occurred.\n");
    throw;
}        
}  // MyMessageMover

The following C++ code shows how to call the MyMessageMover function.

#include <windows.h>
#include <stdio.h>

#define _WIN32_DCOM  // To use CoInitializeEx()

void main() 
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (FAILED (hr)) {
        printf("CoInitializeEx failed: Error # %#x\n", hr);
        exit(0);  // Replace with specific error handling.
    }
    if (! MyMessageMover(L".\\private$\\AppName_deadqueue", 
      L".\\AppName"))
        printf("MyMessageMover failed.\n");
    CoUninitialize();
}

The source path of the message is the final resting queue. It is the dead queue, which is a private Message Queuing queue and is called AppName_deadqueue. Messages are moved here if the transaction repeatedly aborts when attempted on the fifth retry queue. With the message mover tool, you can move the message back to the first queue, which is called AppName. For more information on retry queues, see Server-Side Errors.

If queue attributes permit, the message mover moves messages transitionally so that messages are not lost or duplicated in the event of failure during the move. The tool preserves all the message properties that can be preserved when moving messages from one queue to another.

If the messages are generated by COM+ Queued Components calls, the message mover utility preserves the original caller's security identifier as it moves messages between queues. If both the destination and source queues are transactional, the whole operation is done transitionally. If either the source or destination queues are not transactional, the operation does not run under a transaction. An unexpected failure (such as a crash) and restart of a non-transactional move could duplicate the message being moved at the time of the failure.

Remarks

COM+ handles server-side (player) aborts by moving the message that is failing onto a different "final resting" queue, to get it out of the way. The listener and player cannot continually loop on a message that aborts. In many cases, the aborted transaction can be fixed by taking action at the server.

Queued Components Errors