//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Channels { using System.Runtime; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.ServiceModel; using System.ServiceModel.Diagnostics; using System.Text; using System.Threading; using System.Transactions; enum MsmqTransactionMode { None, // do not use a transaction Single, // create a single message transaction CurrentOrSingle, // use Transaction.Current if set, Single otherwise CurrentOrNone, // use Transaction.Current if set, None otherwise CurrentOrThrow, // use Transaction.Current if set, throw otherwise } class MsmqQueue : IDisposable { MsmqQueueHandle handle; bool isBoundToCompletionPort; bool isAsyncEnabled; protected int shareMode; protected string formatName; protected int accessMode; public MsmqQueue(string formatName, int accessMode) { this.formatName = formatName; this.accessMode = accessMode; this.shareMode = UnsafeNativeMethods.MQ_DENY_NONE; } public MsmqQueue(string formatName, int accessMode, int shareMode) { this.formatName = formatName; this.accessMode = accessMode; this.shareMode = shareMode; } protected object ThisLock { get { return this; } } public string FormatName { get { return this.formatName; } } public override string ToString() { return this.formatName; } public void Dispose() { lock (this.ThisLock) { CloseQueue(); } } internal void EnsureOpen() { GetHandle(); } MsmqQueueHandle GetHandleForAsync(out bool useCompletionPort) { lock (this.ThisLock) { if (this.handle == null) { this.handle = OpenQueue(); } if (!this.isAsyncEnabled) { if (IsCompletionPortSupported(this.handle)) { ThreadPool.BindHandle(this.handle); this.isBoundToCompletionPort = true; } this.isAsyncEnabled = true; } useCompletionPort = this.isBoundToCompletionPort; return this.handle; } } protected MsmqQueueHandle GetHandle() { lock (this.ThisLock) { if (this.handle == null) { this.handle = OpenQueue(); } return this.handle; } } static bool IsCompletionPortSupported(MsmqQueueHandle handle) { // if it's a kernel handle, then it supports completion ports int flags; #pragma warning suppress 56523 return UnsafeNativeMethods.GetHandleInformation(handle, out flags) != 0; } [ResourceConsumption(ResourceScope.Machine)] internal virtual MsmqQueueHandle OpenQueue() { MsmqQueueHandle handle; int error = UnsafeNativeMethods.MQOpenQueue(this.formatName, this.accessMode, this.shareMode, out handle); if (error != 0) { Utility.CloseInvalidOutSafeHandle(handle); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqOpenError, MsmqError.GetErrorString(error)), error)); } MsmqDiagnostics.QueueOpened(this.formatName); return handle; } public virtual void CloseQueue() { if (this.handle != null) { CloseQueue(this.handle); this.handle = null; this.isBoundToCompletionPort = false; this.isAsyncEnabled = false; MsmqDiagnostics.QueueClosed(this.formatName); } } void CloseQueue(MsmqQueueHandle handle) { handle.Dispose(); } protected void HandleIsStale(MsmqQueueHandle handle) { lock (this.ThisLock) { if (this.handle == handle) { CloseQueue(); } } } public static void GetMsmqInformation(ref Version version, ref bool activeDirectoryEnabled) { PrivateComputerProperties properties = new PrivateComputerProperties(); using (properties) { IntPtr nativePropertiesPointer = properties.Pin(); try { int error = UnsafeNativeMethods.MQGetPrivateComputerInformation(null, nativePropertiesPointer); if (error != 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString( SR.MsmqGetPrivateComputerInformationError, MsmqError.GetErrorString(error)), error)); } int packedVersion = properties.Version.Value; version = new Version( packedVersion >> 24, (packedVersion & 0x00FF0000) >> 16, packedVersion & 0xFFFF); activeDirectoryEnabled = properties.ActiveDirectory.Value; } finally { properties.Unpin(); } } } public static bool IsReadable(string formatName, out MsmqException ex) { return SupportsAccessMode(formatName, UnsafeNativeMethods.MQ_RECEIVE_ACCESS, out ex); } public static bool IsWriteable(string formatName) { MsmqException ex; return SupportsAccessMode(formatName, UnsafeNativeMethods.MQ_SEND_ACCESS, out ex); } public static bool IsMoveable(string formatName) { MsmqException ex; return SupportsAccessMode(formatName, UnsafeNativeMethods.MQ_MOVE_ACCESS, out ex); } internal static bool IsQueueOpenable(string formatName, int accessMode, int shareMode, out int error) { MsmqQueueHandle handle; error = UnsafeNativeMethods.MQOpenQueue(formatName, accessMode, shareMode, out handle); if (error != 0) { Utility.CloseInvalidOutSafeHandle(handle); return false; } handle.Dispose(); return true; } static bool SupportsAccessMode(string formatName, int accessType, out MsmqException msmqException) { msmqException = null; try { using (MsmqQueue msmqQueue = new MsmqQueue(formatName, accessType)) { msmqQueue.GetHandle(); } } catch (Exception ex) { msmqException = ex as MsmqException; if (null != msmqException) { return false; } throw; } return true; } public static bool TryGetIsTransactional(string formatName, out bool isTransactional) { using (QueueTransactionProperties properties = new QueueTransactionProperties()) { IntPtr nativePropertiesPointer = properties.Pin(); try { if (UnsafeNativeMethods.MQGetQueueProperties(formatName, nativePropertiesPointer) == 0) { isTransactional = properties.Transaction.Value != UnsafeNativeMethods.MQ_TRANSACTIONAL_NONE; return true; } else { isTransactional = false; MsmqDiagnostics.QueueTransactionalStatusUnknown(formatName); return false; } } finally { properties.Unpin(); } } } protected static bool IsErrorDueToStaleHandle(int error) { switch (error) { case UnsafeNativeMethods.MQ_ERROR_STALE_HANDLE: case UnsafeNativeMethods.MQ_ERROR_INVALID_HANDLE: case UnsafeNativeMethods.MQ_ERROR_INVALID_PARAMETER: case UnsafeNativeMethods.MQ_ERROR_QUEUE_DELETED: return true; default: return false; } } protected static bool IsReceiveErrorDueToInsufficientBuffer(int error) { switch (error) { case UnsafeNativeMethods.MQ_ERROR_BUFFER_OVERFLOW: case UnsafeNativeMethods.MQ_INFORMATION_FORMATNAME_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_SENDERID_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_SECURITY_DESCRIPTOR_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_USER_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_SENDER_CERT_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_RESULT_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_LABEL_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_SYMM_KEY_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_SIGNATURE_BUFFER_TOO_SMALL: case UnsafeNativeMethods.MQ_ERROR_PROV_NAME_BUFFER_TOO_SMALL: return true; default: return false; } } public void MarkMessageRejected(long lookupId) { MsmqQueueHandle handle = GetHandle(); int error = 0; try { error = UnsafeNativeMethods.MQMarkMessageRejected(handle, lookupId); } catch (ObjectDisposedException ex) { MsmqDiagnostics.ExpectedException(ex); } if (error != 0) { if (IsErrorDueToStaleHandle(error)) { HandleIsStale(handle); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqSendError, MsmqError.GetErrorString(error)), error)); } } int TryMoveMessageDtcTransacted(long lookupId, MsmqQueueHandle sourceQueueHandle, MsmqQueueHandle destinationQueueHandle, MsmqTransactionMode transactionMode) { IDtcTransaction dtcTransaction = GetNativeTransaction(transactionMode); if (dtcTransaction != null) { try { return UnsafeNativeMethods.MQMoveMessage(sourceQueueHandle, destinationQueueHandle, lookupId, dtcTransaction); } finally { Marshal.ReleaseComObject(dtcTransaction); } } else { return UnsafeNativeMethods.MQMoveMessage(sourceQueueHandle, destinationQueueHandle, lookupId, (IntPtr)GetTransactionConstant(transactionMode)); } } public MoveReceiveResult TryMoveMessage(long lookupId, MsmqQueue destinationQueue, MsmqTransactionMode transactionMode) { MsmqQueueHandle sourceQueueHandle = GetHandle(); MsmqQueueHandle destinationQueueHandle = destinationQueue.GetHandle(); int error; try { if (RequiresDtcTransaction(transactionMode)) { error = TryMoveMessageDtcTransacted(lookupId, sourceQueueHandle, destinationQueueHandle, transactionMode); } else { error = UnsafeNativeMethods.MQMoveMessage(sourceQueueHandle, destinationQueueHandle, lookupId, (IntPtr)GetTransactionConstant(transactionMode)); } } catch (ObjectDisposedException ex) { MsmqDiagnostics.ExpectedException(ex); return MoveReceiveResult.Succeeded; } if (error != 0) { if (error == UnsafeNativeMethods.MQ_ERROR_MESSAGE_NOT_FOUND) return MoveReceiveResult.MessageNotFound; else if (error == UnsafeNativeMethods.MQ_ERROR_MESSAGE_LOCKED_UNDER_TRANSACTION) return MoveReceiveResult.MessageLockedUnderTransaction; else if (IsErrorDueToStaleHandle(error)) { HandleIsStale(sourceQueueHandle); destinationQueue.HandleIsStale(destinationQueueHandle); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqSendError, MsmqError.GetErrorString(error)), error)); } return MoveReceiveResult.Succeeded; } public virtual ReceiveResult TryReceive(NativeMsmqMessage message, TimeSpan timeout, MsmqTransactionMode transactionMode) { return TryReceiveInternal(message, timeout, transactionMode, UnsafeNativeMethods.MQ_ACTION_RECEIVE); } ReceiveResult TryReceiveInternal(NativeMsmqMessage message, TimeSpan timeout, MsmqTransactionMode transactionMode, int action) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); MsmqQueueHandle handle = GetHandle(); while (true) { int error = ReceiveCore(handle, message, timeoutHelper.RemainingTime(), transactionMode, action); if (0 == error) return ReceiveResult.MessageReceived; if (IsReceiveErrorDueToInsufficientBuffer(error)) { message.GrowBuffers(); continue; } else if (error == UnsafeNativeMethods.MQ_ERROR_IO_TIMEOUT) { return ReceiveResult.Timeout; } else if (error == UnsafeNativeMethods.MQ_ERROR_OPERATION_CANCELLED) { return ReceiveResult.OperationCancelled; } else if (error == UnsafeNativeMethods.MQ_ERROR_INVALID_HANDLE) { // should happen only if racing with Close return ReceiveResult.OperationCancelled; } else if (IsErrorDueToStaleHandle(error)) { HandleIsStale(handle); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqReceiveError, MsmqError.GetErrorString(error)), error)); } } public MoveReceiveResult TryReceiveByLookupId(long lookupId, NativeMsmqMessage message, MsmqTransactionMode transactionMode) { return this.TryReceiveByLookupId(lookupId, message, transactionMode, UnsafeNativeMethods.MQ_LOOKUP_RECEIVE_CURRENT); } public MoveReceiveResult TryReceiveByLookupId(long lookupId, NativeMsmqMessage message, MsmqTransactionMode transactionMode, int action) { MsmqQueueHandle handle = GetHandle(); int error = 0; while (true) { try { error = ReceiveByLookupIdCore(handle, lookupId, message, transactionMode, action); } catch (ObjectDisposedException ex) { // ---- with Close MsmqDiagnostics.ExpectedException(ex); return MoveReceiveResult.Succeeded; } if (0 == error) { return MoveReceiveResult.Succeeded; } if (IsReceiveErrorDueToInsufficientBuffer(error)) { message.GrowBuffers(); continue; } else if (UnsafeNativeMethods.MQ_ERROR_MESSAGE_NOT_FOUND == error) { return MoveReceiveResult.MessageNotFound; } else if (UnsafeNativeMethods.MQ_ERROR_MESSAGE_LOCKED_UNDER_TRANSACTION == error) { return MoveReceiveResult.MessageLockedUnderTransaction; } else if (IsErrorDueToStaleHandle(error)) { HandleIsStale(handle); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqReceiveError, MsmqError.GetErrorString(error)), error)); } } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] protected unsafe int ReceiveByLookupIdCoreDtcTransacted(MsmqQueueHandle handle, long lookupId, NativeMsmqMessage message, MsmqTransactionMode transactionMode, int action) { IDtcTransaction dtcTransaction = GetNativeTransaction(transactionMode); IntPtr nativePropertiesPointer = message.Pin(); try { if (dtcTransaction != null) { try { return UnsafeNativeMethods.MQReceiveMessageByLookupId(handle, lookupId, action, nativePropertiesPointer, null, IntPtr.Zero, dtcTransaction); } finally { Marshal.ReleaseComObject(dtcTransaction); } } else { return UnsafeNativeMethods.MQReceiveMessageByLookupId(handle, lookupId, action, nativePropertiesPointer, null, IntPtr.Zero, (IntPtr)GetTransactionConstant(transactionMode)); } } finally { message.Unpin(); } } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] unsafe int ReceiveByLookupIdCore(MsmqQueueHandle handle, long lookupId, NativeMsmqMessage message, MsmqTransactionMode transactionMode, int action) { if (RequiresDtcTransaction(transactionMode)) { return ReceiveByLookupIdCoreDtcTransacted(handle, lookupId, message, transactionMode, action); } else { IntPtr nativePropertiesPointer = message.Pin(); try { return UnsafeNativeMethods.MQReceiveMessageByLookupId(handle, lookupId, action, nativePropertiesPointer, null, IntPtr.Zero, (IntPtr)GetTransactionConstant(transactionMode)); } finally { message.Unpin(); } } } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] unsafe int ReceiveCoreDtcTransacted(MsmqQueueHandle handle, NativeMsmqMessage message, TimeSpan timeout, MsmqTransactionMode transactionMode, int action) { IDtcTransaction dtcTransaction = GetNativeTransaction(transactionMode); int timeoutInMilliseconds = TimeoutHelper.ToMilliseconds(timeout); IntPtr nativePropertiesPointer = message.Pin(); try { if (dtcTransaction != null) { try { return UnsafeNativeMethods.MQReceiveMessage(handle.DangerousGetHandle(), timeoutInMilliseconds, action, nativePropertiesPointer, null, IntPtr.Zero, IntPtr.Zero, dtcTransaction); } finally { Marshal.ReleaseComObject(dtcTransaction); } } else { return UnsafeNativeMethods.MQReceiveMessage(handle.DangerousGetHandle(), timeoutInMilliseconds, action, nativePropertiesPointer, null, IntPtr.Zero, IntPtr.Zero, (IntPtr)GetTransactionConstant(transactionMode)); } } finally { message.Unpin(); } } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] unsafe int ReceiveCore(MsmqQueueHandle handle, NativeMsmqMessage message, TimeSpan timeout, MsmqTransactionMode transactionMode, int action) { if (RequiresDtcTransaction(transactionMode)) { return ReceiveCoreDtcTransacted(handle, message, timeout, transactionMode, action); } else { int timeoutInMilliseconds = TimeoutHelper.ToMilliseconds(timeout); IntPtr nativePropertiesPointer = message.Pin(); try { return UnsafeNativeMethods.MQReceiveMessage(handle.DangerousGetHandle(), timeoutInMilliseconds, action, nativePropertiesPointer, null, IntPtr.Zero, IntPtr.Zero, (IntPtr)GetTransactionConstant(transactionMode)); } finally { message.Unpin(); } } } protected IDtcTransaction GetNativeTransaction(MsmqTransactionMode transactionMode) { Transaction transaction = Transaction.Current; if (transaction != null) { return TransactionInterop.GetDtcTransaction(transaction); } if (transactionMode == MsmqTransactionMode.CurrentOrThrow) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MsmqTransactionRequired))); } return null; } public ReceiveResult TryPeek(NativeMsmqMessage message, TimeSpan timeout) { return TryReceiveInternal(message, timeout, MsmqTransactionMode.None, UnsafeNativeMethods.MQ_ACTION_PEEK_CURRENT); } bool RequiresDtcTransaction(MsmqTransactionMode transactionMode) { switch (transactionMode) { case MsmqTransactionMode.None: case MsmqTransactionMode.Single: return false; case MsmqTransactionMode.CurrentOrSingle: case MsmqTransactionMode.CurrentOrNone: case MsmqTransactionMode.CurrentOrThrow: return true; default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("transactionMode")); } } int GetTransactionConstant(MsmqTransactionMode transactionMode) { switch (transactionMode) { case MsmqTransactionMode.CurrentOrNone: case MsmqTransactionMode.None: return UnsafeNativeMethods.MQ_NO_TRANSACTION; case MsmqTransactionMode.Single: case MsmqTransactionMode.CurrentOrSingle: return UnsafeNativeMethods.MQ_SINGLE_MESSAGE; default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("transactionMode")); } } int SendDtcTransacted(NativeMsmqMessage message, MsmqTransactionMode transactionMode) { IDtcTransaction dtcTransaction = GetNativeTransaction(transactionMode); MsmqQueueHandle handle = GetHandle(); IntPtr nativePropertiesPointer = message.Pin(); try { if (dtcTransaction != null) { try { return UnsafeNativeMethods.MQSendMessage(handle, nativePropertiesPointer, dtcTransaction); } finally { Marshal.ReleaseComObject(dtcTransaction); } } else { return UnsafeNativeMethods.MQSendMessage(handle, nativePropertiesPointer, (IntPtr)GetTransactionConstant(transactionMode)); } } finally { message.Unpin(); } } public void Send(NativeMsmqMessage message, MsmqTransactionMode transactionMode) { int error = 0; if (RequiresDtcTransaction(transactionMode)) { error = SendDtcTransacted(message, transactionMode); } else { MsmqQueueHandle handle = GetHandle(); IntPtr nativePropertiesPointer = message.Pin(); try { error = UnsafeNativeMethods.MQSendMessage(handle, nativePropertiesPointer, (IntPtr)GetTransactionConstant(transactionMode)); } finally { message.Unpin(); } } if (error != 0) { if (IsErrorDueToStaleHandle(error)) { HandleIsStale(handle); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqSendError, MsmqError.GetErrorString(error)), error)); } } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] unsafe int ReceiveCoreAsync(MsmqQueueHandle handle, IntPtr nativePropertiesPointer, TimeSpan timeout, int action, NativeOverlapped* nativeOverlapped, UnsafeNativeMethods.MQReceiveCallback receiveCallback) { int timeoutInMilliseconds = TimeoutHelper.ToMilliseconds(timeout); return UnsafeNativeMethods.MQReceiveMessage(handle, timeoutInMilliseconds, action, nativePropertiesPointer, nativeOverlapped, receiveCallback, IntPtr.Zero, (IntPtr)UnsafeNativeMethods.MQ_NO_TRANSACTION); } public IAsyncResult BeginTryReceive(NativeMsmqMessage message, TimeSpan timeout, AsyncCallback callback, object state) { return new TryReceiveAsyncResult(this, message, timeout, UnsafeNativeMethods.MQ_ACTION_RECEIVE, callback, state); } public ReceiveResult EndTryReceive(IAsyncResult result) { return TryReceiveAsyncResult.End(result); } public IAsyncResult BeginPeek(NativeMsmqMessage message, TimeSpan timeout, AsyncCallback callback, object state) { return new TryReceiveAsyncResult(this, message, timeout, UnsafeNativeMethods.MQ_ACTION_PEEK_CURRENT, callback, state); } public ReceiveResult EndPeek(IAsyncResult result) { return TryReceiveAsyncResult.End(result); } class TryReceiveAsyncResult : AsyncResult { MsmqQueue msmqQueue; int action; TimeoutHelper timeoutHelper; NativeMsmqMessage message; unsafe NativeOverlapped* nativeOverlapped = null; MsmqQueueHandle handle; ReceiveResult receiveResult; unsafe static IOCompletionCallback onPortedCompletion = Fx.ThunkCallback(new IOCompletionCallback(OnPortedCompletion)); unsafe static UnsafeNativeMethods.MQReceiveCallback onNonPortedCompletion; [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] public TryReceiveAsyncResult(MsmqQueue msmqQueue, NativeMsmqMessage message, TimeSpan timeout, int action, AsyncCallback callback, object state) : base(callback, state) { this.msmqQueue = msmqQueue; this.message = message; this.action = action; this.timeoutHelper = new TimeoutHelper(timeout); StartReceive(true); } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] unsafe ~TryReceiveAsyncResult() { if (null != this.nativeOverlapped && ! Environment.HasShutdownStarted && ! AppDomain.CurrentDomain.IsFinalizingForUnload()) { Overlapped.Free(this.nativeOverlapped); } } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] unsafe void StartReceive(bool synchronously) { bool useCompletionPort; try { this.handle = this.msmqQueue.GetHandleForAsync(out useCompletionPort); } catch (MsmqException ex) { OnCompletion(ex.ErrorCode, synchronously); return; } if (null != nativeOverlapped) { Fx.Assert("---- in StartReceive"); } IntPtr nativePropertiesPointer = this.message.Pin(); nativeOverlapped = new Overlapped(0, 0, IntPtr.Zero, this).UnsafePack(onPortedCompletion, this.message.GetBuffersForAsync()); int error; try { if (useCompletionPort) { error = msmqQueue.ReceiveCoreAsync(this.handle, nativePropertiesPointer, this.timeoutHelper.RemainingTime(), this.action, nativeOverlapped, null); } else { if (onNonPortedCompletion == null) { onNonPortedCompletion = new UnsafeNativeMethods.MQReceiveCallback(OnNonPortedCompletion); } error = msmqQueue.ReceiveCoreAsync(this.handle, nativePropertiesPointer, this.timeoutHelper.RemainingTime(), this.action, nativeOverlapped, onNonPortedCompletion); } } catch (ObjectDisposedException ex) { // if Close ----s with the async Receive, it is possible that SafeHandle will throw ObjectDisposedException // the behavior should be same as if operation was just cancelled (the channel will return no message) MsmqDiagnostics.ExpectedException(ex); error = UnsafeNativeMethods.MQ_ERROR_OPERATION_CANCELLED; } if (error != 0) { if (error != UnsafeNativeMethods.MQ_INFORMATION_OPERATION_PENDING) { Overlapped.Free(nativeOverlapped); nativeOverlapped = null; GC.SuppressFinalize(this); OnCompletion(error, synchronously); } } } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] unsafe static void OnNonPortedCompletion(int error, IntPtr handle, int timeout, int action, IntPtr props, NativeOverlapped* nativeOverlapped, IntPtr cursor) { ThreadPool.UnsafeQueueNativeOverlapped(nativeOverlapped); } [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] unsafe static void OnPortedCompletion(uint error, uint numBytes, NativeOverlapped* nativeOverlapped) { Overlapped overlapped = Overlapped.Unpack(nativeOverlapped); TryReceiveAsyncResult result = (TryReceiveAsyncResult)overlapped.AsyncResult; if (error != 0) { error = (uint)UnsafeNativeMethods.MQGetOverlappedResult(nativeOverlapped); } Overlapped.Free(nativeOverlapped); result.nativeOverlapped = null; #pragma warning suppress 56508 // Suppression justified. Presharp warning concerns different scenario. GC.SuppressFinalize(result); result.OnCompletion((int)error, false); } void OnCompletion(int error, bool completedSynchronously) { Exception completionException = null; this.receiveResult = ReceiveResult.MessageReceived; try { if (error != 0) { if (error == UnsafeNativeMethods.MQ_ERROR_IO_TIMEOUT) { this.receiveResult = ReceiveResult.Timeout; } else if (error == UnsafeNativeMethods.MQ_ERROR_OPERATION_CANCELLED) { this.receiveResult = ReceiveResult.OperationCancelled; } else { if (IsReceiveErrorDueToInsufficientBuffer(error)) { this.message.Unpin(); message.GrowBuffers(); StartReceive(completedSynchronously); return; } else if (IsErrorDueToStaleHandle(error)) { this.msmqQueue.HandleIsStale(this.handle); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqReceiveError, MsmqError.GetErrorString(error)), error)); } } } catch (Exception e) { if (e is NullReferenceException || e is SEHException) throw; completionException = e; } this.message.Unpin(); Complete(completedSynchronously, completionException); } public static ReceiveResult End(IAsyncResult result) { TryReceiveAsyncResult thisPtr = AsyncResult.End(result); return thisPtr.receiveResult; } } class QueueTransactionProperties : NativeMsmqMessage { ByteProperty transaction; public QueueTransactionProperties() : base(1) { this.transaction = new ByteProperty(this, UnsafeNativeMethods.PROPID_Q_TRANSACTION); } public ByteProperty Transaction { get { return this.transaction; } } } class PrivateComputerProperties : NativeMsmqMessage { IntProperty version; BooleanProperty activeDirectory; public PrivateComputerProperties() : base(2) { this.version = new IntProperty(this, UnsafeNativeMethods.PROPID_PC_VERSION); this.activeDirectory = new BooleanProperty(this, UnsafeNativeMethods.PROPID_PC_DS_ENABLED); } public IntProperty Version { get { return this.version; } } public BooleanProperty ActiveDirectory { get { return this.activeDirectory; } } } public enum MoveReceiveResult { Unknown, Succeeded, MessageNotFound, MessageLockedUnderTransaction } internal enum ReceiveResult { Unknown, MessageReceived, Timeout, OperationCancelled } } static class MsmqFormatName { const string systemMessagingLabelPrefix = "LABEL:"; const string systemMessagingFormatNamePrefix = "FORMATNAME:"; public static string ToSystemMessagingQueueName(string formatName) { return systemMessagingFormatNamePrefix + formatName; } public static string FromQueuePath(string queuePath) { int len = 256; StringBuilder buffer = new StringBuilder(len); int error = UnsafeNativeMethods.MQPathNameToFormatName(queuePath, buffer, ref len); if (UnsafeNativeMethods.MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL == error) { buffer = new StringBuilder(len); error = UnsafeNativeMethods.MQPathNameToFormatName(queuePath, buffer, ref len); } if (0 != error) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new MsmqException(SR.GetString(SR.MsmqPathLookupError, queuePath, MsmqError.GetErrorString(error)), error)); } return buffer.ToString(); } } }