//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++


Module Name:

    scapi.cxx

Abstract:

    Small client driver


--*/
#include <sc.hxx>
#include <scqman.hxx>
#include <scqueue.hxx>
#include <scpacket.hxx>
#include <scfile.hxx>

#include <mq.h>
#include <mqformat.h>

#include <scapi.h>

#include <scoverio.hxx>
#include <sccomp.hxx>

#include <scsrmp.hxx>
#include <scsman.hxx>
#include <psl_marshaler.hxx>

//
//  Service code section
//
void *scapi_GetOwnerProcId (void) {
    return GetCallerProcess();
}

ULONG CalcFwdRevViaSectionSize(CAPROPVARIANT *pEntry);
ULONG CalcFwdRevViaSectionSize(CDataHeader *pFwdRevEntry, DWORD *pdwElements);
BOOL  SetFwdRevViaSection(CDataHeader *pFwdRevEntry, CAPROPVARIANT *pPropVar, DWORD dwElements, 
                          DWORD cbBufferSize, HANDLE hCallerProc, HRESULT *pHR);

static HRESULT scapi_FillQueueInfo (int iQueueLenNdx, int iQueueNdx, SCPROPVAR *pMsgProps, QUEUE_FORMAT *pqft, HANDLE hCallerProc) {
    HRESULT hRes = MQ_OK;

    CMarshallDataToProcess copyData(hCallerProc);

    if (iQueueLenNdx >= 0) {
        int ccLen = pMsgProps->aPropVar[iQueueLenNdx].ulVal;
        WCHAR *lpszQueueName = scutil_QFtoString (pqft);

        if (! lpszQueueName) {
            hRes = MQ_ERROR_INSUFFICIENT_RESOURCES;
            pMsgProps->aPropVar[iQueueLenNdx].ulVal = 0;
        } else {
            int ccLenReal = wcslen (lpszQueueName) + 1;

            pMsgProps->aPropVar[iQueueLenNdx].ulVal = ccLenReal;

            if (ccLenReal > ccLen)
                return MQ_ERROR_BUFFER_OVERFLOW;

            if ((iQueueNdx >= 0) && (ccLenReal > 0)) {
                copyData.WriteStrToProc(pMsgProps->aPropVar[iQueueNdx].pwszVal,
                                              lpszQueueName,ccLenReal,&hRes);
            }

            g_funcFree (lpszQueueName, g_pvFreeData);
        }
    } else if (iQueueNdx >= 0)
        hRes = MQ_ERROR_PROPERTY;

    if ((iQueueNdx >= 0) && (pMsgProps->aStatus))
        pMsgProps->aStatus[iQueueNdx] = hRes;

    return hRes;
}

// Fills in PROPVARIANT related to array (VT_UI | VT_VECTOR) types on  
// retrieving message.
static HRESULT scapi_FillArrayInfo(int iDataLenNdx, int iDataNdx, SCPROPVAR *pMsgProps,
                                  const UCHAR *pData, DWORD cbActualDataLen, HANDLE hCallerProc)
{
    // Fill in the length of this data, i.e. in the PROPID_M_FIELD_SIZE
    if (iDataLenNdx >= 0) {
        SVSUTIL_ASSERT(pMsgProps->aPropVar[iDataLenNdx].vt == VT_UI4);
        pMsgProps->aPropVar[iDataLenNdx].ulVal = cbActualDataLen;
    }

    // Fill out the data itself, i.e. the PROPID_M_FIELD
    if (iDataNdx >= 0) {
        DWORD cbAppDataLen = pMsgProps->aPropVar[iDataNdx].caub.cElems;
        if (cbAppDataLen < cbActualDataLen)
            return MQ_ERROR_BUFFER_OVERFLOW;

        HRESULT hRes = MQ_OK;

        if (cbActualDataLen > 0) {
            CMarshallDataToProcess copyData(hCallerProc);
            copyData.WriteBufToProc(pMsgProps->aPropVar[iDataNdx].caub.pElems,
                                    pData,cbActualDataLen,&hRes);
        }
        return hRes;
    }

    return MQ_OK;
}

// Fills in PROPVARIANT info related to a LPWSTR type
static HRESULT scapi_FillStringInfo(int iDataLenNdx, int iDataNdx, SCPROPVAR *pMsgProps,
                                    const WCHAR *szData, DWORD ccActualDataLen, HANDLE hCallerProc)
{
    ULONG ccAppDataLen = (iDataLenNdx < 0) ? 0 : pMsgProps->aPropVar[iDataLenNdx].ulVal;
    if (iDataLenNdx >= 0) {
        SVSUTIL_ASSERT(pMsgProps->aPropVar[iDataLenNdx].vt == VT_UI4);
        pMsgProps->aPropVar[iDataLenNdx].ulVal = ccActualDataLen;
    }

    if (iDataNdx >= 0 && szData) {
        if (ccAppDataLen < ccActualDataLen)
            return MQ_ERROR_BUFFER_OVERFLOW;

        HRESULT hRes = MQ_OK;

        if (ccActualDataLen > 0) {
            CMarshallDataToProcess copyData(hCallerProc);
            copyData.WriteStrToProc(pMsgProps->aPropVar[iDataNdx].pwszVal,
                                szData,ccActualDataLen,&hRes);
        }
        return hRes;
    }

    return MQ_OK;
}

static HRESULT scapi_GetPacket
(
SCHANDLE            hQueue,
SCHANDLE            hCursor,
DWORD               dwAction,
ScPacket            *&pPacket,
ScQueue             *&pQueue,
ScHandleInfo        *&pHInfo
) {
    SVSUTIL_ASSERT (gMem->IsLocked ());

    pPacket = NULL;
    pQueue  = NULL;
    pHInfo  = NULL;

    int fDefaultCursor = ((SVSHandle)hCursor == SVSUTIL_HANDLE_INVALID);

    ScHandleInfo *pQueueHInfo = gQueueMan->QueryHandle ((SVSHandle)hQueue);

    if ((! pQueueHInfo) || (pQueueHInfo->uiHandleType != SCQMAN_HANDLE_QUEUE))
        return MQ_ERROR_INVALID_HANDLE;

    if (((pQueueHInfo->q.uiAccess != MQ_RECEIVE_ACCESS) && (pQueueHInfo->q.uiAccess != MQ_PEEK_ACCESS)) ||
        ((pQueueHInfo->q.uiAccess != MQ_RECEIVE_ACCESS) && (dwAction == MQ_ACTION_RECEIVE)))
        return MQ_ERROR_ACCESS_DENIED;

    pQueue = pQueueHInfo->pQueue;

    if  (fDefaultCursor)
        hCursor = (SCHANDLE)pQueueHInfo->q.hDefaultCursor;

    pHInfo = gQueueMan->QueryHandle ((SVSHandle)hCursor);

    if ((! pHInfo) || (pHInfo->uiHandleType != SCQMAN_HANDLE_CURSOR) || (pHInfo->pQueue != pQueue)) {
        pHInfo = NULL;
        pQueue = NULL;

        return MQ_ERROR_INVALID_HANDLE;
    }

    if (! pHInfo->c.fPosValid) {
        if ((dwAction == MQ_ACTION_PEEK_NEXT) || (dwAction == MQ_ACTION_PEEK_PREV)) {
            pQueue = NULL;
            pHInfo = NULL;

            return MQ_ERROR_ILLEGAL_CURSOR_ACTION;
        }

        if (fDefaultCursor)
            pQueue->Reset (pHInfo);

        if (! pQueue->Advance (pHInfo)) {
            pHInfo = NULL;

            return MQ_OK;
        }

        pHInfo->c.fPosValid = TRUE;
    } else {
        int fSuccess = TRUE;
        if ((dwAction == MQ_ACTION_RECEIVE) || (dwAction == MQ_ACTION_PEEK_CURRENT)) {
            if (fDefaultCursor) {
                pQueue->Reset (pHInfo);

                if (! pQueue->Advance (pHInfo)) {
                    pHInfo = NULL;

                    return MQ_OK;
                }
            }

            ScPacket *pCandidate = (ScPacket *)SVSTree::GetData(pHInfo->c.pNode);
            if (! ((pCandidate->uiPacketState == SCPACKET_STATE_ALIVE) && did_not_expire (pCandidate->tExpirationTime, scutil_now ()))) {
                pQueue = NULL;
                pHInfo = NULL;

                return MQ_ERROR_MESSAGE_ALREADY_RECEIVED;
            }
        } else if (fDefaultCursor) {
            pQueue = NULL;
            pHInfo = NULL;

            return MQ_ERROR_ILLEGAL_CURSOR_ACTION;
        } else if (dwAction == MQ_ACTION_PEEK_NEXT)
            fSuccess = pQueue->Advance (pHInfo);
        else if (dwAction == MQ_ACTION_PEEK_PREV)
            fSuccess = pQueue->Backup (pHInfo);

        if (! fSuccess) {
            pHInfo = NULL;
            return MQ_OK;
        }
    }

    SVSUTIL_ASSERT (pHInfo->c.pNode);

    pPacket = (ScPacket *)SVSTree::GetData(pHInfo->c.pNode);

    return MQ_OK;
}

// Helpers to set PROPVARIANT simple types

inline BOOL SetUI1(PROPVARIANT *pProp, BYTE valueToSet)  {
    if (pProp->vt != VT_UI1)
        return FALSE;

    pProp->bVal = valueToSet;
    return TRUE;
}

inline BOOL SetUI2(PROPVARIANT *pProp, USHORT valueToSet)  {
    if (pProp->vt != VT_UI2)
        return FALSE;

    pProp->uiVal = valueToSet;
    return TRUE;
}

inline BOOL SetUI4(PROPVARIANT *pProp, ULONG valueToSet) {
    if (pProp->vt != VT_UI4)
        return FALSE;

    pProp->ulVal = valueToSet;
    return TRUE;
}

inline BOOL VerifyString(PROPVARIANT *pProp) {
    if ((pProp->vt != VT_LPWSTR) || (! pProp->pwszVal))
        return FALSE;

    return TRUE;
}

inline BOOL SetStringIndex(PROPVARIANT *pProp, int iIndexToSet, int *piIndex) {
    if (! VerifyString(pProp))
        return FALSE;

    *piIndex = iIndexToSet;
    return TRUE;
}

inline BOOL VerifyGuid(PROPVARIANT *pProp) {
    if ((pProp->vt != VT_CLSID) || (pProp->puuid == NULL))
        return FALSE;

    return TRUE;
}

inline BOOL SetLengthIndex(PROPVARIANT *pProp, int iIndexToSet, int *piIndex) {
    if (pProp->vt != VT_UI4)
        return FALSE;

    *piIndex = iIndexToSet;
    return TRUE;
}

inline BOOL SetArrayPtrIndex(PROPVARIANT *pProp, int iIndexToSet, int *piIndex) {
    if ((pProp->vt != (VT_VECTOR | VT_UI1)) ||
        (pProp->caub.cElems <= 0))
        return FALSE;

    *piIndex = iIndexToSet;
    return TRUE;
}

inline BOOL VerifyArrayPtr(PROPVARIANT *pProp, DWORD sizeRequired) {
    if ((pProp->vt != (VT_VECTOR | VT_UI1)) ||
        (pProp->caub.cElems != sizeRequired) ||
        (pProp->caub.pElems == NULL))
        return FALSE;

    return TRUE;

}

inline BOOL SetVariantArrayPtrIndex(PROPVARIANT *pProp, int iIndexToSet, int *piIndex) {
    if (pProp->vt != (VT_VECTOR | VT_VARIANT))
        return FALSE;

    *piIndex = iIndexToSet;
    return TRUE;
}

