Exemple #1
0
        /// <summary>Gets the path names of the private queues on a computer, the local computer is the default.</summary>
        public static string[] GetPrivateQueuePaths(string machine = null)
        {
            var props = new MessageProperties(6, Native.MANAGEMENT_BASE + 1);

            props.SetNull(Native.MANAGEMENT_PRIVATEQ);
            int status = Native.MgmtGetInfo(machine, "MACHINE", props.Allocate());

            props.Free();
            if (Native.IsError(status))
            {
                throw new QueueException(status);
            }

            IntPtr arrayPtr  = props.GetStringVectorBasePointer(Native.MANAGEMENT_PRIVATEQ);
            uint   numQueues = props.GetStringVectorLength(Native.MANAGEMENT_PRIVATEQ);
            var    queues    = new string[numQueues];

            for (int i = 0; i < numQueues; i++)
            {
                IntPtr pathPtr = Marshal.ReadIntPtr((IntPtr)((long)arrayPtr + i * IntPtr.Size));
                queues[i] = Marshal.PtrToStringUni(pathPtr);
                Native.FreeMemory(pathPtr);
            }

            Native.FreeMemory(arrayPtr);
            return(queues);
        }
        /// <summary>
        /// Asks MSMQ to attempt to deliver a message.
        /// To ensure the message reached the queue you need to check acknowledgement messages sent to the <see cref="Message.AdministrationQueue"/>
        /// </summary>
        /// <param name="message">The message to try to send</param>
        /// <param name="transaction">can be NULL for no transaction, a <see cref="QueueTransaction"/>, <see cref="QueueTransaction.Single"/>, or <see cref="QueueTransaction.Dtc"/>.</param>
        public void Write(Message message, QueueTransaction transaction = null)
        {
            Contract.Requires(message != null);

            message.Props.PrepareToSend();
            var props = message.Props.Allocate();

            try
            {
                int    res;
                IntPtr txnHandle;
                if (transaction.TryGetHandle(out txnHandle))
                {
                    res = Native.SendMessage(_handle, props, txnHandle);
                }
                else
                {
                    res = Native.SendMessage(_handle, props, transaction.InternalTransaction);
                }

                if (Native.IsError(res))
                {
                    throw new QueueException(res);
                }
            }
            finally
            {
                message.Props.Free();
            }
        }
Exemple #3
0
        private static QueueInformation GetInfo(string formatName)
        {
            var props = new QueueProperties();

            //props.SetNull(Native.QUEUE_PROPID_CREATE_TIME);
            props.SetNull(Native.QUEUE_PROPID_LABEL);

            int status = Native.GetQueueProperties(formatName, props.Allocate());

            props.Free();
            if (Native.IsError(status))
            {
                throw new QueueException(status);
            }

            string label  = "";
            IntPtr handle = props.GetIntPtr(Native.QUEUE_PROPID_LABEL);

            if (handle != IntPtr.Zero)
            {
                label = Marshal.PtrToStringUni(handle);
                Native.FreeMemory(handle);
            }

            return(new QueueInformation {
                FormatName = formatName, Label = label
            });
        }
