/// <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(); } }
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 }); }
/// <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); } }
/// <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)); }
/// <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); }
/// <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()); }
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); } }
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)); } }