// Note: This function is called with the global lock held and in a __try/_except block.
#pragma prefast(disable:6011, "Function always called in __try/_except block, crash expected on NULL pointer") 
static HRESULT scapi_RetrievePacketInfo
(
ScPacket        *pPacket,
ScQueue         *pQueue,
ScHandleInfo    *pHInfo,
DWORD           dwAction,
ce::copy_in<SCPROPVAR*> *pMsgPropsA,
HANDLE          hCallerProc
) {
    SVSUTIL_ASSERT (pPacket && pHInfo);
    SVSUTIL_ASSERT (gMem->IsLocked ());

    SCPROPVAR* pMsgProps = *pMsgPropsA;

    CMarshallDataToProcess copyData(hCallerProc);

    static const WCHAR szEmpty[] = L"";

#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_IO, L"Got a message!\n");
#endif
    //
    //  pPacket is here, the queue is locked and the cursor handle pointer is in pHInfo...
    //
    HRESULT hRes = MQ_OK;

    //
    //  Restore packet's image if necessary
    //
    if (! pQueue->BringToMemory (pPacket))
        return MQ_ERROR;

    SVSUTIL_ASSERT (pPacket->pImage && pPacket->pImage->sect.pBaseHeader && pPacket->pImage->sect.pUserHeader && pPacket->pImage->sect.pPropHeader);

    SVSUTIL_ASSERT (pPacket->uiAuditType == pPacket->pImage->sect.pUserHeader->GetAuditing ());
    SVSUTIL_ASSERT (pPacket->uiPacketState == SCPACKET_STATE_ALIVE);
    SVSUTIL_ASSERT (pPacket->uiAckType == pPacket->pImage->sect.pPropHeader->GetAckType ());

    if (pMsgProps->aStatus && pMsgProps->cProp > 0)
        memset (pMsgProps->aStatus, 0, sizeof (HRESULT) * pMsgProps->cProp);

    int iAdminQueueNdx     = -1;
    int iAdminQueueLenNdx  = -1;
    int iBodyNdx           = -1;
    int iBodySizeNdx       = -1;
    int iDestQueueNdx      = -1;
    int iDestQueueLenNdx   = -1;
    int iExtNdx            = -1;
    int iExtSizeNdx        = -1;
    int iLabelNdx          = -1;
    int iLabelLenNdx       = -1;
    int iRespQueueNdx      = -1;
    int iRespQueueLenNdx   = -1;
    int iSoapEnvNdx        = -1;
    int iSoapEnvLenNdx     = -1;
    int iCompoundMsgNdx    = -1;
    int iCompoundMsgLenNdx = -1;
    int iSoapFwdViaNdx     = -1;
    int iSoapFwdViaLenNdx  = -1;
    int iSoapRevViaNdx     = -1;
    int iSoapRevViaLenNdx  = -1;
    int iSoapFromNdx       = -1;
    int iSoapFromLenNdx    = -1;
    int iSoapRelatesToNdx    = -1;
    int iSoapRelatesToLenNdx = -1;

    CCompoundMessageHeader *pCompoundMessage = pPacket->pImage->sect.pUserHeader->SrmpIsIncluded() ? pPacket->pImage->sect.pCompoundMessageHeader : NULL;

    // Validate that parameters are legal.
    for (int i = 0 ; (! FAILED (hRes)) && (i < (int)pMsgProps->cProp) ; ++i) {
        hRes = MQ_OK;
        PROPVARIANT *pProp = &pMsgProps->aPropVar[i];

        switch (pMsgProps->aPropID[i]) {
        case PROPID_M_ACKNOWLEDGE:
            if (! SetUI1(pProp,pPacket->pImage->sect.pPropHeader->GetAckType()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_ADMIN_QUEUE:
            if (! SetStringIndex(pProp,i,&iAdminQueueNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            break;

        case PROPID_M_ADMIN_QUEUE_LEN:
            if (! SetLengthIndex(pProp,i,&iAdminQueueLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_APPSPECIFIC:
            if (! SetUI4(pProp,pPacket->pImage->sect.pPropHeader->GetApplicationTag()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            break;

        case PROPID_M_AUTH_LEVEL:
            if (! SetUI4(pProp,MQMSG_AUTH_LEVEL_NONE))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            break;

        case PROPID_M_BODY:
            if (! SetArrayPtrIndex(pProp, i, &iBodyNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_BODY_SIZE:
            if (! SetLengthIndex(pProp,i,&iBodySizeNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_BODY_TYPE:
            if (! SetUI4(pProp,pPacket->pImage->sect.pPropHeader->GetBodyType ()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            break;

        case PROPID_M_CLASS:
            if (! SetUI2(pProp,pPacket->pImage->sect.pPropHeader->GetClass ()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_CORRELATIONID:
            if (! VerifyArrayPtr(pProp,PROPID_M_CORRELATIONID_SIZE))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;

            copyData.WriteBufToProc(pProp->caub.pElems, 
                    pPacket->pImage->sect.pPropHeader->GetCorrelationID(), 
                    PROPID_M_CORRELATIONID_SIZE,&hRes);

            break;

        case PROPID_M_DELIVERY:
            if (! SetUI1(pProp,pPacket->pImage->sect.pUserHeader->GetDelivery ()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_DEST_QUEUE:
            if (! SetStringIndex(pProp,i,&iDestQueueNdx ))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_DEST_QUEUE_LEN:
            if (! SetLengthIndex(pProp,i,&iDestQueueLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_EXTENSION:
            if (! SetArrayPtrIndex(pProp, i, &iExtNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_EXTENSION_LEN:
            if (! SetLengthIndex(pProp,i,&iExtSizeNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_JOURNAL:
            if (! SetUI1(pProp,pPacket->pImage->sect.pUserHeader->GetAuditing()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_LABEL:
            if (! SetStringIndex(pProp, i, &iLabelNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_LABEL_LEN:
            if (! SetLengthIndex(pProp, i, &iLabelLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_PRIORITY:
            if (! SetUI1(pProp,pPacket->pImage->sect.pBaseHeader->GetPriority()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_RESP_QUEUE:
            if (! SetStringIndex(pProp, i, &iRespQueueNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_RESP_QUEUE_LEN:
            if (! SetLengthIndex(pProp, i, &iRespQueueLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_TIME_TO_BE_RECEIVED:
            if (! SetUI4(pProp,pPacket->pImage->sect.pUserHeader->GetTimeToLiveDelta()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_TIME_TO_REACH_QUEUE:
            if (! SetUI4(pProp,pPacket->pImage->sect.pBaseHeader->GetAbsoluteTimeToQueue()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_TRACE:
            if (! SetUI1(pProp,pPacket->pImage->sect.pBaseHeader->GetTraced()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_XACT_STATUS_QUEUE:
            if (! VerifyString(pProp))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                copyData.WriteStrToProc(pProp->pwszVal, szEmpty, 1, &hRes);
            break;

        case PROPID_M_XACT_STATUS_QUEUE_LEN:
            if (! SetUI4(pProp,0))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_VERSION:
            if (! SetUI4(pProp,pPacket->pImage->sect.pBaseHeader->GetVersion()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SRC_MACHINE_ID:
            if (! VerifyGuid(pProp))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                copyData.WriteGUIDToProc(pProp->puuid,pPacket->pImage->sect.pUserHeader->GetSourceQM(),&hRes);
            break;

        case PROPID_M_SIGNATURE:
            break;

        case PROPID_M_SIGNATURE_LEN:
            if (! SetUI4(pProp,0))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SENTTIME:
            if (! SetUI4(pProp,pPacket->pImage->sect.pUserHeader->GetSentTime()))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SENDERID_LEN:
            if (! SetUI4(pProp,0))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SENDERID_TYPE:
            if (! SetUI4(pProp,MQMSG_SENDERID_TYPE_NONE))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SENDERID:
            break;

        case PROPID_M_SENDER_CERT_LEN:
            if (! SetUI4(pProp,0))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SENDER_CERT:
            break;

        case PROPID_M_PROV_NAME_LEN:
            if (! SetUI4(pProp,0))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_PROV_NAME:
            if (! VerifyString(pProp))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                copyData.WriteStrToProc(pProp->pwszVal, szEmpty, 1, &hRes);
            break;

        case PROPID_M_PRIV_LEVEL:
            if (! SetUI4(pProp,MQMSG_PRIV_LEVEL_NONE))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_MSGID:
            if (! VerifyArrayPtr(pProp,sizeof(OBJECTID)))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else {
                OBJECTID messageId;
                pPacket->pImage->sect.pUserHeader->GetMessageID(&messageId);
                copyData.WriteBufToProc(pProp->caub.pElems,(UCHAR*)&messageId,
                    sizeof(OBJECTID), &hRes);
            }
            break;

        case PROPID_M_ARRIVEDTIME:
            if (! SetUI4(pProp,pPacket->tCreationTime))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_DEST_SYMM_KEY:
            break;

        case PROPID_M_DEST_SYMM_KEY_LEN:
            if (! VerifyString(pProp))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                copyData.WriteStrToProc(pProp->pwszVal, szEmpty,1, &hRes);
            break;

        case PROPID_M_CONNECTOR_TYPE:
            if (! VerifyGuid(pProp))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else {
                GUID guid;
                memset(&guid,0,sizeof(GUID));
                copyData.WriteGUIDToProc(pProp->puuid, &guid, &hRes);
            }
            break;

        case PROPID_M_AUTHENTICATED:
            if (! SetUI4(pProp,0))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_HASH_ALG:
        case PROPID_M_ENCRYPTION_ALG:
        case PROPID_M_PROV_TYPE:
        case PROPID_M_SECURITY_CONTEXT:
            hRes = MQ_ERROR_COMPUTER_DOES_NOT_SUPPORT_ENCRYPTION;
            break;

        case PROPID_M_FIRST_IN_XACT:
            {
                CXactHeader *pXactHeader = pPacket->pImage->sect.pXactHeader;
                BOOL fFirstInXact = pXactHeader ? pXactHeader->GetFirstInXact() : FALSE;
                if (! SetUI1(pProp,fFirstInXact))
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            }
            break;

        case PROPID_M_LAST_IN_XACT:
            {         
                CXactHeader *pXactHeader = pPacket->pImage->sect.pXactHeader;
                BOOL fLastInXact = pXactHeader ? pXactHeader->GetLastInXact() : FALSE;
                if (! SetUI1(pProp,fLastInXact))
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            }
            break;

        case PROPID_M_XACTID:
            if (! VerifyArrayPtr(pProp, sizeof(OBJECTID)))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_SIZE;
            else {
                CXactHeader *pXactHeader = pPacket->pImage->sect.pXactHeader;
                OBJECTID xactID;

                if (pXactHeader) {
                    xactID.Lineage    = *pPacket->pImage->sect.pUserHeader->GetSourceQM();
                    xactID.Uniquifier = pXactHeader->GetXactIndex();
                }
                else {
                    memset(&xactID,0,sizeof(OBJECTID));
                }

                copyData.WriteBufToProc(pProp->caub.pElems, (UCHAR*)&xactID, sizeof(xactID), &hRes);
            }
            break;

        case PROPID_M_SOAP_ENVELOPE:
            if (! SetStringIndex(pProp,i,&iSoapEnvNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SOAP_ENVELOPE_LEN:
            if (! SetLengthIndex(pProp, i, &iSoapEnvLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_COMPOUND_MESSAGE:
            if (! SetArrayPtrIndex(pProp, i, &iCompoundMsgNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_COMPOUND_MESSAGE_SIZE:
            if (! SetLengthIndex(pProp, i, &iCompoundMsgLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SOAP_FWD_VIA:
            if (! SetVariantArrayPtrIndex(pProp, i, &iSoapFwdViaNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SOAP_FWD_VIA_SIZE:
            if (! SetLengthIndex(pProp, i, &iSoapFwdViaLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SOAP_REV_VIA:
            if (! SetVariantArrayPtrIndex(pProp, i, &iSoapRevViaNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SOAP_REV_VIA_SIZE:
            if (! SetLengthIndex(pProp, i, &iSoapRevViaLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SOAP_FROM:
            if (! SetStringIndex(pProp, i, &iSoapFromNdx))
                iSoapFromNdx = i;
            break;

        case PROPID_M_SOAP_FROM_LEN:
            if (! SetLengthIndex(pProp, i, &iSoapFromLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_SOAP_RELATES_TO:
            if (! SetStringIndex(pProp, i, &iSoapRelatesToNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            break;

        case PROPID_M_SOAP_RELATES_TO_LEN:
            if (! SetLengthIndex(pProp, i, &iSoapRelatesToLenNdx))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        default:
            hRes = MQ_ERROR_PROPERTY;
        }

        if (pMsgProps->aStatus)
            pMsgProps->aStatus[i] = hRes;
    }

    if (FAILED(hRes))
        return hRes;

    QUEUE_FORMAT qft;
    //
    //  Admin queue
    //
    //
    hRes = MQ_OK;

    if (pPacket->pImage->sect.pUserHeader->GetAdminQueue (&qft))
        hRes = scapi_FillQueueInfo (iAdminQueueLenNdx, iAdminQueueNdx, pMsgProps, &qft, hCallerProc);
    else if (iAdminQueueLenNdx >= 0)
        pMsgProps->aPropVar[iAdminQueueLenNdx].ulVal = 0;

    if (FAILED(hRes))
        return hRes;

    //
    //  Response queue
    //
    hRes = MQ_OK;

    if (pPacket->pImage->sect.pUserHeader->GetResponseQueue (&qft))
        hRes = scapi_FillQueueInfo (iRespQueueLenNdx, iRespQueueNdx, pMsgProps, &qft, hCallerProc);
    else if (iRespQueueLenNdx >= 0)
        pMsgProps->aPropVar[iRespQueueLenNdx].ulVal = 0;

    if (FAILED(hRes))
        return hRes;

    //
    //  Dest queue
    //
    hRes = MQ_OK;

    if (pPacket->pImage->sect.pUserHeader->GetDestinationQueue (&qft))
        hRes = scapi_FillQueueInfo (iDestQueueLenNdx, iDestQueueNdx, pMsgProps, &qft, hCallerProc);
    else if (iDestQueueLenNdx >= 0)
        pMsgProps->aPropVar[iDestQueueLenNdx].ulVal = 0;

    if (FAILED(hRes))
        return hRes;

    //
    //  Label
    //
    hRes = scapi_FillStringInfo(iLabelLenNdx, iLabelNdx, pMsgProps,
                         pPacket->pImage->sect.pPropHeader->GetTitlePtr(),
                         pPacket->pImage->sect.pPropHeader->GetTitleLength(),
                         hCallerProc);
    if (FAILED(hRes))
        return hRes;

    //
    //  Body
    //
    hRes = scapi_FillArrayInfo(iBodySizeNdx,iBodyNdx,pMsgProps,
                       pCompoundMessage ? pCompoundMessage->GetPointerToBody() : pPacket->pImage->sect.pPropHeader->GetBodyPtr(),
                       pCompoundMessage ? pCompoundMessage->GetBodySizeInBytes() : pPacket->pImage->sect.pPropHeader->GetBodySize (),
                       hCallerProc);
    if (FAILED(hRes))
        return hRes;

    //
    //  Extension
    //
    hRes = scapi_FillArrayInfo(iExtSizeNdx,iExtNdx,pMsgProps,
                        pPacket->pImage->sect.pPropHeader->GetMsgExtensionPtr(),
                        pPacket->pImage->sect.pPropHeader->GetMsgExtensionSize(),
                        hCallerProc);
    if (FAILED(hRes))
        return hRes;
    
    //
    //  SRMP Envelope
    //
    CSrmpEnvelopeHeader *pSrmpEnvHead = pPacket->pImage->sect.pSrmpEnvelopeHeader;
    
    hRes = scapi_FillStringInfo(iSoapEnvLenNdx, iSoapEnvNdx, pMsgProps,
                         pSrmpEnvHead ? pPacket->pImage->sect.pSrmpEnvelopeHeader->GetData() : NULL,
                         pSrmpEnvHead ? pPacket->pImage->sect.pSrmpEnvelopeHeader->GetDataLengthInWCHARs() : 0,
                         hCallerProc);
    if (FAILED(hRes))
        return hRes;

    // 
    // Compound Message
    //
    CCompoundMessageHeader *pCmpndMsgHead = pPacket->pImage->sect.pCompoundMessageHeader;
    hRes = scapi_FillArrayInfo(iCompoundMsgLenNdx, iCompoundMsgNdx, pMsgProps,
                        pCmpndMsgHead ? pCmpndMsgHead->GetPointerToData() : 0,
                        pCmpndMsgHead ? pCmpndMsgHead->GetDataSizeInBytes() : 0, 
                        hCallerProc);
    if (FAILED(hRes))
        return hRes;

    //
    // SOAP <fwd><via> entries.
    //
    ULONG cbSoapFwdViaLen       = (iSoapFwdViaLenNdx < 0) ? 0 : pMsgProps->aPropVar[iSoapFwdViaLenNdx].ulVal;
    ULONG cbSoapFwdViaRequired  = 0;
    ULONG cFwdElements          = 0;

    if (iSoapFwdViaLenNdx >= 0) {
        cbSoapFwdViaRequired = CalcFwdRevViaSectionSize(pPacket->pImage->sect.pFwdViaHeader,&cFwdElements);
        pMsgProps->aPropVar[iSoapFwdViaLenNdx].ulVal = cbSoapFwdViaRequired;
    }

    if (iSoapFwdViaNdx >= 0 && pPacket->pImage->sect.pFwdViaHeader) {
        if (cbSoapFwdViaLen < cbSoapFwdViaRequired)
            return MQ_ERROR_BUFFER_OVERFLOW;

        if (! SetFwdRevViaSection(pPacket->pImage->sect.pFwdViaHeader,
                                  &pMsgProps->aPropVar[iSoapFwdViaNdx].capropvar,
                                  cFwdElements,cbSoapFwdViaRequired,hCallerProc,&hRes))
            return hRes;
    }

    //
    // SOAP <rev><via> entries.
    //
    ULONG cbSoapRevViaLen = (iSoapRevViaLenNdx < 0) ? 0 : pMsgProps->aPropVar[iSoapRevViaLenNdx].ulVal;
    ULONG cbSoapRevViaRequired  = 0;
    ULONG cRevElements          = 0;

    if (iSoapRevViaLenNdx >= 0) {
        cbSoapRevViaRequired = CalcFwdRevViaSectionSize(pPacket->pImage->sect.pRevViaHeader,&cRevElements);
        pMsgProps->aPropVar[iSoapRevViaLenNdx].ulVal = cbSoapRevViaRequired;
    }

    if (iSoapRevViaNdx >= 0 && pPacket->pImage->sect.pRevViaHeader) {
        if (cbSoapRevViaLen < cbSoapRevViaRequired)
            return MQ_ERROR_BUFFER_OVERFLOW;

        if (! SetFwdRevViaSection(pPacket->pImage->sect.pRevViaHeader,
                                  &pMsgProps->aPropVar[iSoapRevViaNdx].capropvar,
                                  cRevElements,cbSoapRevViaRequired,hCallerProc,&hRes))
            return hRes;
    }

    //
    // SOAP <from> element
    //
    CSoapExtSection *pSoapExt = pPacket->pImage->sect.pSoapExtHeaderSection;
    hRes = scapi_FillStringInfo(iSoapFromLenNdx, iSoapFromNdx, pMsgProps,
                         pSoapExt ?  pSoapExt->GetFrom() : 0,
                         pSoapExt ?  pSoapExt->GetFromLengthInWCHARs() : 0,
                         hCallerProc);
    if (FAILED(hRes))
        return hRes;

    // 
    // SOAP <relatesTo> element
    //
    hRes = scapi_FillStringInfo(iSoapRelatesToLenNdx, iSoapRelatesToNdx, pMsgProps,
                         pSoapExt ?  pSoapExt->GetRelatesTo() : 0,
                         pSoapExt ?  pSoapExt->GetRelatesToLengthInWCHARs() : 0,
                         hCallerProc);
    if (FAILED(hRes))
        return hRes;

    //
    //  We've read it, now we free the packet.
    //
    if ((hRes == MQ_OK) && (dwAction == MQ_ACTION_RECEIVE)) {
#if defined (SC_VERBOSE)
        scerror_DebugOut (VERBOSE_MASK_IO, L"Message read successfully, accepting and advancing...\n");
#endif

        pHInfo->c.fPosValid = FALSE;
        gQueueMan->ForwardTransactionalResponse (pPacket->pImage, MQMSG_CLASS_ACK_RECEIVE, NULL, NULL);
        gQueueMan->AcceptPacket (pPacket, MQMSG_CLASS_ACK_RECEIVE, pQueue);
        pQueue->DisposeOfPacket (pPacket);
    }

    return hRes;
}
#pragma prefast(enable:6011) 

static HRESULT scapi_MQReceiveMessageI
(
ScIoRequest *pReq
) {
    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    ScPacket     *pPacket    = NULL;
    ScQueue      *pQueue     = NULL;
    ScHandleInfo *pHInfo     = NULL;

    HRESULT hr = scapi_GetPacket (pReq->hQueue, pReq->hCursor, pReq->dwAction, pPacket, pQueue, pHInfo);

    if (hr != MQ_OK) {
        SVSUTIL_ASSERT ((! pHInfo));
        SVSUTIL_ASSERT ((! pPacket));
        SVSUTIL_ASSERT ((! pQueue));
        gMem->Unlock ();
        return hr;
    }

    SVSUTIL_ASSERT_PREFAST (pQueue);

    HANDLE hCallerProc = pReq->hCallerProc;

    if (pPacket) {
        SVSUTIL_ASSERT (pHInfo);

        __try {
            hr = scapi_RetrievePacketInfo (pPacket, pQueue, pHInfo, pReq->dwAction, pReq->pMsgProps, hCallerProc);
        } __except (1) {
            hr = MQ_ERROR_PROPERTY;
        }
        gMem->Unlock ();

        return hr;
    }

#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_IO, L"Waiting (again) for message in the queue %s until %d ms.\n", pQueue->lpszFormatName, pReq->tExpirationTicks);
#endif

    HANDLE hQueueEvent = pQueue->hUpdateEvent;

    gMem->Unlock ();

    if (did_expire (pReq->tExpirationTicks, GetTickCount()))
        return MQ_ERROR_IO_TIMEOUT;

    return gOverlappedSupport->EnterOverlappedReceive (hQueueEvent, pReq);
}

//////////////////////////////////////////////////////////////////////
//
//
//  API code section
//
//
//////////////////////////////////////////////////////////////////////
HRESULT scapi_MQCreateQueue
(
SCPROPVAR       *pQueueProps,
WCHAR           *lpszFormatName,
DWORD           *dwNameLen
) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQCreateQueue\n");
#endif

    if (! pQueueProps)
        return MQ_ERROR_ILLEGAL_MQQUEUEPROPS;

    if (dwNameLen == NULL)
        return MQ_ERROR_INVALID_PARAMETER;

    if ((NULL == pQueueProps->aPropID) || (NULL == pQueueProps->aPropVar)) {
        return MQ_ERROR_ILLEGAL_MQQUEUEPROPS;
    }

    WCHAR           *szLabel = NULL;
    WCHAR           *szPathName = NULL;

    unsigned int    uiJournalQuota = (unsigned int)-1;

    ScQueueParms    qp;

    memset (&qp, 0, sizeof(qp));
    qp.uiPrivacyLevel = MQ_PRIV_LEVEL_NONE;
    qp.bIsIncoming = TRUE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    qp.uiQuotaK = gMachine->uiDefaultInQuotaK;

    gMem->Unlock ();

    HRESULT hRes = MQ_OK;

    if (pQueueProps->aStatus && pQueueProps->cProp > 0)
        memset (pQueueProps->aStatus, 0, sizeof (HRESULT) * pQueueProps->cProp);

    for (int i = 0 ; (! FAILED (hRes)) && (i < (int)pQueueProps->cProp); ++i) {
        hRes = MQ_OK;
        switch (pQueueProps->aPropID[i]) {
        case PROPID_Q_AUTHENTICATE:
            if (pQueueProps->aPropVar[i].vt != VT_UI1)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else if (pQueueProps->aPropVar[i].bVal != MQ_AUTHENTICATE_NONE)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_Q_BASEPRIORITY:
            if (pQueueProps->aPropVar[i].vt != VT_I2)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                qp.iBasePriority = pQueueProps->aPropVar[i].iVal;
            break;

        case PROPID_Q_CREATE_TIME:
        case PROPID_Q_INSTANCE:
        case PROPID_Q_MODIFY_TIME:
            hRes = MQ_ERROR_PROPERTY_NOTALLOWED;
            break;

        case PROPID_Q_JOURNAL:
            if (pQueueProps->aPropVar[i].vt != VT_UI1)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else if (pQueueProps->aPropVar[i].bVal == MQ_JOURNAL)
                qp.bIsJournalOn = qp.bHasJournal = TRUE;
            else if (pQueueProps->aPropVar[i].bVal != MQ_JOURNAL_NONE)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_Q_JOURNAL_QUOTA:
            if (pQueueProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                uiJournalQuota = pQueueProps->aPropVar[i].ulVal;
            break;

        case PROPID_Q_LABEL:
            if (pQueueProps->aPropVar[i].vt != VT_LPWSTR)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                szLabel = pQueueProps->aPropVar[i].pwszVal;
            break;

        case PROPID_Q_PATHNAME:
            if (pQueueProps->aPropVar[i].vt != VT_LPWSTR)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                szPathName = pQueueProps->aPropVar[i].pwszVal;
            break;

        case PROPID_Q_PRIV_LEVEL:
            if (pQueueProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else if (pQueueProps->aPropVar[i].ulVal != MQ_PRIV_LEVEL_NONE)
                return MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_Q_QUOTA:
            if (pQueueProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                qp.uiQuotaK = pQueueProps->aPropVar[i].ulVal;
            break;

        case PROPID_Q_TRANSACTION:
            if (pQueueProps->aPropVar[i].vt != VT_UI1)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else if (pQueueProps->aPropVar[i].bVal == MQ_TRANSACTIONAL_NONE)
                qp.bTransactional = FALSE;
            else if (pQueueProps->aPropVar[i].bVal == MQ_TRANSACTIONAL)
                qp.bTransactional = TRUE;
            else
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;

            break;

        case PROPID_Q_TYPE:
            if (pQueueProps->aPropVar[i].vt != VT_CLSID)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                qp.guidQueueType = *pQueueProps->aPropVar[i].puuid;
            break;

        default:
            hRes = MQ_ERROR_ILLEGAL_PROPID;
        }

        if (pQueueProps->aStatus)
            pQueueProps->aStatus[i] = hRes;
    }

    if (FAILED(hRes))
        return hRes;

    if (szPathName == NULL)
        return MQ_ERROR_INSUFFICIENT_PROPERTIES;

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    ScQueue *pQueue = gQueueMan->MakeIncomingQueue (szPathName, szLabel ? szLabel : NULL, &qp, uiJournalQuota, &hRes);

    if (! pQueue) {
        gMem->Unlock ();
        return hRes;
    }

    int iFormatChars = wcslen (pQueue->lpszFormatName) + 1;

    if ((int)*dwNameLen < iFormatChars) {
        if (lpszFormatName && (*dwNameLen > 0)) {
            memcpy (lpszFormatName, pQueue->lpszFormatName, (*dwNameLen - 1) * sizeof(WCHAR));
            lpszFormatName[*dwNameLen - 1] = L'\0';
        }

        hRes = MQ_INFORMATION_FORMATNAME_BUFFER_TOO_SMALL;
    }
    else {
        if (lpszFormatName)
            memcpy (lpszFormatName, pQueue->lpszFormatName, iFormatChars * sizeof(WCHAR));

        hRes = MQ_OK;
    }

    *dwNameLen = iFormatChars;

    gMem->Unlock ();
    return hRes;
}

HRESULT scapi_MQDeleteQueue
(
WCHAR *lpszFormatName
) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQDeleteQueue\n");
#endif

    if (! lpszFormatName)
        return MQ_ERROR_ILLEGAL_FORMATNAME;

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    ScQueue *pQueue = gQueueMan->FindIncomingByFormat (lpszFormatName);

    if (! pQueue) {
        gMem->Unlock ();

        return MQ_ERROR_QUEUE_NOT_FOUND;
    }

    if (pQueue->qp.bIsProtected || pQueue->qp.bIsJournal) {
        gMem->Unlock ();

        return MQ_ERROR_ACCESS_DENIED;
    }

    if (pQueue->pJournal)
        gQueueMan->DeleteQueue (pQueue->pJournal, TRUE);

    gQueueMan->DeleteQueue (pQueue, TRUE);

    gMem->Unlock ();

    return MQ_OK;
}

HRESULT scapi_MQGetMachineProperties
(
const WCHAR     *lpszMachineName,
const GUID      *pGUID,
SCPROPVAR       *pMachineProps
) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQGetMachineProperties\n");
#endif

    if ((! pMachineProps) || (pMachineProps->cProp < 1))
        return MQ_ERROR_ILLEGAL_MQQMPROPS;

    if (lpszMachineName && pGUID)
        return MQ_ERROR_INVALID_PARAMETER;

    if ((! pMachineProps->aPropID) || (! pMachineProps->aPropVar))
        return MQ_ERROR_ILLEGAL_MQQUEUEPROPS;

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    HRESULT hRes = MQ_OK;
        
    __try {
        if (lpszMachineName && (_wcsicmp (lpszMachineName, gMachine->lpszHostName) != 0)) {
            gMem->Unlock ();
            return MQ_ERROR_SERVICE_NOT_AVAILABLE;
        }

        if (pGUID && (*pGUID != gMachine->guid)) {
            gMem->Unlock ();
            return MQ_ERROR_SERVICE_NOT_AVAILABLE;
        }

        if (pMachineProps->aStatus && pMachineProps->cProp > 0)
            memset (pMachineProps->aStatus, 0, sizeof (HRESULT) * pMachineProps->cProp);

        for (int i = 0 ; (! FAILED(hRes)) && i < (int)pMachineProps->cProp; ++i) {
            hRes = MQ_OK;
            switch (pMachineProps->aPropID[i]) {
            case PROPID_QM_MACHINE_ID:
                {
                    if (pMachineProps->aPropVar[i].vt == VT_NULL) {
                        pMachineProps->aPropVar[i].puuid = (CLSID*)gMem->remoteAlloc.DuplicateBufferAndTranslate((BYTE*)&gMachine->guid,sizeof(GUID));
                        pMachineProps->aPropVar[i].vt = VT_CLSID;
                        break;
                    }

                    if (pMachineProps->aPropVar[i].vt == VT_CLSID) {
                        CMarshallDataToProcess copyOut((HANDLE)GetCallerVMProcessId());
                        copyOut.WriteGUIDToProc(pMachineProps->aPropVar[i].puuid, &gMachine->guid, &hRes);
                    }
                    else
                        hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                }
                break;

            default:
                hRes = MQ_ERROR_ILLEGAL_PROPID;
            }

            if (pMachineProps->aStatus)
                pMachineProps->aStatus[i] = hRes;
        }
    }
    __except(ReportFault(GetExceptionInformation(),0), EXCEPTION_EXECUTE_HANDLER) {
        hRes = MQ_ERROR_INVALID_PARAMETER;
    }

    gMem->Unlock ();

    return hRes;
}

HRESULT scapi_MQGetQueueProperties
(
WCHAR           *lpszFormatName,
SCPROPVAR       *pQueueProps
) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQGetQueueProperties\n");
#endif

    if (! lpszFormatName)
        return MQ_ERROR_ILLEGAL_FORMATNAME;

    if (! pQueueProps)
        return MQ_ERROR_ILLEGAL_MQQUEUEPROPS;

    if ((NULL == pQueueProps->aPropID) || (NULL == pQueueProps->aPropVar))
        return MQ_ERROR_ILLEGAL_MQQUEUEPROPS;

    gMem->Lock ();
    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    ScQueue *pq = gQueueMan->FindIncomingByFormat(lpszFormatName);
    if (! pq) {
        gMem->Unlock ();
        return MQ_ERROR_QUEUE_NOT_FOUND;
    }

    HRESULT hRes = MQ_OK;

    __try {
        if (pQueueProps->aStatus && pQueueProps->cProp > 0)
            memset (pQueueProps->aStatus, 0, sizeof (HRESULT) * pQueueProps->cProp);

        for (int i = 0 ; (! FAILED(hRes)) && i < (int)pQueueProps->cProp; ++i) {
            hRes = MQ_OK;
            switch (pQueueProps->aPropID[i]) {
            case PROPID_Q_AUTHENTICATE:
                if (pQueueProps->aPropVar[i].vt != VT_UI1)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else if (pq->qp.bAuthenticate)
                    pQueueProps->aPropVar[i].bVal = MQ_AUTHENTICATE;
                else
                    pQueueProps->aPropVar[i].bVal = MQ_AUTHENTICATE_NONE;
                break;

            case PROPID_Q_BASEPRIORITY:
                if (pQueueProps->aPropVar[i].vt != VT_I2)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else
                    pQueueProps->aPropVar[i].iVal = pq->qp.iBasePriority;
                break;

            case PROPID_Q_CREATE_TIME:
                if (pQueueProps->aPropVar[i].vt != VT_I4)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else
                    pQueueProps->aPropVar[i].lVal = (int)pq->tCreation;
                break;

            case PROPID_Q_INSTANCE:
                hRes = MQ_INFORMATION_PROPERTY_IGNORED;
                break;

            case PROPID_Q_MODIFY_TIME:
                if (pQueueProps->aPropVar[i].vt != VT_I4)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else
                    pQueueProps->aPropVar[i].lVal = (int)pq->tModification;
                break;

            case PROPID_Q_JOURNAL:
                if (pQueueProps->aPropVar[i].vt != VT_UI1)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else if (pq->qp.bIsJournalOn)
                    pQueueProps->aPropVar[i].bVal = MQ_JOURNAL;
                else
                    pQueueProps->aPropVar[i].bVal = MQ_JOURNAL_NONE;

                break;

            case PROPID_Q_JOURNAL_QUOTA:
                if (pQueueProps->aPropVar[i].vt != VT_UI4)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
                else
                    pQueueProps->aPropVar[i].ulVal = pq->pJournal ? pq->pJournal->qp.uiQuotaK : 0;
                break;

            case PROPID_Q_PRIV_LEVEL:
                if (pQueueProps->aPropVar[i].vt != VT_UI4)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else
                    pQueueProps->aPropVar[i].ulVal = pq->qp.uiPrivacyLevel;
                break;

            case PROPID_Q_QUOTA:
                if (pQueueProps->aPropVar[i].vt != VT_UI4)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else
                    pQueueProps->aPropVar[i].ulVal = pq->qp.uiQuotaK;
                break;

            case PROPID_Q_TRANSACTION:
                if (pQueueProps->aPropVar[i].vt != VT_UI1)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else
                    pQueueProps->aPropVar[i].bVal = pq->qp.bTransactional ? MQ_TRANSACTIONAL :
                                                    MQ_TRANSACTIONAL_NONE;
                break;

            case PROPID_Q_TYPE:
                if (pQueueProps->aPropVar[i].vt != VT_CLSID)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else if (! pQueueProps->aPropVar[i].puuid)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
                else {
                    CMarshallDataToProcess copyData((HANDLE)GetCallerVMProcessId());
                    copyData.WriteGUIDToProc(pQueueProps->aPropVar[i].puuid, &pq->qp.guidQueueType, &hRes);
                }
                break;

            case PROPID_Q_LABEL:
                if (pQueueProps->aPropVar[i].vt != VT_NULL)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else {
                    pQueueProps->aPropVar[i].vt = VT_LPWSTR;
                    pQueueProps->aPropVar[i].pwszVal = scutil_OutOfProcDup (pq->lpszQueueLabel ? pq->lpszQueueLabel : L"");
                }
                break;

            case PROPID_Q_PATHNAME:
                if (pQueueProps->aPropVar[i].vt != VT_NULL)
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
                else {
                    pQueueProps->aPropVar[i].vt = VT_LPWSTR;
                    WCHAR *lpsz = scutil_MakePathName (pq->lpszQueueHost, pq->lpszQueueName, &pq->qp);

                    pQueueProps->aPropVar[i].pwszVal = scutil_OutOfProcDup (lpsz);
                    g_funcFree (lpsz, g_pvFreeData);
                }
                break;

            default:
                hRes = MQ_ERROR_ILLEGAL_PROPID;
            }

            if (pQueueProps->aStatus)
                pQueueProps->aStatus[i] = hRes;
        }
    }
    __except(ReportFault(GetExceptionInformation(),0), EXCEPTION_EXECUTE_HANDLER) {
        hRes = MQ_ERROR_INVALID_PARAMETER;
    }

    gMem->Unlock ();

    return hRes;
}

HRESULT scapi_MQSetQueueProperties (WCHAR *lpszFormatName, SCPROPVAR *pQueueProps) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQSetQueueProperties\n");
#endif

    if (! lpszFormatName)
        return MQ_ERROR_ILLEGAL_FORMATNAME;

    if (! pQueueProps)
        return MQ_ERROR_ILLEGAL_MQQUEUEPROPS;

    HANDLE          hCallerProc = (HANDLE)GetCallerProcess();

    if ((NULL == pQueueProps->aPropID) || (NULL == pQueueProps->aPropVar)) {
        return MQ_ERROR_ILLEGAL_MQQUEUEPROPS;
    }

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    ScQueue *pq = gQueueMan->FindIncomingByFormat (lpszFormatName);

    if (! pq) {
        gMem->Unlock ();
        return MQ_ERROR_QUEUE_NOT_FOUND;
    }

    HRESULT hRes = MQ_OK;

    if (pQueueProps->aStatus && pQueueProps->cProp > 0)
        memset (pQueueProps->aStatus, 0, sizeof (HRESULT) * pQueueProps->cProp);

    for (int i = 0 ; (! FAILED(hRes)) && i < (int)pQueueProps->cProp; ++i) {
        hRes = MQ_OK;
        switch (pQueueProps->aPropID[i]) {
        case PROPID_Q_AUTHENTICATE:
            if (pQueueProps->aPropVar[i].vt != VT_UI1)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else if (pQueueProps->aPropVar[i].bVal == MQ_AUTHENTICATE_NONE)
                pq->qp.bAuthenticate = FALSE;
            else
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_Q_BASEPRIORITY:
            if (pQueueProps->aPropVar[i].vt != VT_I2)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                pq->qp.iBasePriority = pQueueProps->aPropVar[i].iVal;
            break;

        case PROPID_Q_JOURNAL:
            if (! pq->pJournal)
                hRes = MQ_ERROR_PROPERTY;
            else if (pQueueProps->aPropVar[i].bVal == MQ_JOURNAL)
                pq->qp.bIsJournalOn = TRUE;
            else if (pQueueProps->aPropVar[i].bVal == MQ_JOURNAL_NONE)
                pq->qp.bIsJournalOn = FALSE;
            else
                hRes = MQ_ERROR_PROPERTY;
            break;

        case PROPID_Q_JOURNAL_QUOTA:
            if (! pq->pJournal)
                hRes = MQ_ERROR_PROPERTY;
            else
                pq->pJournal->qp.uiQuotaK = pQueueProps->aPropVar[i].ulVal;
            break;

        case PROPID_Q_CREATE_TIME:
        case PROPID_Q_INSTANCE:
        case PROPID_Q_MODIFY_TIME:
        case PROPID_Q_PATHNAME:
        case PROPID_Q_TRANSACTION:
            hRes = MQ_ERROR_WRITE_NOT_ALLOWED;
            break;

        case PROPID_Q_LABEL:
            if (pQueueProps->aPropVar[i].vt != VT_LPWSTR)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else {
                if (pq->lpszQueueLabel) {
                    g_funcFree (pq->lpszQueueLabel, g_pvFreeData);
                    pq->lpszQueueLabel = NULL;
                }

                WCHAR *lpszNewLabel = pQueueProps->aPropVar[i].pwszVal;

                if (lpszNewLabel && (lpszNewLabel[0] != L'\0'))
                    pq->lpszQueueLabel = svsutil_wcsdup (lpszNewLabel);
                else
                    pq->lpszQueueLabel = NULL;
            }
            break;

        case PROPID_Q_PRIV_LEVEL:
            if (pQueueProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                pq->qp.uiPrivacyLevel = pQueueProps->aPropVar[i].ulVal;
            break;

        case PROPID_Q_QUOTA:
            if (pQueueProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                pq->qp.uiQuotaK = pQueueProps->aPropVar[i].ulVal;
            break;

        case PROPID_Q_TYPE:
            if ((pQueueProps->aPropVar[i].vt != VT_CLSID) || (! pQueueProps->aPropVar[i].puuid))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VT;
            else
                pq->qp.guidQueueType = *pQueueProps->aPropVar[i].puuid;
            break;

        default:
            hRes = MQ_ERROR_ILLEGAL_PROPID;
        }
        if (pQueueProps->aStatus)
            pQueueProps->aStatus[i] = hRes;
    }

    if (! FAILED(hRes))
        pq->UpdateFile ();

    gMem->Unlock ();
    return hRes;
}

HRESULT scapi_MQOpenQueue (WCHAR *lpszFormatName, DWORD dwAccess, DWORD dwShareMode, SCHANDLE *phQueue) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQOpenQueue\n");
#endif

    if (! phQueue)
        return MQ_ERROR;

    if (! lpszFormatName)
        return MQ_ERROR_ILLEGAL_FORMATNAME;

    if ((dwAccess != MQ_PEEK_ACCESS) && (dwAccess != MQ_SEND_ACCESS) && (dwAccess != MQ_RECEIVE_ACCESS))
        return MQ_ERROR_UNSUPPORTED_ACCESS_MODE;

    if ((dwAccess == MQ_SEND_ACCESS) && (dwShareMode != MQ_DENY_NONE))
        return MQ_ERROR_INVALID_PARAMETER;

    if (dwShareMode != MQ_DENY_NONE && dwShareMode != MQ_DENY_RECEIVE_SHARE)
        return MQ_ERROR_INVALID_PARAMETER;

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;  

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    WCHAR *p = wcschr (lpszFormatName, L';');
    if (p && (_wcsicmp (p, L";XACTONLY") != 0))
        p = NULL;

    if (p)
        *p = L'\0';

    int uiQueueType;
    ScQueue *pq = gQueueMan->FindIncomingByFormat(lpszFormatName,&uiQueueType);

    if ((! pq) && (dwAccess == MQ_SEND_ACCESS)) {
        pq = gQueueMan->FindOutgoingByFormat (lpszFormatName);

        if (! pq) {
            ScQueueParms qp;
            memset (&qp, 0, sizeof(qp));
            qp.uiQuotaK = gMachine->uiDefaultOutQuotaK;
            qp.bTransactional = p != NULL;
            pq = gQueueMan->MakeOutgoingQueue (lpszFormatName, &qp, NULL);
        }
    }

    if (p)
        *p = L';';

    if (! pq) {
        gMem->Unlock ();

        return MQ_ERROR_QUEUE_NOT_FOUND;
    }

    if (((pq->fDenyAll) && (dwAccess == MQ_RECEIVE_ACCESS)) ||
        ((pq->uiOpenRecv) && (dwShareMode == MQ_DENY_RECEIVE_SHARE)) || pq->qp.bIsInternal) {
        gMem->Unlock ();

        return MQ_ERROR_ACCESS_DENIED;
    }

    if (dwAccess == MQ_SEND_ACCESS) {
        if (pq->qp.bIsDeadLetter || pq->qp.bIsJournal || pq->qp.bIsMachineJournal || pq->qp.bIsOrderAck) {
            gMem->Unlock ();

            return MQ_ERROR_UNSUPPORTED_FORMATNAME_OPERATION;
        }

        if (! pq->qp.bIsIncoming) {
            if ( (pq->IsHttpOrHttps () && (! gMachine->fUseSRMP)) ||
                ((! pq->IsHttpOrHttps ()) && (! gMachine->fUseBinary)) ) {
                gMem->Unlock ();
                return MQ_ERROR_QUEUE_NOT_AVAILABLE;
            }
        }
    }

    ScHandleInfo sHInfo;

    sHInfo.uiHandleType       = SCQMAN_HANDLE_QUEUE;
    sHInfo.pQueue             = pq;
    sHInfo.pProcId            = scapi_GetOwnerProcId ();
    sHInfo.q.uiShareMode      = dwShareMode;
    sHInfo.q.uiAccess         = dwAccess;
    sHInfo.q.uiQueueType      = uiQueueType;

    SCHANDLE hQueue = (SCHANDLE)gQueueMan->AllocHandle (&sHInfo);

    HRESULT hr = MQ_ERROR_INSUFFICIENT_RESOURCES;
    if ((SVSHandle)hQueue != SVSUTIL_HANDLE_INVALID) {
        hr = MQ_OK;

        ScHandleInfo *pHInfo = gQueueMan->QueryHandle ((SVSHandle)hQueue);
        SVSUTIL_ASSERT_PREFAST (pHInfo);
        SVSUTIL_ASSERT((pHInfo->pQueue == pq) && (pHInfo->uiHandleType == SCQMAN_HANDLE_QUEUE));

        if (dwShareMode == MQ_DENY_RECEIVE_SHARE)
            pq->fDenyAll = TRUE;

        if (dwAccess != MQ_SEND_ACCESS)
            ++pq->uiOpenRecv;

        pq->uiOpen++;

        if (pq->qp.bIsIncoming) {
            sHInfo.uiHandleType  = SCQMAN_HANDLE_CURSOR;
            sHInfo.pQueue        = pq;
            sHInfo.pProcId       = scapi_GetOwnerProcId ();
            sHInfo.c.hQueue      = (SVSHandle)hQueue;
            sHInfo.c.pNode       = NULL;
            sHInfo.c.fPosValid   = FALSE;

            pHInfo->q.hDefaultCursor = gQueueMan->AllocHandle (&sHInfo);

            if (pHInfo->q.hDefaultCursor == SVSUTIL_HANDLE_INVALID) {
                gQueueMan->CloseHandle ((SVSHandle)hQueue);
                hr = MQ_ERROR_INSUFFICIENT_RESOURCES;
            }
        } else 
            pHInfo->q.hDefaultCursor = SVSUTIL_HANDLE_INVALID;

        if (hr == MQ_OK) {
            // This assignment does not require a try/except because 
            // the phQueue is a local stack variable of the caller, not 
            // direct ptr from PSL.
            *phQueue = hQueue;
        }
    }

    gMem->Unlock ();

    return hr;
}

HRESULT scapi_MQCloseQueue (SCHANDLE hQueue) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQCloseQueue\n");
#endif

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    HRESULT hr = MQ_OK;

    ScHandleInfo *pHInfo = gQueueMan->QueryHandle ((SVSHandle)hQueue);

    if (pHInfo && (pHInfo->uiHandleType == SCQMAN_HANDLE_QUEUE)) {
        gQueueMan->CloseAllHandles ((SVSHandle)hQueue);
        gQueueMan->CloseHandle ((SVSHandle)hQueue);
    } else
        hr = MQ_ERROR_INVALID_HANDLE;

    gMem->Unlock ();
    return hr;
}

HRESULT scapi_MQCreateCursor (SCHANDLE hQueue, SCHANDLE *phCursor) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQCreateCursor\n");
#endif

    if (! phCursor)
        return MQ_ERROR_INVALID_PARAMETER;

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    HRESULT hr = MQ_OK;

    ScHandleInfo *pHInfo = gQueueMan->QueryHandle ((SVSHandle)hQueue);

    if (pHInfo && (pHInfo->uiHandleType == SCQMAN_HANDLE_QUEUE) &&
                                    pHInfo->pQueue->qp.bIsIncoming) {
        ScHandleInfo sHInfo;
        sHInfo.uiHandleType = SCQMAN_HANDLE_CURSOR;
        sHInfo.pQueue       = pHInfo->pQueue;
        sHInfo.pProcId      = scapi_GetOwnerProcId ();
        sHInfo.c.hQueue     = (SVSHandle)hQueue;
        sHInfo.c.pNode      = NULL;
        sHInfo.c.fPosValid  = FALSE;

        SVSHandle hCursor = gQueueMan->AllocHandle (&sHInfo);

        if (hCursor == SVSUTIL_HANDLE_INVALID)
            hr = MQ_ERROR_INSUFFICIENT_RESOURCES;
        else
        {
            *phCursor = hCursor;
        }
    } else
        hr = MQ_ERROR_INVALID_HANDLE;


    gMem->Unlock ();

    return hr;
}

HRESULT scapi_MQCloseCursor (SCHANDLE hCursor) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQCloseCursor\n");
#endif

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    HRESULT hr = MQ_OK;

    ScHandleInfo *pHInfo = gQueueMan->QueryHandle ((SVSHandle)hCursor);

    if (pHInfo && (pHInfo->uiHandleType == SCQMAN_HANDLE_CURSOR))
        gQueueMan->CloseHandle ((SVSHandle)hCursor);
    else
        hr = MQ_ERROR_INVALID_HANDLE;

    gMem->Unlock ();

    return hr;
}

HRESULT scapi_MQHandleToFormatName (SCHANDLE hQueue, WCHAR *lpszFormatName, DWORD *dwNameLen) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQHandleToFormatName\n");
#endif

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    HRESULT hr = MQ_OK;

    ScHandleInfo *pHInfo = gQueueMan->QueryHandle ((SVSHandle)hQueue);

    if (pHInfo && (pHInfo->uiHandleType == SCQMAN_HANDLE_QUEUE)) {
        __try {
            ScQueue *pQueue = pHInfo->pQueue;

            int ccFormatChars = wcslen (pQueue->lpszFormatName) + 1;
            int ccAddTransact  = (! pQueue->qp.bIsIncoming) && pQueue->qp.bTransactional ? SVSUTIL_CONSTSTRLEN(L";XACTONLY") : 0;

            if ((int)*dwNameLen < ccFormatChars) {
                memcpy (lpszFormatName, pQueue->lpszFormatName, (*dwNameLen - 1) * sizeof(WCHAR));
                lpszFormatName[*dwNameLen - 1] = L'\0';

                hr = MQ_INFORMATION_FORMATNAME_BUFFER_TOO_SMALL;
            } else if ((int)*dwNameLen < ccFormatChars + ccAddTransact) {
                memcpy (lpszFormatName, pQueue->lpszFormatName, ccFormatChars * sizeof(WCHAR));
                PREFAST_SUPPRESS(12008,"ccFormatChars and ccAddTransact are always lengths of strings in memory, so they are relatively small and an integer overflow can never occur"); 
                memcpy (&lpszFormatName[ccFormatChars], L";XACTONLY", (*dwNameLen - ccFormatChars - 1) * sizeof(WCHAR));
                lpszFormatName[*dwNameLen - 1] = L'\0';

                *dwNameLen = ccFormatChars + ccAddTransact;
                hr = MQ_INFORMATION_FORMATNAME_BUFFER_TOO_SMALL;
            } else {
                memcpy (lpszFormatName, pQueue->lpszFormatName, ccFormatChars * sizeof(WCHAR));

                if (ccAddTransact)
                    memcpy (&lpszFormatName[ccFormatChars - 1], L";XACTONLY", (ccAddTransact + 1) * sizeof(WCHAR));

                *dwNameLen = ccFormatChars + ccAddTransact;
            }
        }
        __except (ReportFault(GetExceptionInformation(),0), EXCEPTION_EXECUTE_HANDLER) {
            hr = MQ_ERROR_INVALID_PARAMETER;
        }

    } else
        hr = MQ_ERROR_INVALID_HANDLE;

    gMem->Unlock ();

    return hr;
}

HRESULT scapi_MQPathNameToFormatName (const WCHAR *lpszPathName, WCHAR *lpszFormatName, DWORD *pdwCount) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQPathNameToFormatName\n");
#endif

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    __try {
        ScQueueParms qp;
        memset (&qp, 0, sizeof (qp));

        qp.bIsIncoming = TRUE;
        WCHAR *szFormatName = scutil_MakeFormatName ((WCHAR *)lpszPathName, &qp);
        if (! szFormatName)
            return MQ_ERROR_ILLEGAL_QUEUE_PATHNAME;

        unsigned int uiFormatChars = wcslen (szFormatName) + 1;

        if (*pdwCount < uiFormatChars) {
            if (lpszFormatName && *pdwCount > 0) {
                memcpy (lpszFormatName, szFormatName, (*pdwCount - 1) * sizeof(WCHAR));
                lpszFormatName[*pdwCount - 1] = L'\0';
            }

            g_funcFree (szFormatName, g_pvFreeData);
            return MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL;
        }

        if (lpszFormatName)
            memcpy (lpszFormatName, szFormatName, uiFormatChars * sizeof(WCHAR));

        *pdwCount = uiFormatChars;

        g_funcFree (szFormatName, g_pvFreeData);
    }
    __except (ReportFault(GetExceptionInformation(),0), EXCEPTION_EXECUTE_HANDLER) {
        return MQ_ERROR_INVALID_PARAMETER;
    }

    return MQ_OK;
}

// This function is called with global lock held.
static HRESULT scapi_MQSendMessage(SCHANDLE hQueue, SCPROPVAR *pMsgProps, int iTransaction) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQSendMessage\n");
#endif

    SVSUTIL_ASSERT(gMem->IsLocked());

    if (! pMsgProps)
        return MQ_ERROR_INSUFFICIENT_PROPERTIES;

    if ((NULL == pMsgProps->aPropID) || (NULL == pMsgProps->aPropVar)) {
        return MQ_ERROR_ILLEGAL_MQQUEUEPROPS;
    }

    //
    //  Construct a packet
    //
    HRESULT hRes = MQ_OK;

    if (pMsgProps->aStatus && pMsgProps->cProp > 0)
        memset (pMsgProps->aStatus, 0, sizeof (HRESULT) * pMsgProps->cProp);

    unsigned int uiAckType     = MQMSG_ACKNOWLEDGMENT_NONE;
    unsigned int uiAppSpecific = 0;
    unsigned int uiBodyType    = 0;
    unsigned int uiMsgClass    = MQMSG_CLASS_NORMAL;
    unsigned int uiDelivery    = MQMSG_DELIVERY_EXPRESS;
    unsigned int uiJournalType = MQMSG_JOURNAL_NONE;
    unsigned int uiPriority    = (iTransaction == (int)MQ_SINGLE_MESSAGE) ? 0 : 3;
    unsigned int uiTrace       = MQMSG_TRACE_NONE;

    unsigned int tTTR          = INFINITE;
    unsigned int tTRQ          = INFINITE;

    CAUB  *pcaubBody   = NULL;
    CAUB  *pcaubCorrId = NULL;
    CAUB  *pcaubExt    = NULL;

    CAPROPVARIANT *pFwdVia   = NULL;
    CAPROPVARIANT *pRevVia   = NULL;
    int iSoapFwdVia          = 0;
    int iSoapRevVia          = 0;

    WCHAR *lpszAdminQueue    = NULL;
    WCHAR *lpszLabel         = NULL;
    WCHAR *lpszResponseQueue = NULL;
    WCHAR *lpszDestQueue     = NULL;
    WCHAR *lpszSoapBody      = NULL;
    WCHAR *lpszSoapHeader    = NULL;
    WCHAR *lpszSoapEnvelope  = NULL;
    WCHAR *lpszSoapRelatesTo = NULL;
    WCHAR *lpszSoapFrom      = NULL;

    int          iMsgNdx     = -1;

    for (int i = 0 ; (! FAILED (hRes)) && (i < (int)pMsgProps->cProp) ; ++i) {
        hRes = MQ_OK;
        switch (pMsgProps->aPropID[i]) {
        case PROPID_M_ACKNOWLEDGE:
            if (pMsgProps->aPropVar[i].vt != VT_UI1)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                uiAckType = pMsgProps->aPropVar[i].bVal;
            break;

        case PROPID_M_ADMIN_QUEUE:
            if ((pMsgProps->aPropVar[i].vt != VT_LPWSTR) || (! pMsgProps->aPropVar[i].pwszVal))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                lpszAdminQueue = pMsgProps->aPropVar[i].pwszVal;
            break;

        case PROPID_M_APPSPECIFIC:
            if (pMsgProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                uiAppSpecific = pMsgProps->aPropVar[i].ulVal;
            break;

        case PROPID_M_AUTH_LEVEL:
            if (pMsgProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else if (pMsgProps->aPropVar[i].ulVal != MQMSG_AUTH_LEVEL_NONE)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            break;

        case PROPID_M_BODY:
            if ((pMsgProps->aPropVar[i].vt != (VT_VECTOR | VT_UI1)))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else if (pMsgProps->aPropVar[i].caub.cElems && pMsgProps->aPropVar[i].caub.pElems)
                pcaubBody = &pMsgProps->aPropVar[i].caub;
            break;

        case PROPID_M_BODY_TYPE:
            if (pMsgProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                uiBodyType = pMsgProps->aPropVar[i].ulVal;
            break;

        case PROPID_M_CLASS:
            if (pMsgProps->aPropVar[i].vt != VT_UI2)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                uiMsgClass = pMsgProps->aPropVar[i].uiVal;
            break;

        case PROPID_M_CORRELATIONID:
            if ((pMsgProps->aPropVar[i].vt != (VT_VECTOR | VT_UI1)) ||
                (pMsgProps->aPropVar[i].caub.cElems <= 0) ||
                (pMsgProps->aPropVar[i].caub.cElems > 20) ||
                (! pMsgProps->aPropVar[i].caub.pElems))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                pcaubCorrId = &pMsgProps->aPropVar[i].caub;
            break;

        case PROPID_M_DELIVERY:
            if ((pMsgProps->aPropVar[i].vt != VT_UI1) ||
                ((pMsgProps->aPropVar[i].bVal != MQMSG_DELIVERY_EXPRESS) &&
                (pMsgProps->aPropVar[i].bVal != MQMSG_DELIVERY_RECOVERABLE)))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                uiDelivery = pMsgProps->aPropVar[i].bVal;
            break;

        case PROPID_M_DEST_QUEUE:
            if ((pMsgProps->aPropVar[i].vt != VT_LPWSTR) || (! pMsgProps->aPropVar[i].pwszVal))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                lpszDestQueue = pMsgProps->aPropVar[i].pwszVal;
            break;

        case PROPID_M_EXTENSION:
            if ((pMsgProps->aPropVar[i].vt != (VT_VECTOR | VT_UI1)) ||
                (pMsgProps->aPropVar[i].caub.cElems <= 0) ||
                (! pMsgProps->aPropVar[i].caub.pElems))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                pcaubExt = &pMsgProps->aPropVar[i].caub;
            break;

        case PROPID_M_JOURNAL:
            if ((pMsgProps->aPropVar[i].vt != VT_UI1) ||
                (pMsgProps->aPropVar[i].bVal & (~(MQMSG_DEADLETTER | MQMSG_JOURNAL | MQMSG_JOURNAL_NONE))))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                uiJournalType = pMsgProps->aPropVar[i].bVal;
            break;

        case PROPID_M_LABEL:
            if ((pMsgProps->aPropVar[i].vt != VT_LPWSTR) || (! pMsgProps->aPropVar[i].pwszVal))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                lpszLabel = pMsgProps->aPropVar[i].pwszVal;
            break;

        case PROPID_M_PRIORITY:
            if ((pMsgProps->aPropVar[i].vt != VT_UI1) || (pMsgProps->aPropVar[i].bVal > 7))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                uiPriority = pMsgProps->aPropVar[i].bVal;
            break;

        case PROPID_M_RESP_QUEUE:
            if ((pMsgProps->aPropVar[i].vt != VT_LPWSTR) || (! pMsgProps->aPropVar[i].pwszVal))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                lpszResponseQueue = pMsgProps->aPropVar[i].pwszVal;
            break;

        case PROPID_M_TIME_TO_BE_RECEIVED:
            if (pMsgProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                tTTR = pMsgProps->aPropVar[i].ulVal;
            break;

        case PROPID_M_TIME_TO_REACH_QUEUE:
            if (pMsgProps->aPropVar[i].vt != VT_UI4)
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                tTRQ = pMsgProps->aPropVar[i].ulVal;
            break;

        case PROPID_M_TRACE:
            if ((pMsgProps->aPropVar[i].vt != VT_UI1) ||
                ((pMsgProps->aPropVar[i].bVal != MQMSG_SEND_ROUTE_TO_REPORT_QUEUE) &&
                (pMsgProps->aPropVar[i].bVal != MQMSG_TRACE_NONE)))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                uiTrace = pMsgProps->aPropVar[i].bVal;
            break;

        case PROPID_M_MSGID:
            if ((pMsgProps->aPropVar[i].vt != (VT_VECTOR | VT_UI1)) ||
                (pMsgProps->aPropVar[i].caub.cElems <= 0) ||
                (pMsgProps->aPropVar[i].caub.cElems > 20) ||
                (! pMsgProps->aPropVar[i].caub.pElems))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else {
                iMsgNdx = i;
            }   
            break;

        case PROPID_M_BODY_SIZE:
        case PROPID_M_EXTENSION_LEN:
        case PROPID_M_SENDERID_LEN:
        case PROPID_M_SENDERID_TYPE:
        case PROPID_M_SENDERID:
            hRes = MQ_INFORMATION_PROPERTY_IGNORED;
            break;


        case PROPID_M_SOAP_HEADER:
            if ((pMsgProps->aPropVar[i].vt != VT_LPWSTR))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                lpszSoapHeader = pMsgProps->aPropVar[i].pwszVal;
            break;

        case PROPID_M_SOAP_BODY:
            if ((pMsgProps->aPropVar[i].vt != VT_LPWSTR))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                lpszSoapBody = pMsgProps->aPropVar[i].pwszVal;
            break;

        case PROPID_M_SOAP_FWD_VIA:
            if ((pMsgProps->aPropVar[i].vt != (VT_VECTOR | VT_VARIANT)))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;

            if (hRes != MQ_OK)
                break;

            pFwdVia = &pMsgProps->aPropVar[i].capropvar;

            if (hRes == ERROR_SUCCESS) {
                if (0 == (iSoapFwdVia = CalcFwdRevViaSectionSize(pFwdVia)))
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            }

            break;

        case PROPID_M_SOAP_REV_VIA:
            if ((pMsgProps->aPropVar[i].vt != (VT_VECTOR | VT_VARIANT)))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;

            if (hRes != MQ_OK)
                break;

            pRevVia = &pMsgProps->aPropVar[i].capropvar;

            if (hRes == ERROR_SUCCESS) {
                if (0 == (iSoapRevVia = CalcFwdRevViaSectionSize(pRevVia)))
                    hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            }

            break;

        case PROPID_M_SOAP_FROM:
            if ((pMsgProps->aPropVar[i].vt != VT_LPWSTR))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                lpszSoapFrom = pMsgProps->aPropVar[i].pwszVal;
            break;

        case PROPID_M_SOAP_RELATES_TO:
            if ((pMsgProps->aPropVar[i].vt != VT_LPWSTR))
                hRes = MQ_ERROR_ILLEGAL_PROPERTY_VALUE;
            else
                lpszSoapRelatesTo = pMsgProps->aPropVar[i].pwszVal;
            break;

        case PROPID_M_LABEL_LEN:
        case PROPID_M_RESP_QUEUE_LEN:
        case PROPID_M_DEST_QUEUE_LEN:
        case PROPID_M_ADMIN_QUEUE_LEN:
            // In case a user wants to forward on a message they have received
            // that may have these values set, silently ignore them.
            break;

        case PROPID_M_XACT_STATUS_QUEUE:
        case PROPID_M_XACT_STATUS_QUEUE_LEN:
        case PROPID_M_VERSION:
        case PROPID_M_SRC_MACHINE_ID:
        case PROPID_M_SIGNATURE:
        case PROPID_M_SIGNATURE_LEN:
        case PROPID_M_SENTTIME:
        case PROPID_M_SENDER_CERT_LEN:
        case PROPID_M_SENDER_CERT:
        case PROPID_M_SECURITY_CONTEXT:
        case PROPID_M_PROV_TYPE:
        case PROPID_M_PROV_NAME_LEN:
        case PROPID_M_PROV_NAME:
        case PROPID_M_PRIV_LEVEL:
        case PROPID_M_HASH_ALG:
        case PROPID_M_ENCRYPTION_ALG:
        case PROPID_M_DEST_SYMM_KEY:
        case PROPID_M_DEST_SYMM_KEY_LEN:
        case PROPID_M_CONNECTOR_TYPE:
        case PROPID_M_AUTHENTICATED:
        case PROPID_M_ARRIVEDTIME:
        default:
            hRes = MQ_ERROR_PROPERTY;

        }

        if (pMsgProps->aStatus)
            pMsgProps->aStatus[i] = hRes;
    }

    if (FAILED(hRes))
        return hRes;

    if (lpszLabel && (wcslen (lpszLabel) > MQ_MAX_MSG_LABEL_LEN))
        return MQ_ERROR_LABEL_TOO_LONG;

    if (tTTR < tTRQ)
        tTRQ = tTTR;

    if ((tTRQ != INFINITE) && (tTTR != INFINITE))
        tTTR -= tTRQ;

    //
    //  Parameters parsed. Check the validity...
    //
    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    if ((! gMachine->fUseSRMP) &&
        (lpszSoapHeader || lpszSoapBody || pFwdVia || pRevVia || lpszSoapFrom || lpszSoapRelatesTo)) {
        return MQ_INFORMATION_UNSUPPORTED_PROPERTY;
    }

    ScHandleInfo *pHInfo = gQueueMan->QueryHandle ((SVSHandle)hQueue);

    if ((! pHInfo) || (pHInfo->uiHandleType != SCQMAN_HANDLE_QUEUE)) {
        return MQ_ERROR_INVALID_HANDLE;
    }

    if (pHInfo->q.uiAccess != MQ_SEND_ACCESS) {
        return MQ_ERROR_INVALID_HANDLE;
    }

    ScQueue *pQueue = pHInfo->pQueue;
    int fHttp       = pQueue->IsHttpOrHttps();
    int fUseSoap    = (lpszSoapHeader || lpszSoapBody);

    if (pQueue->qp.bTransactional) {
        uiDelivery = MQMSG_DELIVERY_RECOVERABLE;

        if (iTransaction != (int)MQ_SINGLE_MESSAGE)
            hRes = MQ_ERROR_TRANSACTION_USAGE;
    } else if (iTransaction)
        hRes = MQ_ERROR_TRANSACTION_USAGE;
    else if (!fHttp && fUseSoap)
        hRes = MQ_ERROR_ILLEGAL_PROPID;  // A soap header has been sent but we're not sending to an HTTP queue

    if (FAILED(hRes)) {
        return hRes;
    }

    unsigned int uiMsgId = gQueueMan->GetNextID();

    //
    //  Compute the size and alloc the buffer...
    //
    //  No - Xact header
    //  No - Security header
    //  No - Session section (added by session layer)
    //
    QUEUE_FORMAT qfDest;
    QUEUE_FORMAT qfAdmin;
    QUEUE_FORMAT qfResp;
    QUEUE_FORMAT qfDebug;

    if ((pQueue != gQueueMan->pQueueOutFRS && !fHttp) || (! lpszDestQueue))
        lpszDestQueue = pQueue->lpszFormatName;

    if ((! scutil_StringToQF (&qfDest, lpszDestQueue)) ||
        (lpszAdminQueue && (! scutil_StringToQF (&qfAdmin, lpszAdminQueue))) ||
        (lpszResponseQueue && (! scutil_StringToQF (&qfResp,  lpszResponseQueue))) ||
        (gMachine->lpszDebugQueueFormatName && (! scutil_StringToQF (&qfDebug, gMachine->lpszDebugQueueFormatName)))) {

        return MQ_ERROR;
    }

    int iHeaderSize = CBaseHeader::CalcSectionSize ();
    int iUserSize   = CUserHeader::CalcSectionSize (NULL, NULL, NULL,
                                &qfDest, lpszAdminQueue ? &qfAdmin : NULL,
                                lpszResponseQueue ? &qfResp : NULL);
    int iPropSize   = CPropertyHeader::CalcSectionSize (lpszLabel ? wcslen(lpszLabel) + 1 : 0,
                                pcaubExt ? pcaubExt->cElems : 0,
                                pcaubBody ? pcaubBody->cElems : 0);
    int iDebugSize  = gMachine->lpszDebugQueueFormatName &&
                        (uiTrace == MQMSG_SEND_ROUTE_TO_REPORT_QUEUE) ?
                                    CDebugSection::CalcSectionSize (&qfDebug) : 0;
    int iXactSize   = (! pQueue->qp.bIsIncoming) && pQueue->qp.bTransactional ? CXactHeader::CalcSectionSize((void *)0xffffffff, NULL): 0;

    int iSoapHeader   = fUseSoap   ? CSoapSection::CalcSectionSize(lpszSoapHeader ? wcslen(lpszSoapHeader) : 0) : 0;
    int iSoapBody     = fUseSoap   ? CSoapSection::CalcSectionSize(lpszSoapBody   ? wcslen(lpszSoapBody)   : 0) : 0;

    int ccFrom        = lpszSoapFrom      ? wcslen(lpszSoapFrom) : 0;
    int ccRelatesTo   = lpszSoapRelatesTo ? wcslen(lpszSoapRelatesTo) : 0;
    int iSoapExt      = (lpszSoapRelatesTo || lpszSoapFrom) ? CSoapExtSection::CalcSectionSize(ccFrom, ccRelatesTo) : 0;

    unsigned int uiBaseSize = iHeaderSize + iUserSize + iPropSize + iDebugSize + iXactSize + iSoapHeader + iSoapBody;
    unsigned int uiPacketSize = uiBaseSize + iSoapFwdVia + iSoapRevVia + iSoapExt; // include base + ext size

    if (sizeof(ScPacketImage) + uiPacketSize < uiPacketSize){
        return MQ_ERROR_BUFFER_OVERFLOW;
    }
    
    ScPacketImage *pPacketImage = (ScPacketImage *)g_funcAlloc (sizeof(ScPacketImage) + uiPacketSize, g_pvAllocData);

    if (! pPacketImage) {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }

    void *pvPacketBuffer = (void *)((unsigned char *)pPacketImage + sizeof(ScPacketImage));
    memset (&pPacketImage->sect, 0, sizeof (pPacketImage->sect));
    memset (&pPacketImage->ucSourceAddr, 0, sizeof(pPacketImage->ucSourceAddr));

    pPacketImage->allflags = 0;
    pPacketImage->pvBinary = NULL;
    pPacketImage->pvExt    = NULL;

    pPacketImage->hkOrderKey = ++pQueue->hkReceived;
    if (! pQueue->qp.bTransactional)
        pPacketImage->hkOrderKey |= (uiPriority ^ MQ_MAX_PRIORITY) << SCPACKET_ORD_TIMEBITS;

    pPacketImage->flags.fSecureSession = TRUE;

    CBaseHeader *pBaseHeader = (CBaseHeader *)pvPacketBuffer;
    pBaseHeader->CBaseHeader::CBaseHeader (uiBaseSize);
    pBaseHeader->SetPriority (uiPriority);
    pBaseHeader->IncludeDebug (iDebugSize > 0);
    pBaseHeader->SetTrace (uiTrace);
    pBaseHeader->SetAbsoluteTimeToQueue (tTRQ);

    CUserHeader *pUserHeader = (CUserHeader *)pBaseHeader->GetNextSection ();

    GUID nullGuid;
    memset (&nullGuid, 0, sizeof(nullGuid));

    pUserHeader->CUserHeader::CUserHeader (&gMachine->guid, &nullGuid, &qfDest,
                                lpszAdminQueue ? &qfAdmin : NULL, lpszResponseQueue ? &qfResp : NULL, uiMsgId);

    pUserHeader->SetTimeToLiveDelta (tTTR);
    pUserHeader->SetSentTime (scutil_now());
    pUserHeader->SetDelivery (uiDelivery);
    pUserHeader->IncludeProperty (TRUE);
    pUserHeader->SetAuditing (uiJournalType);

    CPropertyHeader *pPropHeader;
    if (iXactSize) {
        pUserHeader->IncludeXact(TRUE);
        CXactHeader *pXactHeader = (CXactHeader *)pUserHeader->GetNextSection ();
        pXactHeader->CXactHeader::CXactHeader (NULL);
        pXactHeader->SetSeqID (pQueue->llSeqID);
        pXactHeader->SetSeqN (++pQueue->uiSeqNum);

        pPropHeader = (CPropertyHeader *)pXactHeader->GetNextSection ();
    } else
        pPropHeader = (CPropertyHeader *)pUserHeader->GetNextSection ();

    pPropHeader->CPropertyHeader::CPropertyHeader ();

    pPropHeader->SetAckType (uiAckType);

    pPropHeader->SetClass (uiMsgClass);

    if (pcaubCorrId)
        pPropHeader->SetCorrelationID (pcaubCorrId->pElems);

    pPropHeader->SetApplicationTag (uiAppSpecific);

    if (lpszLabel)
        pPropHeader->SetTitle (lpszLabel, wcslen (lpszLabel) + 1);

    if (pcaubExt)
        pPropHeader->SetMsgExtension (pcaubExt->pElems, pcaubExt->cElems);

    if (pcaubBody)
        pPropHeader->SetBody (pcaubBody->pElems, pcaubBody->cElems, pcaubBody->cElems);

    pPropHeader->SetBodyType (uiBodyType);
    pPropHeader->SetPrivLevel (MQMSG_PRIV_LEVEL_NONE);
    pPropHeader->SetHashAlg (0);
    pPropHeader->SetEncryptAlg (0);

    PVOID pNextSection = (PVOID) pPropHeader->GetNextSection ();

    if (iDebugSize > 0) {
        CDebugSection *pDebugSec = (CDebugSection *)pNextSection;
        pDebugSec->CDebugSection::CDebugSection (&qfDebug);
        pNextSection = (PVOID) pDebugSec->GetNextSection();
    }

    // Soap elements
    if (fUseSoap) {
        const USHORT x_SOAP_HEADER_SECTION_ID = 800;
        const USHORT x_SOAP_BODY_SECTION_ID = 900;
        pUserHeader->IncludeSoap(TRUE);

        CSoapSection *pSoapHeader = (CSoapSection *) pNextSection;
        pSoapHeader->CSoapSection::CSoapSection(lpszSoapHeader,lpszSoapHeader ? wcslen(lpszSoapHeader) : 0,x_SOAP_HEADER_SECTION_ID);

        CSoapSection *pSoapBody = (CSoapSection*) pSoapHeader->GetNextSection();
        pSoapBody->CSoapSection::CSoapSection(lpszSoapBody,lpszSoapBody ? wcslen(lpszSoapBody) : 0,x_SOAP_BODY_SECTION_ID);
        pNextSection = (PVOID) pSoapBody->GetNextSection();
    }

    if (pFwdVia) {
        pPacketImage->flags.fFwdIncluded = TRUE;
        CDataHeader *pFwd = (CDataHeader*) pNextSection;
        WCHAR *szTrav = (WCHAR*)pFwd->GetData();
        
        for (i = 0; i < (int) pFwdVia->cElems; ++i) {
            PROPVARIANT *pVar = &pFwdVia->pElems[i];
            if (pVar==NULL) {
                return MQ_ERROR_INVALID_PARAMETER;
            }

            unsigned int uiLen = wcslen(pVar->pwszVal)+1;
            memcpy(szTrav,pVar->pwszVal,uiLen*2);
            szTrav += uiLen;
        }
        pFwd->SetDataLengthInWCHARs(szTrav - (WCHAR*)pFwd->GetData());
        pNextSection = (PVOID) pFwd->GetNextSection();
    }

    if (pRevVia) {
        pPacketImage->flags.fRevIncluded = TRUE;
        CDataHeader *pRev = (CDataHeader*) pNextSection;
        WCHAR *szTrav = (WCHAR*) pRev->GetData();

        for (i = 0; i < (int) pRevVia->cElems; ++i) {
            PROPVARIANT *pVar = &pRevVia->pElems[i];
            if (pVar==NULL) {
                return MQ_ERROR_INVALID_PARAMETER;
            }

            unsigned int uiLen = wcslen(pVar->pwszVal)+1;
            memcpy(szTrav,pVar->pwszVal,uiLen*2);
            szTrav += uiLen;
        }
        pRev->SetDataLengthInWCHARs(szTrav - (WCHAR*)pRev->GetData());
        pNextSection = (PVOID) pRev->GetNextSection();
    }

    if (lpszSoapRelatesTo || lpszSoapFrom) {
        pPacketImage->flags.fSoapExtIncluded = TRUE;
        CSoapExtSection *pSoapExt = (CSoapExtSection*) pNextSection;
        
        pSoapExt->CSoapExtSection::CSoapExtSection(lpszSoapFrom,ccFrom,lpszSoapRelatesTo,ccRelatesTo);
        pNextSection = (PVOID) pSoapExt->GetNextSection();
    }

    if (! pPacketImage->PopulateSections ()) {
        g_funcFree (pPacketImage, g_pvFreeData);
        return MQ_ERROR;
    }

    if ((! pQueue->qp.bIsIncoming) && (! pQueue->qp.bIsOutFRS)) {
        ScQueue *pQueueDest = gQueueMan->FindQueueByPacketImage (pPacketImage, FALSE);

        if (pQueueDest)
            pQueue = pQueueDest;
    }

    ScPacket *pPacket = pQueue->MakePacket (pPacketImage, -1, TRUE);
    if (! pPacket) {
        g_funcFree (pPacketImage, g_pvFreeData);
        hRes = MQ_ERROR_INSUFFICIENT_RESOURCES;
    } else if (pQueue->qp.bIsIncoming) {
        //
        // Packet is only journalled when send is non-local
        //
        gQueueMan->AcceptPacket (pPacket, MQMSG_CLASS_ACK_REACH_QUEUE, pQueue);
    }

    if ((! FAILED(hRes)) && (iMsgNdx >= 0)) {
        // PROPID_M_MSGID is the one parameter that is an output -- write
        // this data back to caller process.
        CMarshallDataToProcess copyData((HANDLE)GetCallerVMProcessId());
        OBJECTID objectId;
        HRESULT hRes2;

        // This points to unmarshalled pointer in caller process.
        UCHAR *pMsgID = pMsgProps->aPropVar[iMsgNdx].caub.pElems;

        objectId.Lineage = gMachine->guid;
        objectId.Uniquifier = uiMsgId;
        copyData.WriteBufToProc(pMsgID, (UCHAR*)&objectId, sizeof(objectId), &hRes2);

        if (pMsgProps->aStatus)
            pMsgProps->aStatus[iMsgNdx] = hRes2;
    }

    return hRes;
}


HRESULT scapi_MQReceiveMessage
(
SCHANDLE            hQueue,
DWORD               dwTimeout,
DWORD               dwAction,
SCPROPVAR           *pMsgPropsUnmarshalled,
OVERLAPPED          *lpOverlapped,
SCHANDLE            hCursor,
int                 iNull3
) {
#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_API, L"Entered MQReceiveMessage\n");
#endif
    if (iNull3 != 0)
        return MQ_ERROR_TRANSACTION_USAGE;

    if ((dwAction != MQ_ACTION_RECEIVE) && (dwAction != MQ_ACTION_PEEK_CURRENT) && (dwAction != MQ_ACTION_PEEK_NEXT))
        return MQ_ERROR_ILLEGAL_CURSOR_ACTION;

    if ((! hCursor) && (dwAction == MQ_ACTION_PEEK_NEXT))
        return MQ_ERROR_ILLEGAL_CURSOR_ACTION;

    if (! fApiInitialized)
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;

    HANDLE hCallerProc = (HANDLE)GetCallerVMProcessId();

    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    ScPacket     *pPacket    = NULL;
    ScQueue      *pQueue     = NULL;
    ScHandleInfo *pHInfo     = NULL;

    HRESULT hr = scapi_GetPacket (hQueue, hCursor, dwAction, pPacket, pQueue, pHInfo);

    if (hr != MQ_OK) {
        gMem->Unlock ();

        SVSUTIL_ASSERT ((! pHInfo));
        SVSUTIL_ASSERT ((! pPacket));
        SVSUTIL_ASSERT ((! pQueue));
        return hr;
    }

    SVSUTIL_ASSERT_PREFAST (pQueue);

    ce::copy_in<SCPROPVAR*> *pMsgProps = new ce::copy_in<SCPROPVAR*>(hCallerProc);
    if (! pMsgProps) {
        gMem->Unlock ();
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }

    // This class takes care of marshalling PROPVARS, as needed.
    pMsgProps->EnableCopyOutPropVar();
    pMsgProps->copy_arg_in(pMsgPropsUnmarshalled);
    if (! pMsgProps->IsInited()) {
        delete pMsgProps;
        gMem->Unlock ();
        return MQ_ERROR_INVALID_PARAMETER;
    }

    CMarshalOverlapped *pMarshalOverlapped = NULL;
    if (lpOverlapped) {
        pMarshalOverlapped = new CMarshalOverlapped(lpOverlapped,hCallerProc);
        if (! pMarshalOverlapped || !pMarshalOverlapped->IsInited()) {
            if (pMarshalOverlapped)
                delete pMarshalOverlapped;

            delete pMsgProps;
            gMem->Unlock();
            return MQ_ERROR_INSUFFICIENT_RESOURCES;
        }
    }

    if (pPacket) {
        SVSUTIL_ASSERT (pHInfo);

        __try {
            hr = scapi_RetrievePacketInfo (pPacket, pQueue, pHInfo, dwAction, pMsgProps, hCallerProc);
        }
        __except (ReportFault(GetExceptionInformation(),0), EXCEPTION_EXECUTE_HANDLER) { 
            hr = MQ_ERROR_INVALID_PARAMETER;
        }

        gMem->Unlock ();

        if (pMarshalOverlapped) {
            pMarshalOverlapped->SetOverlappedEvent();
            pMarshalOverlapped->SetStatus(hr);
            delete pMarshalOverlapped;
        }

        delete pMsgProps;
        return hr;
    }

#if defined (SC_VERBOSE)
    scerror_DebugOut (VERBOSE_MASK_IO, L"Waiting for message in the queue %s for %d ms.\n", pQueue->lpszFormatName, dwTimeout);
#endif

    HANDLE hQueueEvent = pQueue->hUpdateEvent;

    gMem->Unlock ();

    if (dwTimeout == 0) {
        if (pMarshalOverlapped)
            delete pMarshalOverlapped;
        delete pMsgProps;
        return MQ_ERROR_IO_TIMEOUT;
    }

    if (lpOverlapped) {
        SVSUTIL_ASSERT(pMarshalOverlapped);
        // Do NOT free pMarshalOverlapped or pMsgProps here - caller will take care of it.
        return gOverlappedSupport->EnterOverlappedReceive (hQueueEvent,NULL,
                    hCallerProc, NULL,pMarshalOverlapped, hQueue, hCursor, 
                    dwTimeout, dwAction, pMsgProps);
    }
    SVSUTIL_ASSERT(!pMarshalOverlapped);

    HANDLE hWaitEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
    if (hWaitEvent == NULL)
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    
    HRESULT hr2;
    hr = gOverlappedSupport->EnterOverlappedReceive (hQueueEvent, hWaitEvent,
            hCallerProc, (DWORD*)&hr2, NULL, hQueue,
            hCursor, dwTimeout, dwAction, pMsgProps);

    if (hr == MQ_INFORMATION_OPERATION_PENDING) {
        if (WaitForSingleObject (hWaitEvent, INFINITE) != WAIT_OBJECT_0)
            hr = MQ_ERROR_OPERATION_CANCELLED;
        else
            hr = hr2;
    }

    CloseHandle (hWaitEvent);
    delete pMsgProps;
    return hr;
}


void scapi_ProcExit (void *pvProcIdent) {
    if (pvProcIdent) {
        if (! fApiInitialized)
            return;

        gMem->Lock ();

        if (fApiInitialized)
            gQueueMan->CloseProcHandles (pvProcIdent);

        gMem->remoteAlloc.DeInitForProcess();

        gMem->Unlock ();
    }
}

//////////////////////////////////////////////////////////////////////
//
//
//  Overlapped support section
//
//
//////////////////////////////////////////////////////////////////////
void CloseOverlappedHandle (SVSHandle h) {
    gOverlappedSupport->CloseHandle (h);
}

void ScOverlappedSupport::CloseHandle (SCHANDLE h) {
    SVSUTIL_ASSERT (gMem->IsLocked ());

    for (int i = 0 ; i < iNumPendingRequests ; ++i) {
        ScIoRequest *pReq = apPendingRequests[i];
        while (pReq) {
            ScIoRequest *pNext = pReq->pNext;
            if ((pReq->hCursor == h) || (pReq->hQueue == h)) {
#if defined (SC_VERBOSE)
                scerror_DebugOut (VERBOSE_MASK_IO, L"Handle closed: cancel overlapped read request for queue handle %08x\n\texpiration time %08x action %08x properties ptr %08x\n\tevent %08x cursor handle %08x\n",
                    pReq->hQueue, pReq->tExpirationTicks, pReq->dwAction, pReq->pMsgProps, pReq->hEvent, pReq->hCursor);
#endif

                //
                //  If this is the last one, the index will be compressed - need to rescan the position
                //
                if (apPendingRequests[i]->pNext == NULL)
                    --i;

                Deregister (pReq, MQ_ERROR_OPERATION_CANCELLED);
            }
            pReq = pNext;
        }
    }
}

void ScOverlappedSupport::SelfDestruct (void) {
    SVSUTIL_ASSERT (gMem->IsLocked ());

    if (hThread)
        TerminateThread (hThread, 0);

    if (ahQueueEvents[0])
        ::CloseHandle (ahQueueEvents[0]);

    if (pTimeTree)
        delete pTimeTree;

    for (int i = 0 ; i < iNumPendingRequests ; ++i) {
        ScIoRequest *pReq = apPendingRequests[i];
        while (pReq) {
#if defined (SC_VERBOSE)
            scerror_DebugOut (VERBOSE_MASK_IO, L"Cancelled overlapped read request for queue handle %08x\n\texpiration time %08x action %08x properties ptr %08x\n\tevent %08x cursor handle %08x\n",
                    pReq->hQueue, pReq->tExpirationTicks, pReq->dwAction, pReq->pMsgProps, pReq->hEvent, pReq->hCursor);
#endif

            ScIoRequest *pNext = pReq->pNext;
            pReq->SetStatusAndEvent(MQ_ERROR_OPERATION_CANCELLED);
            delete pReq;
            pReq = pNext;
        }
    }
}

void ScOverlappedSupport::CompressIndex (int iNdx) {
    SVSUTIL_ASSERT (gMem->IsLocked ());
    //
    //  We need to
    //      1) move arrays one position forward, and
    //      2) change indices of all moved items.
    //
    for (int i = iNdx + 1 ; i < iNumPendingRequests ; ++i) {
        pahQueueEvents[i-1] = pahQueueEvents[i];

        ScIoRequest *pIO = apPendingRequests[i];
        apPendingRequests[i-1] = pIO;
        SVSUTIL_ASSERT (pIO);
        while (pIO) {
            SVSUTIL_ASSERT (pIO->iNdx == i);
            pIO->iNdx = i - 1;
            pIO = pIO->pNext;
        }
    }

    --iNumPendingRequests;
}

void ScOverlappedSupport::Deregister (ScIoRequest *pRequest, HRESULT hr) {
    pRequest->SetStatusAndEvent(hr);

    if (pRequest->pNode) {
        SVSUTIL_ASSERT (gMem->IsLocked ());
        pTimeTree->Delete (pRequest->pNode);
    }

    if (pRequest->iNdx >= 0) {
        SVSUTIL_ASSERT (gMem->IsLocked ());
        ScIoRequest *pParent = NULL;
        ScIoRequest *pRunner = apPendingRequests[pRequest->iNdx];
        while (pRunner) {
            if (pRunner == pRequest) {
                if (! pParent) {
                    if (! pRequest->pNext) {    // Compress the array...
                        CompressIndex (pRequest->iNdx);
                    } else
                        apPendingRequests[pRequest->iNdx] = pRequest->pNext;
                } else
                    pParent->pNext = pRequest->pNext;
                break;
            }
            pParent = pRunner;
            pRunner = pRunner->pNext;
        }
    }

    delete pRequest;
}

static ScIoRequest *scapi_ReverseReqList (ScIoRequest *pReqList) {
    ScIoRequest *pNewHead = NULL;
    while (pReqList) {
        ScIoRequest *pNext = pReqList->pNext;

        pReqList->pNext = pNewHead;
        pNewHead = pReqList;

        pReqList = pNext;
    }

    return pNewHead;
}

void ScOverlappedSupport::OverlappedSupportThread(void) {
    gMem->Lock ();

    SVSUTIL_ASSERT (! fBusy);
    SVSUTIL_ASSERT (iNumPendingRequests > 0);

    for ( ; ; ) {
        DWORD dwTimeout = INFINITE;
        unsigned int    uiS;
        unsigned int    uiMS;
        svsutil_GetAbsTime (&uiS, &uiMS);

        SVSTNode *pNode = pTimeTree->Min ();

        while (pNode) {
            SVSTNode *pNextNode = pTimeTree->Next (pNode);

            ScIoRequest *pReq = (ScIoRequest *)SVSTree::GetData (pNode);
            if ((pReq->tExpirationS > uiS) || ((pReq->tExpirationS == uiS) && (pReq->tExpirationMS > uiMS))) {
                DWORD dwTimeout2 = (pReq->tExpirationS - uiS) * 1000 + (pReq->tExpirationMS - uiMS);

                if ((dwTimeout == INFINITE) || (dwTimeout > dwTimeout2))
                    dwTimeout = dwTimeout2;

                if (pReq->tExpirationS > uiS + 1)
                    break;
            } else {
                //
                //  Wait expired here...
                //
#if defined (SC_VERBOSE)
                scerror_DebugOut (VERBOSE_MASK_IO, L"Expired overlapped read request for queue handle %08x\n\texpiration time %08x action %08x properties ptr %08x\n\tevent %08x cursor handle %08x\n",
                    pReq->hQueue, pReq->tExpirationTicks, pReq->dwAction, pReq->pMsgProps, pReq->hEvent, pReq->hCursor);
#endif
                Deregister (pReq, MQ_ERROR_IO_TIMEOUT);
            }

            pNode = pNextNode;
        }

        DWORD dwRes;

        if (iNumPendingRequests <= 0) {
            gMem->Unlock ();
            dwRes = WaitForSingleObject (ahQueueEvents[0], SC_OVER_THREAD_TIMEOUT);
            gMem->Lock ();

            if ((iNumPendingRequests > 0) || (dwRes == WAIT_OBJECT_0))
                continue;

            break;
        }

        int      iNum = iNumPendingRequests + 1;

        gMem->Unlock ();
        dwRes = WaitForMultipleObjects (iNum, ahQueueEvents, FALSE, dwTimeout);
        gMem->Lock ();

        if (dwRes == WAIT_OBJECT_0) // Just refresh
            continue;

        //
        //  Someone signalled?
        //
        if ((dwRes >= (WAIT_OBJECT_0 + 1)) && (dwRes <= (DWORD)(WAIT_OBJECT_0 + iNumPendingRequests))) {
            int iNdx = dwRes - WAIT_OBJECT_0 - 1;
            ScIoRequest *pReq = apPendingRequests[iNdx];
            CompressIndex (iNdx);

            ScIoRequest *pReqSav = pReq;

            while (pReq) {
                pTimeTree->Delete (pReq->pNode);

                pReq->iNdx  = -1;
                pReq->pNode = NULL;
                pReq = pReq->pNext;
            }

            pReq = scapi_ReverseReqList (pReqSav);

            fBusy++;
            gMem->Unlock ();

            DWORD dwNow = GetTickCount ();

            while (pReq) {
                ScIoRequest *pNext = pReq->pNext;
                DWORD dwCallTimeout = INFINITE;

#if defined (SC_VERBOSE)
                scerror_DebugOut (VERBOSE_MASK_IO, L"At %08x : Processing overlapped read request for queue handle %08x\n\texpiration time %08x action %08x properties ptr %08x\n\tevent %08x cursor handle %08x\n",
                    dwNow , pReq->hQueue, pReq->tExpirationTicks, pReq->dwAction, pReq->pMsgProps, pReq->hEvent, pReq->hCursor);
#endif
                if (pReq->dwTimeout == INFINITE)
                    dwCallTimeout = INFINITE;
                else if (time_greater (pReq->tExpirationTicks, dwNow))
                    dwCallTimeout = pReq->tExpirationTicks - dwNow;
                else
                    dwCallTimeout = 0;

                HRESULT hr = scapi_MQReceiveMessageI (pReq);

                if (hr != MQ_INFORMATION_OPERATION_PENDING) {
#if defined (SC_VERBOSE)
                    scerror_DebugOut (VERBOSE_MASK_IO, L"Overlapped I/O call result %08x\n", hr);
#endif
                    Deregister (pReq, hr);
                }

                pReq = pNext;
            }

            gMem->Lock ();
            fBusy--;
        }

        //
        //  Someone abandoned?
        //
        if ((dwRes >= (WAIT_ABANDONED_0 + 1)) && (dwRes <= (DWORD)(WAIT_ABANDONED_0 + iNumPendingRequests))) {
            int iNdx = dwRes - WAIT_ABANDONED_0 - 1;
            ScIoRequest *pReq = apPendingRequests[iNdx];
            CompressIndex (iNdx);
            while (pReq) {
#if defined (SC_VERBOSE)
                scerror_DebugOut (VERBOSE_MASK_IO, L"Abandoned overlapped read request for queue handle %08x\n\texpiration time %08x action %08x properties ptr %08x\n\tevent %08x cursor handle %08x\n",
                    pReq->hQueue, pReq->tExpirationTicks, pReq->dwAction, pReq->pMsgProps, pReq->hEvent, pReq->hCursor);
#endif
                ScIoRequest *pNext = pReq->pNext;
                pReq->iNdx = -1;
                Deregister (pReq, MQ_ERROR_OPERATION_CANCELLED);
                pReq = pNext;
            }
        }
    }

    SVSUTIL_ASSERT (gMem->IsLocked ());
    SVSUTIL_ASSERT (iNumPendingRequests == 0);
    SVSUTIL_ASSERT (! fBusy);

    hThread = NULL;

    gMem->Unlock ();
}

DWORD WINAPI ScOverlappedSupport::OverlappedSupportThread_s (void *pvParam) {
    ScOverlappedSupport *pOS = (ScOverlappedSupport *)pvParam;
    pOS->OverlappedSupportThread ();

    return 0;
}

HRESULT ScOverlappedSupport::EnterOverlappedReceive
(
HANDLE              hQueueEvent,
HANDLE              hWaitEvent,
HANDLE              hCallerProc,
DWORD               *pdwStatus,
CMarshalOverlapped  *pOverlapped,
SCHANDLE            hQueue,
SCHANDLE            hCursor,
DWORD               dwTimeout,
DWORD               dwAction,
ce::copy_in<SCPROPVAR*> *pMsgProps
) {
    if (hWaitEvent && (! ResetEvent (hWaitEvent)))
        return MQ_ERROR_INVALID_HANDLE;

    HRESULT hr = MQ_INFORMATION_OPERATION_PENDING;
    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    int iNdx = -1;
    for (int i = 0 ; i < iNumPendingRequests ; ++i) {
        if (pahQueueEvents[i] == hQueueEvent) {
            iNdx = i;
            break;
        }
    }

    if ((iNdx < 0) && (iNumPendingRequests < (MAXIMUM_WAIT_OBJECTS - 1))) {
        iNdx = iNumPendingRequests;
        apPendingRequests[iNdx] = NULL;
    }

    if (iNdx >= 0) {
        ScIoRequest *pIO = new ScIoRequest(hWaitEvent, hCallerProc, pdwStatus, pOverlapped, hQueue, hCursor, dwTimeout, dwAction, pMsgProps);
        if (pIO) {
            pIO->pNode = pTimeTree->Insert (pIO->tExpirationS, pIO);
            if (pIO->pNode) {
                pIO->pNext = apPendingRequests[iNdx];

                apPendingRequests[iNdx] = pIO;
                pahQueueEvents[iNdx]    = hQueueEvent;

                pIO->iNdx = iNdx;

                if (iNdx == iNumPendingRequests)
                    ++iNumPendingRequests;

#if defined (SC_VERBOSE)
                scerror_DebugOut (VERBOSE_MASK_IO, L"Entering async read request for queue handle %08x\n\texpiration time %08x action %08x properties ptr %08x\n\tevent %08x cursor handle %08x\n",
                    pIO->hQueue, pIO->tExpirationTicks, pIO->dwAction, pIO->pMsgProps, pIO->hEvent, pIO->hCursor);
#endif
                SpinThread ();
            } else {
                delete pIO;
                hr = MQ_ERROR_INSUFFICIENT_RESOURCES;
            }
        } else
            hr = MQ_ERROR_INSUFFICIENT_RESOURCES;
    } else
        hr = MQ_ERROR_INSUFFICIENT_RESOURCES;

    gMem->Unlock ();

    return hr;
}

HRESULT ScOverlappedSupport::EnterOverlappedReceive
(
HANDLE          hQueueEvent,
ScIoRequest     *pIO
) {
    HRESULT hr = MQ_INFORMATION_OPERATION_PENDING;
    gMem->Lock ();

    if (! fApiInitialized) {
        gMem->Unlock ();
        return MQ_ERROR_SERVICE_NOT_AVAILABLE;
    }

    int iNdx = -1;
    for (int i = 0 ; i < iNumPendingRequests ; ++i) {
        if (pahQueueEvents[i] == hQueueEvent) {
            iNdx = i;
            break;
        }
    }

    if ((iNdx < 0) && (iNumPendingRequests < (MAXIMUM_WAIT_OBJECTS - 1))) {
        iNdx = iNumPendingRequests;
        apPendingRequests[iNdx] = NULL;
    }

    if (iNdx >= 0) {
        pIO->pNode = pTimeTree->Insert (pIO->tExpirationS, pIO);
        if (pIO->pNode) {
            pIO->pNext = apPendingRequests[iNdx];

            apPendingRequests[iNdx] = pIO;
            pahQueueEvents[iNdx]    = hQueueEvent;

            pIO->iNdx = iNdx;

            if (iNdx == iNumPendingRequests)
                ++iNumPendingRequests;

#if defined (SC_VERBOSE)
            scerror_DebugOut (VERBOSE_MASK_IO, L"Re-Entering async read request for queue handle %08x\n\texpiration time %08x action %08x properties ptr %08x\n\tevent %08x cursor handle %08x\n",
                pIO->hQueue, pIO->tExpirationTicks, pIO->dwAction, pIO->pMsgProps, pIO->hEvent, pIO->hCursor);
#endif
            SpinThread ();
        } else
            hr = MQ_ERROR_INSUFFICIENT_RESOURCES;
    } else
        hr = MQ_ERROR_INSUFFICIENT_RESOURCES;

    gMem->Unlock ();

    return hr;
}

//
//  Console, debug and NT RPC support
//
#if defined (SC_INCLUDE_CONSOLE)
#include <stdio.h>
#include <scsman.hxx>
#include <scorder.hxx>

void scapi_DumpMem (unsigned char *p, int iSz) {
    int iOut = 0;
    unsigned char *pSav = p;
    wprintf_s (L"%08x |  ", p - pSav);
    if (--iSz > iSz){
       ASSERT(FALSE);
    }
    while (--iSz >= 0) {
        wprintf_s (L"%02x ", *p);
        ++iOut;
        ++p;
        if (iOut == 8) {
            wprintf_s (L" |  ");
            p -= iOut;
            for (int i = 0 ; i < iOut ; ++i, ++p)
                wprintf_s (L"%c", (*p >= ' ' && *p <= 126) ? *p : '.');
            wprintf_s (L"\n%08x |  ", p - pSav);
            iOut = 0;
        }
    }

    for (int i = iOut ; i < 8 ; ++i )
        wprintf_s (L"   ");

    wprintf_s (L" |  ");
    p -= iOut;
    for (i = 0 ; i < iOut ; ++i, ++p)
        wprintf_s (L"%c", (*p >= ' ' && *p <= 126) ? *p : '.');
    wprintf_s (L"\n");
}

int scapi_HandleDumper (SVSHandle h, void *pUnused) {
    wprintf_s (L"Handle %08x ", h);

    ScHandleInfo *pHInfo = gQueueMan->QueryHandle (h);
    if (! pHInfo) {
        wprintf_s (L": can't query - system is badly corrupted\n", h);
        return 0;
    }

    if (pHInfo->uiHandleType == SCQMAN_HANDLE_QUEUE) {
        wprintf_s (L" [Queue %s] Share mode %d Access %d Default Cursor %08x\n", pHInfo->pQueue->lpszFormatName, pHInfo->q.uiShareMode, pHInfo->q.uiAccess, pHInfo->q.hDefaultCursor);
    } else if (pHInfo->uiHandleType == SCQMAN_HANDLE_CURSOR) {
        wprintf_s (L" [Cursor for Queue %s] Queue Handle %08x Current Position %08x Pos Valid %d", pHInfo->pQueue->lpszFormatName, pHInfo->c.hQueue, pHInfo->c.pNode, pHInfo->c.fPosValid);
    } else {
        wprintf_s (L"Unknown handle...\n");
        return 0;
    }

    return 1;
}

void scapi_TimerDump (unsigned int dwWhen, SVSHandle hWhat, void *pUnused) {
    wprintf_s (L"At %08x signal %08x\n", dwWhen, hWhat);
}

DWORD WINAPI scapi_UserControlThread (LPVOID lpParameter) {
    _putws (L"MSMQ Small Client Monitor V1.0.");
    for ( ; ; ) {
        WCHAR szBuffer[500];
        wprintf_s (L"Ticks = %08x Secs = %08x MSMQ> ", GetTickCount(), scutil_now());
        if ((! _getws_s (szBuffer, _countof(szBuffer))) || (_wcsicmp (szBuffer, L"exit") == 0))
            break;
        else if (_wcsnicmp (szBuffer, L"dump ", 5) == 0) {
            if (! fApiInitialized) {
                wprintf_s (L"MSMQ service not started.\n");
                continue;
            }

            gMem->Lock ();
            if (! fApiInitialized) {
                gMem->Unlock ();
                wprintf_s (L"MSMQ service not started.\n");
                continue;
            }
            switch (szBuffer[5]) {
            case L'x': {
                if (! gSeqMan) {
                    wprintf_s (L"Sequence manager not initialized\n");
                    break;
                }

                wprintf_s (L"Sequence Pulse     : %s initialized\n", (! gSeqMan->hSequencePulse) ? L"not" : L"");
                wprintf_s (L"File               : %s initialized\n", (gSeqMan->hBackupFile == INVALID_HANDLE_VALUE) ? L"not" : L"");
                wprintf_s (L"Strings            : %s initialized\n", (gSeqMan->hStringFile == INVALID_HANDLE_VALUE) ? L"not" : L"");
                wprintf_s (L"File name          : %s\n", gSeqMan->lpszBackupName);
                wprintf_s (L"String name        : %s\n", gSeqMan->lpszStringName);
                wprintf_s (L"Last backup access : %08x\n", gSeqMan->uiLastBackupAccessT);
                wprintf_s (L"Last string access : %08x\n", gSeqMan->uiLastStringAccessT);
                wprintf_s (L"Last compact       : %08x\n", gSeqMan->uiLastCompactT);
                wprintf_s (L"Last prune         : %08x\n", gSeqMan->uiLastPruneT);

                wprintf_s (L"Clusters           : %d\n", gSeqMan->uiClustersCount);
                wprintf_s (L"Clusters allocated : %d\n", gSeqMan->uiClustersAlloc);
                wprintf_s (L"Clusters:\n");
                for (int j = 0 ; j < (int)gSeqMan->uiClustersCount ; ++j) {
                    ScOrderCluster *pCluster = gSeqMan->ppClusters[j];
                    wprintf_s (L"Cluster %d\n", j);
                    wprintf_s (L"    Free Entries: %d\n", pCluster->iNumFree);
                    wprintf_s (L"    Dirty       : %s\n", pCluster->iDirty ? L"yes" : L"no");
                    wprintf_s (L"    First Free  : %d\n", pCluster->h.uiFirstFreeBlock);
                    wprintf_s (L"    Sequences in cluster:\n");
                    for (int i = 0 ; i < SCSEQUENCE_ENTRIES_PER_BLOCK ; ++i) {
                        if (! pCluster->pos[i].uiLastAccessS)
                            wprintf_s (L"        Cluster %d <<< FREE >>> next free %d\n", i, pCluster->pos[i].uiCurrentSeqN);
                        else {
                            wprintf_s (L"        Cluster %d\n", i);
                            wprintf_s (L"            Local Queue GUID    : " SC_GUID_FORMAT L"\n", SC_GUID_ELEMENTS((&pCluster->pos[i].guidQ)));
                            wprintf_s (L"            Local Name GUID     : " SC_GUID_FORMAT L"\n", SC_GUID_ELEMENTS((&pCluster->pos[i].guidQueueName)));
                            wprintf_s (L"            Stream Id GUID      : " SC_GUID_FORMAT L"\n", SC_GUID_ELEMENTS((&pCluster->pos[i].guidStreamId)));
                            wprintf_s (L"            Ack Queue Name GUID : " SC_GUID_FORMAT L"\n", SC_GUID_ELEMENTS((&pCluster->pos[i].guidOrderAck)));
                            wprintf_s (L"            Current Sequence ID : %016I64x\n", pCluster->pos[i].llCurrentSeqID);
                            wprintf_s (L"            Current Sequence N  : %d\n", pCluster->pos[i].uiCurrentSeqN);
                            wprintf_s (L"            Last Access (sec)   : %08x\n", pCluster->pos[i].uiLastAccessS);
                        }
                    }
                }
                wprintf_s (L"Active sequences:\n");
                ScOrderSeq *pSeq = gSeqMan->pSeqActive;
                while (pSeq) {
                    wprintf_s (L"    Local transactional queue : %s\n", pSeq->pQueue->lpszFormatName);
                    wprintf_s (L"    Local queue guid          : " SC_GUID_FORMAT L"\n", SC_GUID_ELEMENTS ((&pSeq->p->guidQ)));
                    wprintf_s (L"    Local queue name          : %s\n", gSeqMan->GetStringFromGUID(&pSeq->p->guidQueueName));
                    wprintf_s (L"    Local queue name guid     : " SC_GUID_FORMAT L"\n", SC_GUID_ELEMENTS ((&pSeq->p->guidQueueName)));
                    wprintf_s (L"    StreamId                  : %s\n", gSeqMan->GetStringFromGUID(&pSeq->p->guidStreamId));
                    wprintf_s (L"    Stream Id GUID            : " SC_GUID_FORMAT L"\n", SC_GUID_ELEMENTS ((&pSeq->p->guidStreamId)));
                    wprintf_s (L"    Order queue name          : %s\n", gSeqMan->GetStringFromGUID(&pSeq->p->guidOrderAck));
                    wprintf_s (L"    Order queue guid          : " SC_GUID_FORMAT L"\n", SC_GUID_ELEMENTS ((&pSeq->p->guidOrderAck)));
                    wprintf_s (L"    Active                    : %s\n", pSeq->fActive ? L"yes" : L"no");
                    wprintf_s (L"    Current Sequence ID       : %016I64x\n", pSeq->p->llCurrentSeqID);
                    wprintf_s (L"    Current Sequence Number   : %d\n", pSeq->p->uiCurrentSeqN);
                    wprintf_s (L"    Last Access (sec)         : %08x\n\n", pSeq->p->uiLastAccessS);

                    pSeq = pSeq->pNextActive;
                }
            }
                break;

            case L'o': {
                    if (! gOverlappedSupport) {
                        wprintf_s (L"Support for overlapped I/O not initialized\n");
                        break;
                    }
                    wprintf_s (L"Overlapped I/O support:\n\n");
                    wprintf_s (L"Structure init: %s\n", gOverlappedSupport->fInitialized ? L"completed" : L"failed");
                    wprintf_s (L"I/O Thread    : %08x\n", gOverlappedSupport->hThread);
                    wprintf_s (L"Pending queues: %d\n", gOverlappedSupport->iNumPendingRequests);
                    wprintf_s (L"Refresh semaphore %08x\n", gOverlappedSupport->ahQueueEvents[0]);
                    for (int i = 0 ; i < gOverlappedSupport->iNumPendingRequests ; ++i) {
                        wprintf_s (L"    Queue semaphore %08x\n", gOverlappedSupport->pahQueueEvents[i]);
                        ScIoRequest *pIO = gOverlappedSupport->apPendingRequests[i];

                        while (pIO) {
                            wprintf_s (L"        Request %08x\n", pIO);
                            wprintf_s (L"            Overlapped event: %08x\n", pIO->hEvent);
                            wprintf_s (L"            Calling process : %08x\n", pIO->hCallerProc);
                            wprintf_s (L"            Overlapped ptr  : %08x\n", pIO->pOverlapped);
                            wprintf_s (L"            Status ptr      : %08x\n", pIO->pdwStatus);
                            wprintf_s (L"            Queue Handle    : %d\n", pIO->hQueue);
                            wprintf_s (L"            Cursor Handle   : %d\n", pIO->hCursor);
                            wprintf_s (L"            Expiration Time : %08x\n", pIO->tExpirationTicks);
                            wprintf_s (L"            Expiration (s)  : %08x\n", pIO->tExpirationS);
                            wprintf_s (L"            Expiration (ms) : %08x\n", pIO->tExpirationMS);
                            wprintf_s (L"            Timeout         : %08x\n", pIO->dwTimeout);
                            wprintf_s (L"            Action          : %08x\n", pIO->dwAction);
                            wprintf_s (L"            Node            : %08x\n", pIO->pNode);
                            wprintf_s (L"            Properties ptr  : %08x\n", pIO->pMsgProps);
                            wprintf_s (L"            Index           : %08x\n", pIO->iNdx);
                            pIO = pIO->pNext;
                        }
                    }
                    wprintf_s (L"Tree enumeration:\n");
                    SVSTNode *pMinNode = gOverlappedSupport->pTimeTree->Min();
                    while (pMinNode) {
                        wprintf_s (L"    Node %08x Data %08x Key %08x\n", pMinNode,
                                SVSTree::GetData (pMinNode), SVSTree::GetKey (pMinNode));
                        pMinNode = gOverlappedSupport->pTimeTree->Next(pMinNode);
                    }
                    break;
                }
            case L'g': {
                    _putws (L"Global Info Dump:\n\n");
                    wprintf_s (L" Globa Data : %s\n", gMem->fInitialized ? L"Initialized" : L"Not initialized");

                    wprintf_s (L" Packet Memory    : %s\n", gMem->pPacketMem ? L"Initialized" : L"Not initialized");
                    wprintf_s (L" Tree Node Memory : %s\n", gMem->pTreeNodeMem ? L"Initialized" : L"Not initialized");
                    wprintf_s (L" Ack  Node Memory : %s\n", gMem->pAckNodeMem ? L"Initialized" : L"Not initialized");
                    wprintf_s (L" String Hash      : %s\n", gMem->pStringHash ? L"Initialized" : L"Not initialized");

                    if (gMem->pTimer) {
                        wprintf_s (L"System timer  : initialized. Contents follow:\n");
                        svsutil_WalkAttrTimer (gMem->pTimer, scapi_TimerDump, NULL);
                    } else
                        wprintf_s (L"System timer  : not initialized\n");

                    wprintf_s    (L"Protocol port   : %d\n", gMachine->uiPort);
                    wprintf_s    (L"Ping     port   : %d\n", gMachine->uiPingPort);
                    wprintf_s    (L"QM Server       : %s\n", gMachine->lpszHostName);
                    wprintf_s    (L"DefaultInQuota  : %d K\n", gMachine->uiDefaultInQuotaK);
                    wprintf_s    (L"DefaultOutQuota : %d K\n", gMachine->uiDefaultOutQuotaK);
                    wprintf_s    (L"MachineQuota    : %d K\n", gMachine->uiMachineQuotaK);
                    wprintf_s    (L"MachineQuotaUsed: %d K\n", gMachine->iMachineQuotaUsedB);
                    wprintf_s    (L"Start UID       : %08x\n", gMachine->uiStartID);
                    wprintf_s    (L"Local QM GUID   : " GUID_FORMAT L"\n", GUID_ELEMENTS((&gMachine->guid)));
                    wprintf_s    (L"QM Directory    : %s\n", gMachine->lpszDirName);
                    wprintf_s    (L"Host Name       : %s\n", gMachine->lpszHostName);
                    wprintf_s    (L"Debug Queue     : %s\n", gMachine->lpszDebugQueueFormatName);
                }
                break;

            case L't': {
                    _putws (L"Time-out tree dump\n");
                    SVSTNode *pNode = gMem->pTimeoutTree->Min();
                    while (pNode) {
                        ScPacket *pPacket = (ScPacket *)SVSTree::GetData (pNode);
                        wprintf_s (L"    Packet ptr %08x UID %08x Expiration %08x Queue %s\n", pPacket, pPacket->uiMessageID, pPacket->tExpirationTime, pPacket->pQueue ? pPacket->pQueue->lpszFormatName : L"None");
                        pNode = gMem->pTimeoutTree->Next(pNode);
                    }
                    break;
                }
            case L'q': {
                    _putws (L"Queue Manager Dump:\n");
                    ScQueueManager *pqm = gQueueMan;
                    wprintf_s (L"Current Message ID : %08x\n", pqm->uiMessageID);
                    wprintf_s (L"Handle System      : %s\n", pqm->pHandles    ? L"initialized" : L"not initialized");
                    wprintf_s (L"Handle Memory      : %s\n", pqm->pHandleMem  ? L"initialized" : L"not initialized");
                    wprintf_s (L"Main Thread        : %s\n", pqm->hMainThread ? L"initialized" : L"not initialized");
                    wprintf_s (L"Garbage collector  : %s\n", pqm->hPacketExpired ? L"initialized" : L"not initialized");
                    wprintf_s (L"Dead letter queue  : %s\n", pqm->pQueueDLQ      ? pqm->pQueueDLQ->lpszFormatName      : L"not initialized");
                    wprintf_s (L"Machine journal    : %s\n", pqm->pQueueJournal  ? pqm->pQueueJournal->lpszFormatName  : L"not initialized");
                    wprintf_s (L"Out-FRS     queue  : %s\n", pqm->pQueueOutFRS   ? pqm->pQueueOutFRS->lpszFormatName   : L"not initialized");
                    wprintf_s (L"Order ACK   queue  : %s\n", pqm->pQueueOrderAck ? pqm->pQueueOrderAck->lpszFormatName : L"not initialized");

                    _putws (L"Handle Table Dump:\n");
                    gQueueMan->pHandles->FilterHandles (scapi_HandleDumper, NULL);

                    int i = 0;
                    ScQueueList *pql = pqm->pqlIncoming;
                    _putws (L"Incoming Queues:");

                    if (! pql)
                        _putws (L"    None...");

                    while (pql) {
                        wprintf_s (L"    %d. %s\n", ++i, pql->pQueue->lpszFormatName);
                        pql = pql->pqlNext;
                    }

                    pql = pqm->pqlOutgoing;
                    _putws (L"Outgoing Queues:");

                    if (! pql)
                        _putws (L"    None...");

                    while (pql) {
                        wprintf_s (L"    %d. %s\n", ++i, pql->pQueue->lpszFormatName);
                        pql = pql->pqlNext;
                    }
                }
                break;
            case L's': {
                    ScSessionManager *pSessMan = gSessionMan;
                    _putws (L"Session Manager Dump:\n");
                    wprintf_s (L"Session manager    : %s\n", pSessMan->fInitialized ? L"initialized" : L"not initialized");
                    wprintf_s (L"Accepting  Thread  : %08x\n", pSessMan->hAccThread);
                    wprintf_s (L"Event              : %08x\n", pSessMan->hBuzz);
                    wprintf_s (L"Socket             : %08x\n", pSessMan->s_listen);
                    wprintf_s (L"Active pairs       : %d\n", pSessMan->iThreadPairs);

                    _putws (L"Sessions Dump:");
                    ScSession *pSessRun = pSessMan->pSessList;
                    if (! pSessRun)
                        _putws (L"    none...");

                    while (pSessRun) {
                        wprintf_s  (L"    Session %s\n", pSessRun->lpszHostName);
                        printf_s    ("    (ASCII) %s\n", pSessRun->lpszmbHostName);
                        wprintf_s  (L"        State                   : %s\n",
                             (pSessRun->fSessionState == SCSESSION_STATE_INACTIVE)         ? L"Inactive" :
                            ((pSessRun->fSessionState == SCSESSION_STATE_CONNECTING)       ? L"Connecting" :
                            ((pSessRun->fSessionState == SCSESSION_STATE_CONNECTED_CLIENT) ? L"Connected/Client" :
                            ((pSessRun->fSessionState == SCSESSION_STATE_CONNECTED_SERVER) ? L"Connected/Server" :
                            ((pSessRun->fSessionState == SCSESSION_STATE_OPERATING)        ? L"Operating" :
                            ((pSessRun->fSessionState == SCSESSION_STATE_EXITING)          ? L"Exiting" :
                            ((pSessRun->fSessionState == SCSESSION_STATE_WAITING)          ? L"Waiting" : L"Undefined")))))));
                        wprintf_s  (L"        Failures                : %d\n", pSessRun->iFailures);
                        wprintf_s  (L"        Next Connection Attempt : %08x\n", pSessRun->uiNextAttemptTime);
                        wprintf_s  (L"        Event                   : %08x\n", pSessRun->hEvent);
                        wprintf_s  (L"        Sending Thread          : %08x\n", pSessRun->hServiceThreadW);
                        wprintf_s  (L"        Receiving Thread        : %08x\n", pSessRun->hServiceThreadR);
                        wprintf_s  (L"        Socket                  : %d\n", pSessRun->s);
                        wprintf_s  (L"        GUID                    : " GUID_FORMAT L"\n", GUID_ELEMENTS((&pSessRun->guidDest)));
                        wprintf_s  (L"        Connection stamp/delta  : %08x\n", pSessRun->uiConnectionStamp);
                        wprintf_s  (L"        ACK Timeout             : %d\n", pSessRun->uiAckTimeout);
                        wprintf_s  (L"        Store ACK Timeout       : %d\n", pSessRun->uiStoreAckTimeout);
                        wprintf_s  (L"        Local Window Size       : %d\n", pSessRun->uiMyWindowSize);
                        wprintf_s  (L"        Remote Window Size      : %d\n", pSessRun->uiOtherWindowSize);
                        wprintf_s  (L"        Last ACK sent           : %d\n", pSessRun->usLastAckSent);
                        wprintf_s  (L"        Last reliable ACK sent  : %d\n", pSessRun->usLastRelAckSent);
                        wprintf_s  (L"        Packets sent            : %d\n", pSessRun->usPacketsSent);
                        wprintf_s  (L"        Reliable Packets sent   : %d\n", pSessRun->usRelPacketsSent);
                        wprintf_s  (L"        Last Ack recvd          : %d\n", pSessRun->usLastAckReceived);
                        wprintf_s  (L"        Packets recvd           : %d\n", pSessRun->usPacketsReceived);
                        wprintf_s  (L"        Reliable Packets recvd  : %d\n", pSessRun->usRelPacketsReceived);
                        wprintf_s  (L"        ACK Due                 : %08x\n", pSessRun->uiAckDue);
                        SentPacket *pSP = pSessRun->pSentPackets;
                        while (pSP) {
                            wprintf_s  (L"            Pending express packet ptr %08x UID %08x from queue %s : sent no %d\n",
                                    pSP->pPacket, pSP->pPacket->uiMessageID, pSP->pPacket->pQueue->lpszFormatName, pSP->usNum);

                            pSP = pSP->pNext;
                        }
                        pSP = pSessRun->pSentRelPackets;
                        while (pSP) {
                            wprintf_s  (L"            Pending reliable packet ptr %x UID %08x from queue %s : sent no %d\n",
                                    pSP->pPacket, pSP->pPacket->uiMessageID, pSP->pPacket->pQueue->lpszFormatName, pSP->usNum);

                            pSP = pSP->pNext;
                        }
                        pSessRun = pSessRun->pNext;
                    }
                }
                break;

            case L'p': {
                    int i = 0;
                    ScQueueList *pql = gQueueMan->pqlIncoming;
                    wprintf_s (L"Total\t\tReliable\t\tQueue Format Name\n");
                    while (pql) {
                        SVSTNode *pNode = pql->pQueue->pPackets->Min();

                        int iPackets    = 0;
                        int iRelPackets = 0;

                        while (pNode) {
                            ScPacket *pPacket = (ScPacket *)SVSTree::GetData (pNode);

                            if (pPacket->iDirEntry != -1)
                                ++iRelPackets;

                            ++iPackets;
                            pNode = pql->pQueue->pPackets->Next(pNode);
                        }

                        wprintf_s (L"%d\t\t%d\t\t%s\n", iPackets, iRelPackets, pql->pQueue->lpszFormatName);
                        pql = pql->pqlNext;
                    }

                    pql = gQueueMan->pqlOutgoing;

                    while (pql) {
                        SVSTNode *pNode = pql->pQueue->pPackets->Min();

                        int iPackets    = 0;
                        int iRelPackets = 0;

                        while (pNode) {
                            ScPacket *pPacket = (ScPacket *)SVSTree::GetData (pNode);

                            if (pPacket->iDirEntry != -1)
                                ++iRelPackets;

                            ++iPackets;
                            pNode = pql->pQueue->pPackets->Next(pNode);
                        }

                        wprintf_s (L"%d\t\t%d\t\t%s\n", iPackets, iRelPackets, pql->pQueue->lpszFormatName);
                        pql = pql->pqlNext;
                    }
                }
                break;

            case L'b': {
            case L'f':
                int iQueueNum = 0;
                WCHAR *pX = &szBuffer[6];
                while (*pX == L' ')
                    ++pX;
                while ((*pX >= L'0') && (*pX <= L'9')) {
                    iQueueNum = iQueueNum * 10 + (*pX - L'0');
                    ++pX;
                }

                ScQueueManager *pqm = gQueueMan;
                int i = 0;
                ScQueueList *pql = pqm->pqlIncoming;

                while (pql) {
                    if (++i == iQueueNum)
                        break;
                    pql = pql->pqlNext;
                }

                if (! pql) {
                    pql = pqm->pqlOutgoing;

                    while (pql) {
                        if (++i == iQueueNum)
                            break;

                        pql = pql->pqlNext;
                    }
                }
                if (! pql) {
                    wprintf_s (L"Queue %d was not found.\n", iQueueNum);
                    break;
                }

                ScQueue *pQueue = pql->pQueue;

                wprintf_s (L"Dumping queue %s\n", pQueue->lpszFormatName);
                wprintf_s (L"    Initialized            : %s\n", pQueue->fInitialized ? L"yes" : L"no");
                wprintf_s (L"    File                   : %s\n", pQueue->sFile->lpszFileName);
                wprintf_s (L"        Open               : %s\n", pQueue->sFile->hBackupFile == INVALID_HANDLE_VALUE ? L"no" : L"yes");
                wprintf_s (L"        Last used          : %08x\n", pQueue->sFile->tLastUsed);
                wprintf_s (L"        Header Offset      : %d\n", pQueue->sFile->pFileDir->uiQueueHeaderOffset);
                wprintf_s (L"        Header Size        : %d\n", pQueue->sFile->pFileDir->uiQueueHeaderSize);
                wprintf_s (L"        Dir Offset         : %d\n", pQueue->sFile->pFileDir->uiPacketDirOffset);
                wprintf_s (L"        Dir Size           : %d\n", pQueue->sFile->pFileDir->uiPacketDirSize);
                wprintf_s (L"        Backup Offset      : %d\n", pQueue->sFile->pFileDir->uiPacketBackupOffset);
                wprintf_s (L"        Backup Size        : %d\n", pQueue->sFile->pFileDir->uiPacketBackupSize);
                wprintf_s (L"        Dir Entries        : %d\n", pQueue->sFile->pPacketDir->uiNumEntries);
                wprintf_s (L"        Dir Entries (Used) : %d\n", pQueue->sFile->pPacketDir->uiUsedEntries);
                wprintf_s (L"        First Free in Map  : %d\n", pQueue->sFile->iFreeIndex);
                wprintf_s (L"        Map Size           : %d\n", pQueue->sFile->iMapSize);
                wprintf_s (L"        Queue Inited       : %s\n", pQueue->sFile->pQueue ? L"yes" : L"no");
                wprintf_s (L"    Packet Storage Inited  : %s\n", pQueue->pPackets      ? L"yes" : L"no");
                wprintf_s (L"    Journal                : %s\n", pQueue->pJournal ? pQueue->pJournal->lpszFormatName : L"none");
                wprintf_s (L"    Host                   : %s\n", pQueue->lpszQueueHost);
                wprintf_s (L"    Name                   : %s\n", pQueue->lpszQueueName);
                wprintf_s (L"    Label                  : %s\n", pQueue->lpszQueueLabel);
                wprintf_s (L"    Incoming               : %s\n", pQueue->qp.bIsIncoming    ? L"yes" : L"no");
                wprintf_s (L"    Internal               : %s\n", pQueue->qp.bIsInternal    ? L"yes" : L"no");
                wprintf_s (L"    Public                 : %s\n", pQueue->qp.bIsPublic      ? L"yes" : L"no");
                wprintf_s (L"    Protected              : %s\n", pQueue->qp.bIsProtected   ? L"yes" : L"no");
                wprintf_s (L"    Is Journal             : %s\n", pQueue->qp.bIsJournal     ? L"yes" : L"no");
                wprintf_s (L"    Is Dead Letter Queue   : %s\n", pQueue->qp.bIsDeadLetter  ? L"yes" : L"no");
                wprintf_s (L"    Is Machine Journal     : %s\n", pQueue->qp.bIsMachineJournal ? L"yes" : L"no");
                wprintf_s (L"    Is Order Ack           : %s\n", pQueue->qp.bIsOrderAck    ? L"yes" : L"no");
                wprintf_s (L"    Is Out-FRS             : %s\n", pQueue->qp.bIsOutFRS      ? L"yes" : L"no");
                wprintf_s (L"    Has Journal            : %s\n", pQueue->qp.bHasJournal    ? L"yes" : L"no");
                wprintf_s (L"    Journal On             : %s\n", pQueue->qp.bIsJournalOn   ? L"yes" : L"no");
                wprintf_s (L"    Authenticate           : %s\n", pQueue->qp.bAuthenticate  ? L"yes" : L"no");
                wprintf_s (L"    Transactional          : %s\n", pQueue->qp.bTransactional ? L"yes" : L"no");
                wprintf_s (L"    Quota                  : %d K\n", pQueue->qp.uiQuotaK);
                wprintf_s (L"    Privacy Level          : %d\n", pQueue->qp.uiPrivacyLevel);
                wprintf_s (L"    Base Priority          : %d\n", pQueue->qp.iBasePriority);
                wprintf_s (L"    GUID                   : " GUID_FORMAT L"\n", GUID_ELEMENTS((&pQueue->qp.guid)));
                wprintf_s (L"    Type GUID              : " GUID_FORMAT L"\n", GUID_ELEMENTS((&pQueue->qp.guidQueueType)));
                wprintf_s (L"    Creation Time          : %08x\n", pQueue->tCreation);
                wprintf_s (L"    Last Modification Time : %08x\n", pQueue->tModification);
                wprintf_s (L"    Currently DENYALL?     : %s\n", pQueue->fDenyAll ? L"yes" : L"no");
                wprintf_s (L"    Opened for receiving   : %d\n", pQueue->uiOpenRecv);
                wprintf_s (L"    Opened                 : %d\n", pQueue->uiOpen);
                wprintf_s (L"    Event Inited           : %s\n", pQueue->hUpdateEvent ? L"yes" : L"no");
                wprintf_s (L"    Session Inited         : %s\n", pQueue->pSess ? L"yes" : L"no");
                wprintf_s (L"    Sequence ID            : %016I64x\n", pQueue->llSeqID);
                wprintf_s (L"    Sequence Number        : %08x\n", pQueue->uiSeqNum);
                wprintf_s (L"    Received messages      : %08x\n", pQueue->hkReceived);

                {
                    SVSTNode *pNode = pQueue->pPackets->Min();
                    int iPackets2    = 0;
                    int iRelPackets = 0;

                    while (pNode) {
                        ScPacket *pPacket = (ScPacket *)SVSTree::GetData (pNode);

                        if (pPacket->iDirEntry != -1)
                            ++iRelPackets;

                        ++iPackets2;
                        pNode = pQueue->pPackets->Next(pNode);
                    }
                    wprintf_s (L"    Packets                : %d\n", iPackets2);
                    wprintf_s (L"    Reliable packets       : %d\n", iRelPackets);

                }

                if (szBuffer[5] == L'f') {
                    _putws (L"Message directory dump:");
                    _putws (L"File:");
                    for (int j = 0 ; j <= (int)pQueue->sFile->pPacketDir->uiUsedEntries ; ++j) {
                        wprintf_s (L"    [Entry %3d] Offset %08x [%9d] Code %02x [%s]\n", j,
                            pQueue->sFile->pPacketDir->sPacketEntry[j].uiOffset,
                            pQueue->sFile->pPacketDir->sPacketEntry[j].uiOffset,
                            pQueue->sFile->pPacketDir->sPacketEntry[j].uiType,
                            (pQueue->sFile->pPacketDir->sPacketEntry[j].uiType == SCFILE_PACKET_EMPTY) ? L"Empty" :
                            ((pQueue->sFile->pPacketDir->sPacketEntry[j].uiType == SCFILE_PACKET_LIVE) ? L"Live" :
                            ((pQueue->sFile->pPacketDir->sPacketEntry[j].uiType == SCFILE_PACKET_LAST) ? L"Last" : L"ERROR")));

                        if (pQueue->sFile->pPacketDir->sPacketEntry[j].uiType == SCFILE_PACKET_LIVE) {
                            static int iBufLen = 0;
                            static char *pBuffer = NULL;

                            wprintf_s (L"Packet dump:\n");
                            int iLen = pQueue->sFile->pPacketDir->sPacketEntry[j + 1].uiOffset -
                                pQueue->sFile->pPacketDir->sPacketEntry[j].uiOffset;
                            if (iLen <= 0) {
                                wprintf_s (L"Error: message size 0 or negative - nothing to dump!\n");
                                continue;
                            }

                            if (iBufLen < iLen) {
                                char *pBuffer2 = (char *)realloc (pBuffer, iLen);
                                if (! pBuffer2)
                                    wprintf_s (L"No memory or file corruption!\n");
                                else {
                                    iBufLen = iLen;
                                    pBuffer = pBuffer2;
                                }
                            }

                            DWORD dwSize = 0;

                            if ((0xFFFFFFFF == SetFilePointer (pQueue->sFile->hBackupFile,
                                pQueue->sFile->pFileDir->uiPacketBackupOffset +
                                pQueue->sFile->pPacketDir->sPacketEntry[j].uiOffset,
                                NULL, FILE_BEGIN)) || (! ReadFile (pQueue->sFile->hBackupFile, pBuffer,
                                iLen, &dwSize, NULL)) || ((int)dwSize != iLen)) {
                                wprintf_s (L"File read error. Directory or file corrupted\n");
                                continue;
                            }
                            scapi_DumpMem ((unsigned char *)pBuffer, iLen);
                        }
                    }
                    _putws (L"Memory:");
                    SVSTNode *pNode = pQueue->pPackets->Min();
                    while (pNode) {
                        ScPacket *pPacket = (ScPacket *)SVSTree::GetData (pNode);

                        wprintf_s (L"    Packet ptr %08x UID %08x " SC_GUID_FORMAT L":\n", pPacket, pPacket->uiMessageID, SC_GUID_ELEMENTS((&pPacket->guidSourceQM)));
                        wprintf_s (L"        State      : %d [%s]\n", pPacket->uiPacketState,
                                (pPacket->uiPacketState == SCPACKET_STATE_ALIVE ? L"Alive" :
                        (pPacket->uiPacketState == SCPACKET_STATE_DEAD ? L"Dead" : (pPacket->uiPacketState == SCPACKET_STATE_DEAD ? L"WaitOrderAck" : L"Error"))));
                        wprintf_s (L"        Node       : %08x\n", pPacket->pNode);
                        wprintf_s (L"        T/O Node   : %08x\n", pPacket->pTimeoutNode);
                        wprintf_s (L"        Queue      : %s\n", pPacket->pQueue? pPacket->pQueue->lpszFormatName : L"None");
                        wprintf_s (L"        Image      : %08x\n", pPacket->pImage);
                        wprintf_s (L"        Creation   : %08x\n", pPacket->tCreationTime);
                        wprintf_s (L"        Expiration : %08x\n", pPacket->tExpirationTime);
                        wprintf_s (L"        Ack        : %08x [%s %s %s %s %s]\n", pPacket->uiAckType,
                                (pPacket->uiAckType & MQMSG_ACKNOWLEDGMENT_FULL_REACH_QUEUE) ? L"Full Reach" : L"",
                                (pPacket->uiAckType & MQMSG_ACKNOWLEDGMENT_FULL_RECEIVE)     ? L"Full Receive" : L"",
                                (pPacket->uiAckType & MQMSG_ACKNOWLEDGMENT_NACK_REACH_QUEUE) ? L"Nack Reach" : L"",
                                (pPacket->uiAckType & MQMSG_ACKNOWLEDGMENT_NACK_RECEIVE)     ? L"Nack Receive" : L"",
                                (pPacket->uiAckType == MQMSG_ACKNOWLEDGMENT_NONE)            ? L"None" : L"");
                        wprintf_s (L"        Dir Entry  : %d\n", pPacket->iDirEntry);
                        if (pPacket->iDirEntry >= 0)
                            wprintf_s (L"        File Index : %d\n", (*pQueue->sFile->pMap)[pPacket->iDirEntry]);
                        wprintf_s (L"        Size       : %d\n", pPacket->pImage->BinarySize());
                        wprintf_s (L"        Order Key  : %08x\n", pPacket->hkOrderKey);
                        if (pPacket->pImage) {
                            wprintf_s (L"    Memory dump (bin):\n");
                            scapi_DumpMem ((unsigned char *)pPacket->pImage->pvBinary, pPacket->pImage->BinarySize());
                            if (pPacket->pImage->pvExt) {
                                wprintf_s (L"    Memory dump (ext):\n");
                                scapi_DumpMem ((unsigned char *)pPacket->pImage->pvExt, pPacket->pImage->ExtensionsSize());
                            }
                        } else
                            wprintf_s (L"    File-bound\n");

                        pNode = pQueue->pPackets->Next(pNode);
                    }
                    wprintf_s (L"Map:\n        ");
                    for (int j = 0 ; j < pQueue->sFile->iMapSize ; ++j) {
                        wprintf_s (L"%d ", (*pQueue->sFile->pMap)[j]);
                        if ((j % 8) == 7)
                            wprintf_s (L"\n        ");
                    }
                    wprintf_s (L"\n");
                }

                break;
                }
            default:
                _putws (L"Unknown command. Type HELP for help on available commands.");
            }

            gMem->Unlock ();
        } else if (_wcsicmp (szBuffer, L"break") == 0)
            DebugBreak();
        else if (_wcsicmp (szBuffer, L"help") == 0) {
            _putws (L"The following commands are available:");
            _putws (L"exit                Terminate MSMQ service and exit.");
            _putws (L"break               User break into the debugger (int3 or the like).");
            _putws (L"dump g              Dump global MSMQ information.");
            _putws (L"dump q              Dump queue manager information.");
            _putws (L"dump t              Dump packet time/out information.");
            _putws (L"dump s              Dump session manager information.");
            _putws (L"dump o              Dump overlapped I/O information.");
            _putws (L"dump x              Dump in-order and transactopnal info.");
            _putws (L"dump p              Dump current number of packets in the system");
            _putws (L"dump b <Queue #>    Dump brief queue info.");
            _putws (L"dump f <Queue #>    Dump full queue info (including messages).");
        } else
            _putws (L"Unknown command. Type HELP for help on available commands.");
    }

    scce_Shutdown ();

    return 0;
}
#endif

HRESULT scapi_Console (void) {
#if defined (SC_INCLUDE_CONSOLE)
    DWORD tid;

    HANDLE hThread = CreateThread (NULL, 0, scapi_UserControlThread, NULL, 0, &tid);
    if (hThread) {
        CloseHandle (hThread);
        return MQ_OK;
    }
#endif
    return MQ_ERROR;
}

void scapi_EnterInputLoop (void) {
    scce_Listen ();
}

//
//  PSL translation logic.  The below functions process PSL as
//  called from psl_marshal classes and in turn call into the implementation
//  functions above.
//

HRESULT scapi_MQCreateQueuePSL(
   ce::marshal_arg<ce::copy_in,SCPROPVAR*> pQueueProps,
   ce::marshal_arg<ce::copy_out,ce::psl_buffer_wrapper<WCHAR*> > lpszFormatName,
   ce::marshal_arg<ce::copy_in_out, LPDWORD> pdwNameLen
)
{
    if (! pQueueProps.IsInited())
        return MQ_ERROR_INVALID_PARAMETER;

    return scapi_MQCreateQueue(pQueueProps,lpszFormatName.buffer(),pdwNameLen);
}

HRESULT scapi_MQDeleteQueuePSL(
    ce::marshal_arg<ce::copy_in,LPCWSTR> lpszFormatName
)
{
    return scapi_MQDeleteQueue((WCHAR*)((const WCHAR*)lpszFormatName));
}

HRESULT scapi_MQSendMessagePSL(
    SCHANDLE hQueue, 
    ce::marshal_arg<ce::copy_in,SCPROPVAR*> pMsgProps,
    int iTransaction
)
{
    if (! pMsgProps.IsInited())
        return MQ_ERROR_INVALID_PARAMETER;

    gMem->Lock ();

    HRESULT hr = scapi_MQSendMessage(hQueue, pMsgProps, iTransaction);

    gMem->Unlock();
    return hr;
}

HRESULT scapi_MQOpenQueuePSL(
    ce::marshal_arg<ce::copy_in,LPCWSTR> lpszFormatName, 
    DWORD dwAccess, 
    DWORD dwShareMode, 
    ce::marshal_arg<ce::copy_out, LPDWORD> phQueue
)
{
    return scapi_MQOpenQueue((WCHAR*)((const WCHAR*)lpszFormatName), dwAccess, 
                              dwShareMode, phQueue);
}

HRESULT scapi_MQCloseQueuePSL(SCHANDLE hQueue) {
    return scapi_MQCloseQueue(hQueue);
}

HRESULT scapi_MQSetQueuePropertiesPSL (
    ce::marshal_arg<ce::copy_in,LPCWSTR> lpszFormatName,
    ce::marshal_arg<ce::copy_in,SCPROPVAR*> pMsgProps
)
{
    if (! pMsgProps.IsInited())
        return MQ_ERROR_INVALID_PARAMETER;

    return scapi_MQSetQueueProperties((WCHAR*)((const WCHAR*)lpszFormatName), pMsgProps);
}

HRESULT scapi_MQCreateCursorPSL(
    SCHANDLE hQueue, 
    ce::marshal_arg<ce::copy_out, LPDWORD> phCursor
)
{
    return scapi_MQCreateCursor(hQueue, phCursor);
}

HRESULT scapi_MQCloseCursorPSL
(
    SCHANDLE        hCursor
)
{
    return scapi_MQCloseCursor(hCursor);
}

HRESULT scapi_MQHandleToFormatNamePSL
(
    SCHANDLE hQueue,
    ce::marshal_arg<ce::copy_out,ce::psl_buffer_wrapper<WCHAR*> > lpszFormatName,
    ce::marshal_arg<ce::copy_in_out, LPDWORD> dwNameLen
)
{
    return scapi_MQHandleToFormatName(hQueue,lpszFormatName.buffer(),dwNameLen);
}

HRESULT scapi_MQPathNameToFormatNamePSL
(
ce::marshal_arg<ce::copy_in,LPCWSTR> lpszPathName,
ce::marshal_arg<ce::copy_out,ce::psl_buffer_wrapper<WCHAR*> > lpszFormatName,
ce::marshal_arg<ce::copy_in_out, LPDWORD> pdwCount
)
{
    return scapi_MQPathNameToFormatName(lpszPathName,lpszFormatName.buffer(),pdwCount);
}

HRESULT scapi_MQReceiveMessagePSL
(
SCHANDLE            hQueue,
DWORD               dwTimeout,
DWORD               dwAction,
SCPROPVAR           *pMsgPropsUnmarshalled,
OVERLAPPED          *lpOverlapped,
SCHANDLE            hCursor,
int                 iNull3
)
{
    return scapi_MQReceiveMessage(hQueue,dwTimeout,dwAction,pMsgPropsUnmarshalled,lpOverlapped,hCursor,iNull3);
}

HRESULT scapi_MQFreeMemoryPSL(void *pvPtr) {
    gMem->Lock();
    gMem->remoteAlloc.FreeData((BYTE*)pvPtr);
    gMem->Unlock();
    // Don't bother checking return code of the FreeData() because the 
    // MQFreeMemory API is void anyway.
    return MQ_OK;
}

HRESULT scapi_MQGetMachinePropertiesPSL
(
ce::marshal_arg<ce::copy_in,LPCWSTR> lpszMachineName,
ce::marshal_arg<ce::copy_in,GUID*> pguidMachineID,
SCPROPVAR       *pQMPropsUnmarshalled
)
{
    ce::copy_in<SCPROPVAR*> pQMProps((HANDLE)GetCallerVMProcessId());
    pQMProps.EnableCopyOutPropVar();
    pQMProps.copy_arg_in(pQMPropsUnmarshalled);

    if (! pQMProps.IsInited())
        return MQ_ERROR_INVALID_PARAMETER;
    
    return scapi_MQGetMachineProperties(lpszMachineName,pguidMachineID,pQMProps);
}

HRESULT scapi_MQGetQueuePropertiesPSL
(
ce::marshal_arg<ce::copy_in,LPCWSTR> lpszFormatName,
SCPROPVAR       *pQueuePropsUnmarshalled
)
{
    ce::copy_in<SCPROPVAR*> pQMProps((HANDLE)GetCallerVMProcessId());
    pQMProps.EnableCopyOutPropVar();
    pQMProps.copy_arg_in(pQueuePropsUnmarshalled);

    if (! pQMProps.IsInited())
        return MQ_ERROR_INVALID_PARAMETER;

    return scapi_MQGetQueueProperties((WCHAR*)((const WCHAR*)lpszFormatName), pQMProps);
}


//
//  Helper functions that marshall more complicated types across process
//  boundaries.
//

// Marshalls a PROPVARIANT from user mode -> servicesd.exe.
void CMarshalPropVariantIn::MarshallPropVar(PROPVARIANT *pPropVar, MSGPROPID propID) {
    HRESULT hr;

    // Make sure that MarshallPropVar is only called once.
    SVSUTIL_ASSERT(m_variantArray == NULL);
    SVSUTIL_ASSERT(m_MappedClientPtr.ptr() == NULL);

    // Copies type information and shallow copy of data.
    memcpy(&m_PropVar,pPropVar,sizeof(m_PropVar));
    DWORD i;

    // Only marshall the subset of types that MSMQ supports.
    switch (m_PropVar.vt) {
    case VT_UI1:
    case VT_I2:
    case VT_UI4:
        // Simple (shallow) types that don't need a further copy
    break;

    case VT_LPWSTR:
    {
        hr = m_MappedClientPtr.Marshal(pPropVar->pwszVal, 0, ARG_I_WSTR, TRUE, TRUE);
        if (FAILED(hr)) {
            m_PropVar.pwszVal = NULL;
            return MSMQMarshalPtrError();
        }

        // Fixup pointer in structure to make it easier for rest of MSMQ
        // to use this VARIANT directly without calling this class.
        m_PropVar.pwszVal = (LPWSTR)m_MappedClientPtr.ptr();
    }
    break;

    case VT_CLSID:
    {
        hr = m_MappedClientPtr.Marshal(pPropVar->puuid, sizeof(CLSID), ARG_I_PTR, TRUE, TRUE);
        if (FAILED(hr)) {
            m_PropVar.pwszVal = NULL;
            return MSMQMarshalPtrError();
        }
        m_PropVar.puuid = (CLSID*)m_MappedClientPtr.ptr();
    }
    break;

    case (VT_VECTOR | VT_UI1):
    {
        // An array of raw data.
        hr = m_MappedClientPtr.Marshal(pPropVar->caub.pElems, pPropVar->caub.cElems, 
                                       ARG_I_PTR,TRUE,TRUE);

        if (FAILED(hr)) {
            m_PropVar.caub.pElems = NULL;
            return MSMQMarshalPtrError();
        }

        if (propID != PROPID_M_MSGID) {
            // By default, we marshall the pointer *unless* it's for a PROPID_M_MSGID,
            // in which case later down the line we use this pointer directly to 
            // write back to the caller process memory and hence we need the original
            // (All other elements in this class are input only, this needs to be an
            // output only).
            m_PropVar.caub.pElems = (UCHAR*)m_MappedClientPtr.ptr();
        }
    }
    break;

    case (VT_VECTOR | VT_VARIANT):
    {
        // An array of VARIANTs.

        // We must first marshall the array of VARIANTs themselves.
        DWORD numVariants = m_PropVar.capropvar.cElems;
        hr = m_MappedClientPtr.Marshal(pPropVar->capropvar.pElems,numVariants*sizeof(PROPVARIANT),
                                       ARG_I_PTR,TRUE,TRUE);

        if (FAILED(hr)) {
            m_PropVar.capropvar.cElems = 0;
            m_PropVar.capropvar.pElems = NULL;
            return MSMQMarshalPtrError();
        }

        m_PropVar.capropvar.pElems = (PROPVARIANT*)m_MappedClientPtr.ptr();

        // MSMQ only deals with VT_LPWSTR as the variant types of this passed
        // in array.  Check now that this is the case before unmarshaling.
        for (i = 0; i < numVariants; i++) {
            if (m_PropVar.capropvar.pElems[i].vt != VT_LPWSTR) {
                return MSMQMarshalPtrError();
            }
        }

        m_variantArray = new CMarshalPropVariantIn[numVariants];
        if (! m_variantArray) {
            return;
        }

        for (i = 0; i < numVariants; i++) {
            m_variantArray[i].MarshallPropVar(&m_PropVar.capropvar.pElems[i],VT_LPWSTR);
            memcpy(&m_PropVar.capropvar.pElems[i],m_variantArray[i].GetPropVar(),sizeof(PROPVARIANT));
        }
    }
    break;

    default:
        // Unhandled type.  Don't raise an error since MSMQ code that
        // parses these types does later validity checks.  MSMQ also returns
        // different errors under different contexts so we can't handle globally here.
    break;
    }
}


CMarshalPropVariantIn::~CMarshalPropVariantIn() {
    if (m_variantArray)
        delete [] m_variantArray;
}

void ce::copy_in<SCPROPVAR*>::copy_arg_in(SCPROPVAR *pPropVar) {
    SVSUTIL_ASSERT(NULL == m_pServerPtr);
    SVSUTIL_ASSERT(FALSE == m_fInited);
    if (! pPropVar)
        return;

    //
    // Marshal the base pointer, make m_pServerPtr be the marshalled copy.
    //
    HRESULT hr = m_MappedClientPtr.Marshal(pPropVar,sizeof(SCPROPVAR),ARG_I_PTR,TRUE,TRUE);
    if (FAILED(hr))
        return MSMQMarshalPtrError();

    m_pServerPtr = (SCPROPVAR*)(m_MappedClientPtr.ptr());

    DWORD cProp = m_pServerPtr->cProp;

    if (cProp == 0) {
        // 0 params is legal, can be used to remove a msg from a queue
        m_pServerPtr->aPropID  = NULL;
        m_pServerPtr->aPropVar = NULL;
        m_pServerPtr->aStatus  = NULL;
        m_fInited = TRUE;
        return;
    }

    // PropID and PropVariant are required; status is optional.
    if (! m_pServerPtr->aPropID || !m_pServerPtr->aPropVar)
        return;

    //
    // Marshal aPropID and fixup pointer
    //
    hr = m_MarshalPropIds.Marshal(m_pServerPtr->aPropID, sizeof(PROPID)*cProp, ARG_I_PTR, TRUE, TRUE);
    if (FAILED(hr))
        return MSMQMarshalPtrError();

    m_pServerPtr->aPropID = (PROPID*)m_MarshalPropIds.ptr();

    //
    // Marshall the PROPVARIANT structure.
    //
    if (m_fCopyInPropVar) {
        // CopyIn when we do not modify the PROPVARIANT in servicesd.exe.
        // Used for instance when sending a message to a client.  Do the deep
        // copy of paramaters here.
        hr = m_MarshalPropVar.Marshal(m_pServerPtr->aPropVar,sizeof(SCPROPVAR)*cProp,ARG_I_PTR,TRUE,TRUE);
        if (FAILED(hr))
            return MSMQMarshalPtrError();

        m_pServerPtr->aPropVar = (PROPVARIANT*)m_MarshalPropVar.ptr();

        m_pPropVariants = new CMarshalPropVariantIn[cProp];
        if (NULL == m_pPropVariants)
            return;

        for (DWORD i = 0; i < cProp; i++) {
            m_pPropVariants[i].MarshallPropVar(&m_pServerPtr->aPropVar[i],m_pServerPtr->aPropID[i]);
            memcpy(&m_pServerPtr->aPropVar[i],m_pPropVariants[i].GetPropVar(),sizeof(PROPVARIANT));
        }
    }
    else {
        // Used when we want to modify the PROPVARIANT.  For various reasons
        // it is too hard to do the deep-copy at this stage, so leave that until
        // later.
        hr = m_MarshalPropVar.Marshal(m_pServerPtr->aPropVar,sizeof(SCPROPVAR)*cProp,ARG_IO_PTR,TRUE,TRUE);
        if (FAILED(hr))
            return MSMQMarshalPtrError();

        m_pServerPtr->aPropVar = (PROPVARIANT*)m_MarshalPropVar.ptr();
    }

    //
    // Marshal the aStatus and fixup pointer
    //
    if (m_pServerPtr->aStatus) {
        // The aStatus array is optional and may be NULL.  It is always copy_out
        hr = m_MarshalStatus.Marshal(m_pServerPtr->aStatus, sizeof(PROPID)*cProp, ARG_O_PTR, TRUE, TRUE);
        if (FAILED(hr))
            return MSMQMarshalPtrError();

        m_pServerPtr->aStatus = (HRESULT*)m_MarshalStatus.ptr();
    }

    m_fInited = TRUE;
}