Exemple #4
0
        /// <summary>Move the message specified by <paramref name="lookupId"/> from <paramref name="sourceQueue"/> to the <paramref name="targetQueue"/>.</summary>
        /// <remarks>
        /// Moving message is 10 to 100 times faster than sending the message to another queue.
        /// Within a transaction you cannot receive a message that you moved to a subqueue.
        /// </remarks>
        public static void MoveMessage(QueueReader sourceQueue, SubQueue targetQueue, long lookupId, QueueTransaction transaction = null)
        {
            Contract.Requires(sourceQueue != null);
            Contract.Requires(targetQueue != null);

            if (sourceQueue.IsClosed)
            {
                throw new ObjectDisposedException(nameof(sourceQueue));
            }
            if (targetQueue.IsClosed)
            {
                throw new ObjectDisposedException(nameof(targetQueue));
            }

            int    res;
            IntPtr txnHandle;

            if (transaction.TryGetHandle(out txnHandle))
            {
                res = Native.MoveMessage(sourceQueue._handle, targetQueue.MoveHandle, lookupId, txnHandle);
            }
            else
            {
                res = Native.MoveMessage(sourceQueue._handle, targetQueue.MoveHandle, lookupId, transaction.InternalTransaction);
            }

            if (Native.IsError(res))
            {
                throw new QueueException(res);
            }
        }
        /// <summary>Creates a new cursor for queue represented by the <paramref name="reader"/>.</summary>
        public QueueCursor(QueueReader reader)
        {
            Contract.Requires(reader != null);
            _reader = reader;

            int res = Native.CreateCursor(reader._handle, out _cursorHandle);

            if (Native.IsError(res))
            {
                throw new QueueException(res);
            }
        }
        /// <summary>Tries to peek (or receive) a message using the queue-specific <paramref name="lookupId"/></summary>
        /// <remarks>Within a transaction you cannot receive a message that you moved to a subqueue within the same transaction</remarks>
        /// <param name="properties">The properties to read</param>
        /// <param name="lookupId">The <see cref="Message.LookupId"/> of the message to read</param>
        /// <param name="action">Receive or peek a message?</param>
        /// <param name="timeout">The time allowed, defaults to infinite.  Use <see cref="TimeSpan.Zero"/> to return without waiting</param>
        /// <param name="transaction">can be NULL for no transaction, a <see cref="QueueTransaction"/>, <see cref="QueueTransaction.Single"/>, or <see cref="QueueTransaction.Dtc"/>.</param>
        /// <returns>The message, or NULL if the message was not found or the receive times out</returns>
        public unsafe Message Lookup(Properties properties, long lookupId, LookupAction action = LookupAction.ReceiveCurrent, TimeSpan?timeout = null, QueueTransaction transaction = null)
        {
            if (IsClosed)
            {
                throw new ObjectDisposedException(nameof(Queue));
            }

            uint timeoutMS = TimeoutInMs(timeout);
            var  msg       = new Message();
            int  res;

            msg.Props.SetForRead(properties);
            for (;;) // loop because we might need to adjust memory size
            {
                var props = msg.Props.Allocate();
                try
                {
                    IntPtr txnHandle;
                    if (transaction.TryGetHandle(out txnHandle))
                    {
                        res = Native.ReceiveMessageByLookupId(_handle, lookupId, action, props, null, null, txnHandle);
                    }
                    else
                    {
                        res = Native.ReceiveMessageByLookupId(_handle, lookupId, action, props, null, null, transaction.InternalTransaction);
                    }
                }
                finally
                {
                    msg.Props.Free();
                }

                if ((ErrorCode)res == ErrorCode.IOTimeout || (ErrorCode)res == ErrorCode.MessageNotFound)
                {
                    return(null);
                }

                if (Native.NotEnoughMemory(res))
                {
                    msg.Props.IncreaseBufferSize();
                    continue; // try again
                }

                if (Native.IsError(res))
                {
                    throw new QueueException(res);
                }

                msg.Props.ResizeBody();
                return(msg);
            }
        }
        /// <summary>
        /// Sends a negative acknowledgement of <see cref="MessageClass.ReceiveRejected"/> to the <see cref="Message.AdministrationQueue"/> when the transaction is committed.
        /// NOTE: Must be called in the scope of a the message MUST have been received in the scope of a transaction.
        /// </summary>
        public void MarkRejected(long lookupId)
        {
            if (IsClosed)
            {
                throw new ObjectDisposedException(nameof(Queue));
            }

            int res = Native.MarkMessageRejected(_handle, lookupId);

            if (Native.IsError(res))
            {
                throw new QueueException(res);
            }
        }
Exemple #8
0
        /// <summary>Returns the transactional property of the queue</summary>
        public static QueueTransactional IsTransactional(string formatName)
        {
            Contract.Requires(formatName != null);
            var props = new QueueProperties();

            props.SetByte(Native.QUEUE_PROPID_TRANSACTION, 0);
            int status = Native.GetQueueProperties(formatName, props.Allocate());

            props.Free();
            if (Native.IsError(status))
            {
                throw new QueueException(status);
            }

            return((QueueTransactional)props.GetByte(Native.QUEUE_PROPID_TRANSACTION));
        }
Exemple #9
0
        /// <summary>Tries to delete an existing message queue, returns TRUE if the queue was deleted, FALSE if the queue does not exists</summary>
        /// <param name="formatName">The format name (NOT path name) of the queue</param>
        public static bool TryDelete(string formatName)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(formatName));

            int res = Native.DeleteQueue(formatName);

            if ((ErrorCode)res == ErrorCode.QueueNotFound)
            {
                return(false);
            }

            if (Native.IsError(res))
            {
                throw new QueueException(res);
            }

            return(true);
        }
Exemple #10
0
        /// <summary>Creates a message queue (if it does not already exist), returning the format name of the queue.</summary>
        /// <param name="path">the path (NOT format name) of the queue</param>
        /// <param name="transactional">create a transactional queue or not?</param>
        /// <param name="quotaKB">Maximum size of the queue, in KB, defaults to 20MB</param>
        /// <param name="label">the label to add to the queue</param>
        /// <param name="multicast">the multicast address to attach to the queue</param>
        public static string TryCreate(string path, QueueTransactional transactional, int quotaKB = 20000, string label = null, IPEndPoint multicast = null)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(path));
            Contract.Requires(label == null || label.Length < 125);
            Contract.Ensures(Contract.Result <string>() != null);

            const int MaxLabelLength = 124;

            //Create properties.
            var properties = new QueueProperties();

            properties.SetString(Native.QUEUE_PROPID_PATHNAME, path);
            properties.SetByte(Native.QUEUE_PROPID_TRANSACTION, (byte)transactional);
            properties.SetUInt(Native.QUEUE_PROPID_QUOTA, quotaKB);
            if (label != null)
            {
                properties.SetString(Native.QUEUE_PROPID_LABEL, label);
            }
            if (multicast != null)
            {
                properties.SetString(Native.QUEUE_PROPID_MULTICAST_ADDRESS, $"{multicast.Address}:{multicast.Port}");
            }

            var formatName = new StringBuilder(MaxLabelLength);
            int len        = MaxLabelLength;

            //Try to create queue.
            int res = Native.CreateQueue(IntPtr.Zero, properties.Allocate(), formatName, ref len);

            properties.Free();

            if ((ErrorCode)res == ErrorCode.QueueExists)
            {
                return(PathToFormatName(path));
            }

            if (Native.IsError(res))
            {
                throw new QueueException(res);
            }

            formatName.Length = len;
            return(formatName.ToString());
        }
Exemple #11
0
        public unsafe Task <Message> ReceiveAsync()
        {
            // create overlapped with callback that sets the task complete source
            var overlapped       = new Overlapped();
            var nativeOverlapped = overlapped.Pack(EndReceive, null);

            try
            {
                for (;;)
                {
                    // receive, may complete synchronously or call the async callback on the overlapped defined above
                    int res = Native.ReceiveMessage(handle, timeoutMS, action, Props, nativeOverlapped, null, cursor, IntPtr.Zero);

                    // successfully completed synchronously but no enough memory
                    if (Native.NotEnoughMemory(res))
                    {
                        Message.Props.Free();
                        Message.Props.IncreaseBufferSize();
                        Props = Message.Props.Allocate();
                        continue; // try again
                    }

                    if (Native.IsError(res))
                    {
                        Message.Props.Free();
                        Overlapped.Free(nativeOverlapped);
                        Tcs.TrySetException(new QueueException(unchecked (res))); // we really want Task.FromException...
                        return(Tcs.Task);
                    }

                    return(Tcs.Task);
                }
            }
            catch (ObjectDisposedException ex)
            {
                Tcs.TrySetException(new QueueException(ErrorCode.OperationCanceled));
                return(Tcs.Task);
            }
        }
Exemple #12
0
        public unsafe void EndReceive(uint code, uint bytes, NativeOverlapped *native)
        {
            Overlapped.Free(native);
            Message.Props.Free();

            lock (Outstanding)
                Outstanding.Remove(this);

            if (code == 995) // operation aborted
            {
                Tcs.TrySetException(new QueueException(ErrorCode.OperationCanceled));
                return;
            }

            var result = Native.GetOverlappedResult(native);

            try
            {
                switch (result)
                {
                case 0:
                    Message.Props.ResizeBody();
                    Tcs.TrySetResult(Message);
                    break;

                case (int)ErrorCode.InsufficientResources:
                    Tcs.SetException(new OutOfMemoryException("async receive operation reported InsufficientResources"));
                    break;

                case (int)ErrorCode.IOTimeout:
                    Tcs.TrySetResult(null);
                    break;

                default:
                    // successfully completed but no enough memory
                    if (Native.NotEnoughMemory(result))
                    {
                        Message.Props.Free();
                        Message.Props.IncreaseBufferSize();
                        Props = Message.Props.Allocate();
                        var overlapped       = new Overlapped();
                        var nativeOverlapped = overlapped.Pack(EndReceive, null);
                        int res = Native.ReceiveMessage(handle, timeoutMS, action, Props, nativeOverlapped, null, cursor, IntPtr.Zero);

                        if (res == MQ_INFORMATION_OPERATION_PENDING)        // running asynchronously
                        {
                            return;
                        }

                        // call completed synchronously
                        Message.Props.Free();
                        Overlapped.Free(nativeOverlapped);

                        if (!Native.IsError(res))
                        {
                            Message.Props.ResizeBody();
                            Tcs.TrySetResult(Message);
                            return;
                        }
                    }

                    // some other error
                    Tcs.TrySetException(new QueueException(unchecked ((int)code)));    // or do we use the result?
                    break;
                }
            }
            catch (ObjectDisposedException ex)
            {
                Tcs.TrySetException(new QueueException(ErrorCode.OperationCanceled));
            }
        }