|
//------------------------------------------------------------------------------
// <copyright file="MessageQueue.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Messaging
{
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.ComponentModel;
using System.Diagnostics;
using System;
using System.Configuration.Install;
using System.Messaging.Interop;
using Microsoft.Win32;
using System.ComponentModel.Design;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Security.Permissions;
using System.DirectoryServices;
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue"]/*' />
/// <devdoc>
/// <para>
/// Provides
/// access to a Message Queuing backend queue resource.
/// </para>
/// </devdoc>
[DefaultEvent("ReceiveCompleted"),
TypeConverterAttribute(typeof(System.Messaging.Design.MessageQueueConverter)),
Editor("System.Messaging.Design.QueuePathEditor", "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
InstallerTypeAttribute(typeof(MessageQueueInstaller)),
MessagingDescription(Res.MessageQueueDesc)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
public class MessageQueue : Component, IEnumerable
{
//Public constants
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.InfiniteTimeout"]/*' />
/// <devdoc>
/// <para>
/// Specifies that
/// there is no
/// timeout period for calls to peek or receive messages.
/// </para>
/// </devdoc>
public static readonly TimeSpan InfiniteTimeout = TimeSpan.FromMilliseconds(UInt32.MaxValue);
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.InfiniteQueueSize"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public static readonly long InfiniteQueueSize = UInt32.MaxValue;
//Internal members
private DefaultPropertiesToSend defaultProperties;
private MessagePropertyFilter receiveFilter;
private QueueAccessMode accessMode;
private int sharedMode;
private string formatName;
private string queuePath;
private string path;
private bool enableCache;
private QueuePropertyVariants properties;
private IMessageFormatter formatter;
// Double-checked locking pattern requires volatile for read/write synchronization
private static volatile string computerName;
internal static readonly Version OSVersion = Environment.OSVersion.Version;
internal static readonly Version WinXP = new Version(5, 1);
internal static readonly bool Msmq3OrNewer = OSVersion >= WinXP;
//Cached properties
private QueuePropertyFilter filter;
private bool authenticate;
private short basePriority;
private DateTime createTime;
private int encryptionLevel;
private Guid id;
private string label;
private string multicastAddress;
private DateTime lastModifyTime;
private long journalSize;
private long queueSize;
private Guid queueType;
private bool useJournaling;
private MQCacheableInfo mqInfo;
// Double-checked locking pattern requires volatile for read/write synchronization
//Async IO support
private volatile bool attached;
private bool useThreadPool;
private AsyncCallback onRequestCompleted;
private PeekCompletedEventHandler onPeekCompleted;
private ReceiveCompletedEventHandler onReceiveCompleted;
private ISynchronizeInvoke synchronizingObject;
// Double-checked locking pattern requires volatile for read/write synchronization
private volatile Hashtable outstandingAsyncRequests;
//Path sufixes
private static readonly string SUFIX_PRIVATE = "\\PRIVATE$";
private static readonly string SUFIX_JOURNAL = "\\JOURNAL$";
private static readonly string SUFIX_DEADLETTER = "\\DEADLETTER$";
private static readonly string SUFIX_DEADXACT = "\\XACTDEADLETTER$";
//Path prefixes
private static readonly string PREFIX_LABEL = "LABEL:";
private static readonly string PREFIX_FORMAT_NAME = "FORMATNAME:";
//Connection pooling support
private static CacheTable<string, string> formatNameCache =
new CacheTable<string, string>("formatNameCache", 4, new TimeSpan(0, 0, 100)); // path -> formatname
private static CacheTable<QueueInfoKeyHolder, MQCacheableInfo> queueInfoCache =
new CacheTable<QueueInfoKeyHolder, MQCacheableInfo>("queue info", 4, new TimeSpan(0, 0, 100)); // <formatname, accessMode> -> <readHandle. writeHandle, isTrans>
// Whidbey Beta 2 SECREVIEW (Dec 2004 Microsoft):
// Connection Cache can be a security vulnerability (see bug 422227)
// Therefore, disable it by default
private static bool enableConnectionCache = false;
// Double-checked locking pattern requires volatile for read/write synchronization
private volatile QueueInfoKeyHolder queueInfoKey = null;
//Code Acess Security support
private bool administerGranted;
private bool browseGranted;
private bool sendGranted;
private bool receiveGranted;
private bool peekGranted;
private object syncRoot = new object();
private static object staticSyncRoot = new object();
static MessageQueue()
{
try
{
using (TelemetryEventSource eventSource = new TelemetryEventSource())
{
eventSource.MessageQueue();
}
}
catch
{
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue"]/*' />
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/> class. To use the object instantiated by the default
/// constructor, the <see cref='System.Messaging.MessageQueue.Path'/>
/// property must be set.
/// </para>
/// </devdoc>
//
public MessageQueue()
{
this.path = String.Empty;
this.accessMode = QueueAccessMode.SendAndReceive;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue1"]/*' />
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/>
/// class that references the Message Queuing application resource specified by the
/// <paramref name="path"/>
/// parameter.
/// </para>
/// </devdoc>
public MessageQueue(string path)
: this(path, false, enableConnectionCache)
{
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue5"]/*' />
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/>
/// class that references the Message Queuing application resource specified by the
/// <paramref name="path"/> parameter and having the specifed access mode.
/// </para>
/// </devdoc>
public MessageQueue(string path, QueueAccessMode accessMode)
: this(path, false, enableConnectionCache, accessMode)
{
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue2"]/*' />
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/> class that references the
/// Message Queuing application resource specified by the <paramref name="path"/> parameter,
/// and has the specified queue read access restriction.
/// </para>
/// </devdoc>
public MessageQueue(string path, bool sharedModeDenyReceive)
: this(path, sharedModeDenyReceive, enableConnectionCache)
{
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue3"]/*' />
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/> class that references the
/// Message Queuing application resource specified by the <paramref name="path"/> parameter,
/// has the specified queue read access restriction and whether to cache handles
/// </para>
/// </devdoc>
public MessageQueue(string path, bool sharedModeDenyReceive, bool enableCache)
{
this.path = path;
this.enableCache = enableCache;
if (sharedModeDenyReceive)
{
this.sharedMode = NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE;
}
this.accessMode = QueueAccessMode.SendAndReceive;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue4"]/*' />
/// <devdoc>
/// <para>
/// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/> class that references the
/// Message Queuing application resource specified by the <paramref name="path"/> parameter,
/// has the specified queue read access restriction, whether to cache handles,
/// and specified access mode.
/// </para>
/// </devdoc>
public MessageQueue(string path, bool sharedModeDenyReceive,
bool enableCache, QueueAccessMode accessMode)
{
this.path = path;
this.enableCache = enableCache;
if (sharedModeDenyReceive)
{
this.sharedMode = NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE;
}
SetAccessMode(accessMode);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue3"]/*' />
/// <internalonly/>
internal MessageQueue(string path, Guid id)
{
PropertyFilter.Id = true;
this.id = id;
this.path = path;
this.accessMode = QueueAccessMode.SendAndReceive;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AccessMode"]/*' />
/// <devdoc>
/// <para>
/// Gets value specifying access mode of the queue
/// </para>
/// </devdoc>
public QueueAccessMode AccessMode
{
get
{
return this.accessMode;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Authenticate"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value specifying whether the queue only accepts authenticated
/// messages.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_Authenticate)]
public bool Authenticate
{
get
{
if (!PropertyFilter.Authenticate)
{
Properties.SetUI1(NativeMethods.QUEUE_PROPID_AUTHENTICATE, (byte)0);
GenerateQueueProperties();
this.authenticate = (Properties.GetUI1(NativeMethods.QUEUE_PROPID_AUTHENTICATE) != NativeMethods.QUEUE_AUTHENTICATE_NONE);
PropertyFilter.Authenticate = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_AUTHENTICATE);
}
return this.authenticate;
}
set
{
if (value)
Properties.SetUI1(NativeMethods.QUEUE_PROPID_AUTHENTICATE, (byte)NativeMethods.QUEUE_AUTHENTICATE_AUTHENTICATE);
else
Properties.SetUI1(NativeMethods.QUEUE_PROPID_AUTHENTICATE, (byte)NativeMethods.QUEUE_AUTHENTICATE_NONE);
SaveQueueProperties();
this.authenticate = value;
PropertyFilter.Authenticate = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_AUTHENTICATE);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BasePriority"]/*' />
/// <devdoc>
/// <para>Gets or sets a value indicating the base
/// priority used to route a public queue's messages over the network.</para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_BasePriority)]
public short BasePriority
{
get
{
if (!PropertyFilter.BasePriority)
{
Properties.SetI2(NativeMethods.QUEUE_PROPID_BASEPRIORITY, (short)0);
GenerateQueueProperties();
this.basePriority = properties.GetI2(NativeMethods.QUEUE_PROPID_BASEPRIORITY);
PropertyFilter.BasePriority = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_BASEPRIORITY);
}
return this.basePriority;
}
set
{
Properties.SetI2(NativeMethods.QUEUE_PROPID_BASEPRIORITY, value);
SaveQueueProperties();
this.basePriority = value;
PropertyFilter.BasePriority = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_BASEPRIORITY);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CanRead"]/*' />
/// <devdoc>
/// <para>
/// Gets a value indicating whether the <see cref='System.Messaging.MessageQueue'/>
/// has read permission.
/// </para>
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_CanRead)]
public bool CanRead
{
get
{
if (!browseGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Browse, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
browseGranted = true;
}
return MQInfo.CanRead;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CanWrite"]/*' />
/// <devdoc>
/// <para>
/// Gets a value indicating whether the <see cref='System.Messaging.MessageQueue'/>
/// has write permission.
/// </para>
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_CanWrite)]
public bool CanWrite
{
get
{
if (!browseGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Browse, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
browseGranted = true;
}
return MQInfo.CanWrite;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Category"]/*' />
/// <devdoc>
/// <para>Gets or sets the queue type.</para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_Category)]
public Guid Category
{
get
{
if (!PropertyFilter.Category)
{
Properties.SetNull(NativeMethods.QUEUE_PROPID_TYPE);
GenerateQueueProperties();
byte[] bytes = new byte[16];
IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_TYPE);
if (handle != IntPtr.Zero)
{
Marshal.Copy(handle, bytes, 0, 16);
//MSMQ allocated memory for this operation, needs to be freed
SafeNativeMethods.MQFreeMemory(handle);
}
this.queueType = new Guid(bytes);
PropertyFilter.Category = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_TYPE);
}
return this.queueType;
}
set
{
Properties.SetGuid(NativeMethods.QUEUE_PROPID_TYPE, value.ToByteArray());
SaveQueueProperties();
this.queueType = value;
PropertyFilter.Category = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_TYPE);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ComputerName"]/*' />
/// <internalonly/>
internal static string ComputerName
{
get
{
if (computerName == null)
{
lock (MessageQueue.staticSyncRoot)
{
if (computerName == null)
{
StringBuilder sb = new StringBuilder(256);
SafeNativeMethods.GetComputerName(sb, new int[] { sb.Capacity });
computerName = sb.ToString();
}
}
}
return computerName;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CreateTime"]/*' />
/// <devdoc>
/// <para>
/// Gets the time and date of the queue's creation.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_CreateTime)]
public DateTime CreateTime
{
get
{
if (!PropertyFilter.CreateTime)
{
DateTime time = new DateTime(1970, 1, 1);
Properties.SetI4(NativeMethods.QUEUE_PROPID_CREATE_TIME, 0);
GenerateQueueProperties();
this.createTime = time.AddSeconds(properties.GetI4(NativeMethods.QUEUE_PROPID_CREATE_TIME)).ToLocalTime();
PropertyFilter.CreateTime = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_CREATE_TIME);
}
return this.createTime;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.DefaultPropertiesToSend"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the properties to be used by
/// default when sending messages to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
/// .
/// </para>
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MessagingDescription(Res.MQ_DefaultPropertiesToSend)]
public DefaultPropertiesToSend DefaultPropertiesToSend
{
get
{
if (this.defaultProperties == null)
{
if (this.DesignMode)
this.defaultProperties = new DefaultPropertiesToSend(true);
else
this.defaultProperties = new DefaultPropertiesToSend();
}
return this.defaultProperties;
}
set
{
this.defaultProperties = value;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.DenySharedReceive"]/*' />
/// <devdoc>
/// <para>
/// Specifies the shared mode for the queue that this object
/// references. If <see langword='true'/> ,
/// no other queue object will be able to receive messages from the queue resource.
/// </para>
/// </devdoc>
[Browsable(false), DefaultValueAttribute(false), MessagingDescription(Res.MQ_DenySharedReceive)]
public bool DenySharedReceive
{
get
{
return (this.sharedMode == NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE);
}
set
{
if (value && (this.sharedMode != NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE))
{
this.Close();
this.sharedMode = NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE;
}
else if (!value && (this.sharedMode == NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE))
{
this.Close();
this.sharedMode = NativeMethods.QUEUE_SHARED_MODE_DENY_NONE;
}
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.EnableConnectionCache"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[Browsable(false)]
public static bool EnableConnectionCache
{
get
{
return enableConnectionCache;
}
set
{
enableConnectionCache = value;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.EncryptionRequired"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether the queue only accepts non-private
/// (non-encrypted) messages.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_EncryptionRequired)]
public EncryptionRequired EncryptionRequired
{
get
{
if (!PropertyFilter.EncryptionLevel)
{
Properties.SetUI4(NativeMethods.QUEUE_PROPID_PRIV_LEVEL, 0);
GenerateQueueProperties();
this.encryptionLevel = Properties.GetUI4(NativeMethods.QUEUE_PROPID_PRIV_LEVEL);
PropertyFilter.EncryptionLevel = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_PRIV_LEVEL);
}
return (EncryptionRequired)this.encryptionLevel;
}
set
{
if (!ValidationUtility.ValidateEncryptionRequired(value))
throw new InvalidEnumArgumentException("value", (int)value, typeof(EncryptionRequired));
Properties.SetUI4(NativeMethods.QUEUE_PROPID_PRIV_LEVEL, (int)value);
SaveQueueProperties();
this.encryptionLevel = properties.GetUI4(NativeMethods.QUEUE_PROPID_PRIV_LEVEL);
PropertyFilter.EncryptionLevel = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_PRIV_LEVEL);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.FormatName"]/*' />
/// <devdoc>
/// <para>
/// Gets the unique name that was generated for the queue when the queue was created.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_FormatName)]
public string FormatName
{
get
{
if (this.formatName == null)
{
if (this.path == null || path.Length == 0)
{
return string.Empty;
}
string pathUpper = this.path.ToUpper(CultureInfo.InvariantCulture);
// see if we already have this cached
if (enableCache)
this.formatName = MessageQueue.formatNameCache.Get(pathUpper);
// not in the cache? keep working.
if (formatName == null)
{
if (PropertyFilter.Id)
{
//Improves performance when enumerating queues.
//This codepath will only be executed when accessing
//a queue returned by MessageQueueEnumerator.
int result;
int status = 0;
StringBuilder newFormatName = new StringBuilder(NativeMethods.MAX_LABEL_LEN);
result = NativeMethods.MAX_LABEL_LEN;
status = SafeNativeMethods.MQInstanceToFormatName(this.id.ToByteArray(), newFormatName, ref result);
if (status != 0)
throw new MessageQueueException(status);
this.formatName = newFormatName.ToString();
return this.formatName;
}
if (pathUpper.StartsWith(PREFIX_FORMAT_NAME))
{
this.formatName = this.path.Substring(PREFIX_FORMAT_NAME.Length);
}
else if (pathUpper.StartsWith(PREFIX_LABEL))
{
MessageQueue labeledQueue = ResolveQueueFromLabel(this.path, true);
this.formatName = labeledQueue.FormatName;
this.queuePath = labeledQueue.QueuePath;
}
else
{
this.queuePath = this.path;
this.formatName = ResolveFormatNameFromQueuePath(this.queuePath, true);
}
MessageQueue.formatNameCache.Put(pathUpper, formatName);
}
}
return this.formatName;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Formatter"]/*' />
/// <devdoc>
/// <para>
/// Gets or
/// sets a
/// formatter class used to serialize messages read or written to
/// the message body.
/// </para>
/// </devdoc>
[DefaultValueAttribute(null),
TypeConverterAttribute(typeof(System.Messaging.Design.MessageFormatterConverter)),
Browsable(false),
MessagingDescription(Res.MQ_Formatter)]
public IMessageFormatter Formatter
{
get
{
if (this.formatter == null && !DesignMode)
this.formatter = new XmlMessageFormatter();
return this.formatter;
}
set
{
this.formatter = value;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Id"]/*' />
/// <devdoc>
/// <para>
/// Gets the Message Queuing unique identifier for the queue.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_GuidId)]
public Guid Id
{
get
{
if (!PropertyFilter.Id)
{
Properties.SetNull(NativeMethods.QUEUE_PROPID_INSTANCE);
GenerateQueueProperties();
byte[] bytes = new byte[16];
IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_INSTANCE);
if (handle != IntPtr.Zero)
{
Marshal.Copy(handle, bytes, 0, 16);
//MSMQ allocated memory for this operation, needs to be freed
SafeNativeMethods.MQFreeMemory(handle);
}
this.id = new Guid(bytes);
PropertyFilter.Id = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_INSTANCE);
}
return this.id;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Label"]/*' />
/// <devdoc>
/// <para>Gets or sets the queue description.</para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_Label)]
public string Label
{
get
{
if (!PropertyFilter.Label)
{
Properties.SetNull(NativeMethods.QUEUE_PROPID_LABEL);
GenerateQueueProperties();
string description = null;
IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_LABEL);
if (handle != IntPtr.Zero)
{
//Using Unicode API even on Win9x
description = Marshal.PtrToStringUni(handle);
//MSMQ allocated memory for this operation, needs to be freed
SafeNativeMethods.MQFreeMemory(handle);
}
this.label = description;
PropertyFilter.Label = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_LABEL);
}
return this.label;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
//Borrow this function from message
Properties.SetString(NativeMethods.QUEUE_PROPID_LABEL, Message.StringToBytes(value));
SaveQueueProperties();
this.label = value;
PropertyFilter.Label = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_LABEL);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.LastModifyTime"]/*' />
/// <devdoc>
/// <para>
/// Indicates the last time the properties of a queue were modified.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_LastModifyTime)]
public DateTime LastModifyTime
{
get
{
if (!PropertyFilter.LastModifyTime)
{
DateTime time = new DateTime(1970, 1, 1);
Properties.SetI4(NativeMethods.QUEUE_PROPID_MODIFY_TIME, 0);
GenerateQueueProperties();
this.lastModifyTime = time.AddSeconds(properties.GetI4(NativeMethods.QUEUE_PROPID_MODIFY_TIME)).ToLocalTime();
PropertyFilter.LastModifyTime = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_MODIFY_TIME);
}
return this.lastModifyTime;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MachineName"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the name of the computer where
/// the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
/// is located.
/// </para>
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_MachineName)]
public string MachineName
{
get
{
string queuePath = QueuePath;
if (queuePath.Length == 0)
{
return queuePath;
}
return queuePath.Substring(0, queuePath.IndexOf('\\'));
}
set
{
if (value == null)
throw new ArgumentNullException("value");
if (!SyntaxCheck.CheckMachineName(value))
throw new ArgumentException(Res.GetString(Res.InvalidProperty, "MachineName", value));
StringBuilder newPath = new StringBuilder();
if ((this.path == null || this.path.Length == 0) && this.formatName == null)
{
//Need to default to an existing queue, for instance Journal.
newPath.Append(value);
newPath.Append(SUFIX_JOURNAL);
}
else
{
newPath.Append(value);
newPath.Append("\\");
newPath.Append(QueueName);
}
Path = newPath.ToString();
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MaximumJournalSize"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the maximum size of the journal queue.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
MessagingDescription(Res.MQ_MaximumJournalSize),
TypeConverterAttribute(typeof(System.Messaging.Design.SizeConverter))]
public long MaximumJournalSize
{
get
{
if (!PropertyFilter.MaximumJournalSize)
{
Properties.SetUI4(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA, 0);
GenerateQueueProperties();
this.journalSize = (long)((uint)properties.GetUI4(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA));
PropertyFilter.MaximumJournalSize = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA);
}
return this.journalSize;
}
set
{
if (value > InfiniteQueueSize || value < 0)
throw new ArgumentException(Res.GetString(Res.InvalidProperty, "MaximumJournalSize", value));
Properties.SetUI4(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA, (int)((uint)value));
SaveQueueProperties();
this.journalSize = value;
PropertyFilter.MaximumJournalSize = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MaximumQueueSize"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the maximum size of the queue.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
MessagingDescription(Res.MQ_MaximumQueueSize),
TypeConverterAttribute(typeof(System.Messaging.Design.SizeConverter))]
public long MaximumQueueSize
{
get
{
if (!PropertyFilter.MaximumQueueSize)
{
Properties.SetUI4(NativeMethods.QUEUE_PROPID_QUOTA, 0);
GenerateQueueProperties();
this.queueSize = (long)((uint)properties.GetUI4(NativeMethods.QUEUE_PROPID_QUOTA));
PropertyFilter.MaximumQueueSize = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_QUOTA);
}
return this.queueSize;
}
set
{
if (value > InfiniteQueueSize || value < 0)
throw new ArgumentException(Res.GetString(Res.InvalidProperty, "MaximumQueueSize", value));
Properties.SetUI4(NativeMethods.QUEUE_PROPID_QUOTA, (int)((uint)value));
SaveQueueProperties();
this.queueSize = value;
PropertyFilter.MaximumQueueSize = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_QUOTA);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageReadPropertyFilter"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the property filter for
/// receiving messages.
/// </para>
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MessagingDescription(Res.MQ_MessageReadPropertyFilter)]
public MessagePropertyFilter MessageReadPropertyFilter
{
get
{
if (this.receiveFilter == null)
{
this.receiveFilter = new MessagePropertyFilter();
this.receiveFilter.SetDefaults();
}
return this.receiveFilter;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
this.receiveFilter = value;
}
}
internal MQCacheableInfo MQInfo
{
get
{
if (mqInfo == null)
{
MQCacheableInfo cachedInfo = queueInfoCache.Get(QueueInfoKey);
if (sharedMode == NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE || !enableCache)
{
if (cachedInfo != null)
cachedInfo.CloseIfNotReferenced();
// don't use the cache
mqInfo = new MQCacheableInfo(this.FormatName, accessMode, sharedMode);
mqInfo.AddRef();
}
else
{
// use the cache
if (cachedInfo != null)
{
cachedInfo.AddRef();
mqInfo = cachedInfo;
}
else
{
mqInfo = new MQCacheableInfo(this.FormatName, accessMode, sharedMode);
mqInfo.AddRef();
queueInfoCache.Put(QueueInfoKey, mqInfo);
}
}
}
return mqInfo;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MulticastAddress"]/*' />
/// <devdoc>
/// <para>Gets or sets the IP multicast address associated with the queue.</para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
DefaultValue(""),
MessagingDescription(Res.MQ_MulticastAddress)]
public string MulticastAddress
{
get
{
if (!Msmq3OrNewer)
{ //this feature is unavailable on win2k
// don't throw in design mode: this makes component unusable
if (DesignMode)
return String.Empty;
else
throw new PlatformNotSupportedException(Res.GetString(Res.PlatformNotSupported));
}
if (!PropertyFilter.MulticastAddress)
{
Properties.SetNull(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
GenerateQueueProperties();
string address = null;
IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
if (handle != IntPtr.Zero)
{
address = Marshal.PtrToStringUni(handle);
//MSMQ allocated memory for this operation, needs to be freed
SafeNativeMethods.MQFreeMemory(handle);
}
this.multicastAddress = address;
PropertyFilter.MulticastAddress = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
}
return this.multicastAddress;
}
set
{
if (value == null)
throw new ArgumentNullException("value");
if (!Msmq3OrNewer) //this feature is unavailable on win2k
throw new PlatformNotSupportedException(Res.GetString(Res.PlatformNotSupported));
if (value.Length == 0) // used to disassocciate queue from a muliticast address
Properties.SetEmpty(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
else //Borrow this function from message
Properties.SetString(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS, Message.StringToBytes(value));
SaveQueueProperties();
this.multicastAddress = value;
PropertyFilter.MulticastAddress = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Path"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the queue's path. When setting the <see cref='System.Messaging.MessageQueue.Path'/>, this points the <see cref='System.Messaging.MessageQueue'/>
/// to a new queue.
/// </para>
/// </devdoc>
[Editor("System.Messaging.Design.QueuePathEditor", "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
SettingsBindable(true),
RefreshProperties(RefreshProperties.All),
Browsable(false),
DefaultValue(""),
TypeConverter("System.Diagnostics.Design.StringValueConverter, " + AssemblyRef.SystemDesign),
MessagingDescription(Res.MQ_Path)]
public string Path
{
get
{
return this.path;
}
set
{
if (value == null)
value = String.Empty;
if (!ValidatePath(value, false))
throw new ArgumentException(Res.GetString(Res.PathSyntax));
if (!String.IsNullOrEmpty(this.path))
this.Close();
this.path = value;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Properties"]/*' />
/// <internalonly/>
private QueuePropertyVariants Properties
{
get
{
if (this.properties == null)
this.properties = new QueuePropertyVariants();
return this.properties;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PropertyFilter"]/*' />
/// <internalonly/>
private QueuePropertyFilter PropertyFilter
{
get
{
if (this.filter == null)
this.filter = new QueuePropertyFilter();
return this.filter;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.QueueName"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets the friendly
/// name that identifies the queue.
/// </para>
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_QueueName)]
public string QueueName
{
get
{
string queuePath = QueuePath;
if (queuePath.Length == 0)
{
return queuePath;
}
return queuePath.Substring(queuePath.IndexOf('\\') + 1);
}
set
{
if (value == null)
throw new ArgumentNullException("value");
StringBuilder newPath = new StringBuilder();
if ((this.path == null || this.path.Length == 0) && this.formatName == null)
{
newPath.Append(".\\");
newPath.Append(value);
}
else
{
newPath.Append(MachineName);
newPath.Append("\\");
newPath.Append(value);
}
Path = newPath.ToString();
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.QueuePath"]/*' />
/// <internalonly/>
internal string QueuePath
{
get
{
if (this.queuePath == null)
{
if (this.path == null || this.path.Length == 0)
{
return string.Empty;
}
string pathUpper = this.path.ToUpper(CultureInfo.InvariantCulture);
if (pathUpper.StartsWith(PREFIX_LABEL))
{
MessageQueue labeledQueue = ResolveQueueFromLabel(this.path, true);
this.formatName = labeledQueue.FormatName;
this.queuePath = labeledQueue.QueuePath;
}
else if (pathUpper.StartsWith(PREFIX_FORMAT_NAME))
{
Properties.SetNull(NativeMethods.QUEUE_PROPID_PATHNAME);
GenerateQueueProperties();
string description = null;
IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_PATHNAME);
if (handle != IntPtr.Zero)
{
//Using Unicode API even on Win9x
description = Marshal.PtrToStringUni(handle);
//MSMQ allocated memory for this operation, needs to be freed
SafeNativeMethods.MQFreeMemory(handle);
}
Properties.Remove(NativeMethods.QUEUE_PROPID_PATHNAME);
this.queuePath = description;
}
else
this.queuePath = path;
}
return this.queuePath;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReadHandle"]/*' />
/// <devdoc>
/// <para>
/// The native handle used to receive messages from the message queue
/// </para>
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_ReadHandle)]
public IntPtr ReadHandle
{
get
{
if (!receiveGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Receive, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
receiveGranted = true;
}
return MQInfo.ReadHandle.DangerousGetHandle();
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SynchronizingObject"]/*' />
/// <devdoc>
/// Represents the object used to marshal the event handler
/// calls issued as a result of a BeginReceive or BeginPeek
/// request into a specific thread. Normally this property will
/// be set when the component is placed inside a control or
/// a from, since those components are bound to a specific
/// thread.
/// </devdoc>
[Browsable(false), DefaultValue(null), MessagingDescription(Res.MQ_SynchronizingObject)]
public ISynchronizeInvoke SynchronizingObject
{
get
{
if (this.synchronizingObject == null && DesignMode)
{
IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
if (host != null)
{
object baseComponent = host.RootComponent;
if (baseComponent != null && baseComponent is ISynchronizeInvoke)
this.synchronizingObject = (ISynchronizeInvoke)baseComponent;
}
}
return this.synchronizingObject;
}
set
{
this.synchronizingObject = value;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Transactional"]/*' />
/// <devdoc>
/// <para>
/// Gets
/// a value indicating whether the queue supports transactions.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_Transactional)]
public bool Transactional
{
get
{
if (!browseGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Browse, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
browseGranted = true;
}
return MQInfo.Transactional;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.UseJournalQueue"]/*' />
/// <devdoc>
/// <para>
/// Gets or sets a value indicating whether retrieved messages are copied to the
/// journal queue.
/// </para>
/// </devdoc>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_UseJournalQueue)]
public bool UseJournalQueue
{
get
{
if (!PropertyFilter.UseJournalQueue)
{
Properties.SetUI1(NativeMethods.QUEUE_PROPID_JOURNAL, (byte)0);
GenerateQueueProperties();
this.useJournaling = (Properties.GetUI1(NativeMethods.QUEUE_PROPID_JOURNAL) != NativeMethods.QUEUE_JOURNAL_NONE);
PropertyFilter.UseJournalQueue = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_JOURNAL);
}
return this.useJournaling;
}
set
{
if (value)
Properties.SetUI1(NativeMethods.QUEUE_PROPID_JOURNAL, (byte)NativeMethods.QUEUE_JOURNAL_JOURNAL);
else
Properties.SetUI1(NativeMethods.QUEUE_PROPID_JOURNAL, (byte)NativeMethods.QUEUE_JOURNAL_NONE);
SaveQueueProperties();
this.useJournaling = value;
PropertyFilter.UseJournalQueue = true;
Properties.Remove(NativeMethods.QUEUE_PROPID_JOURNAL);
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.WriteHandle"]/*' />
/// <devdoc>
/// <para>
/// The native handle used to send messages to the message queue
/// </para>
/// </devdoc>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_WriteHandle)]
public IntPtr WriteHandle
{
get
{
if (!sendGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Send, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
sendGranted = true;
}
return MQInfo.WriteHandle.DangerousGetHandle();
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekCompleted"]/*' />
/// <devdoc>
/// <para>Occurs when a message is read without being removed
/// from the queue. This is a result of the asynchronous operation, <see cref='System.Messaging.MessageQueue.BeginPeek'/>
/// .</para>
/// </devdoc>
[MessagingDescription(Res.MQ_PeekCompleted)]
public event PeekCompletedEventHandler PeekCompleted
{
add
{
if (!peekGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Peek, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
peekGranted = true;
}
onPeekCompleted += value;
}
remove
{
onPeekCompleted -= value;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveCompleted"]/*' />
/// <devdoc>
/// <para>
/// Occurs when a message has been taken out of the queue.
/// This is a result of the asynchronous operation <see cref='System.Messaging.MessageQueue.BeginReceive'/>
/// .
/// </para>
/// </devdoc>
[MessagingDescription(Res.MQ_ReceiveCompleted)]
public event ReceiveCompletedEventHandler ReceiveCompleted
{
add
{
if (!receiveGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Receive, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
receiveGranted = true;
}
onReceiveCompleted += value;
}
remove
{
onReceiveCompleted -= value;
}
}
private Hashtable OutstandingAsyncRequests
{
get
{
if (outstandingAsyncRequests == null)
{
lock (this.syncRoot)
{
if (outstandingAsyncRequests == null)
{
Hashtable requests = Hashtable.Synchronized(new Hashtable());
Thread.MemoryBarrier();
outstandingAsyncRequests = requests;
}
}
}
return outstandingAsyncRequests;
}
}
private QueueInfoKeyHolder QueueInfoKey
{
get
{
if (queueInfoKey == null)
{
lock (this.syncRoot)
{
if (queueInfoKey == null)
{
QueueInfoKeyHolder keyHolder = new QueueInfoKeyHolder(FormatName, accessMode);
Thread.MemoryBarrier();
queueInfoKey = keyHolder;
}
}
}
return this.queueInfoKey;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginPeek"]/*' />
/// <devdoc>
/// <para>Initiates an asynchronous peek operation with no timeout. The method
/// returns immediately, but the asynchronous operation is not completed until
/// the event handler is called. This occurs when a message is
/// available in the
/// queue.</para>
/// </devdoc>
public IAsyncResult BeginPeek()
{
return ReceiveAsync(InfiniteTimeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, null, null);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginPeek1"]/*' />
/// <devdoc>
/// <para> Initiates an asynchronous peek operation with the timeout specified.
/// The method returns immediately, but the asynchronous operation is not completed until
/// the event handler is called. This occurs when either a message is available in
/// the queue or the timeout
/// expires.</para>
/// </devdoc>
public IAsyncResult BeginPeek(TimeSpan timeout)
{
return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, null, null);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginPeek2"]/*' />
/// <devdoc>
/// <para> Initiates an asynchronous peek operation with a state object that associates
/// information with the operation throughout the operation's
/// lifetime. The method returns immediately, but the asynchronous operation is not completed
/// until the event handler
/// is called. This occurs when either a message is available in the
/// queue or the timeout
/// expires.</para>
/// </devdoc>
public IAsyncResult BeginPeek(TimeSpan timeout, object stateObject)
{
return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, null, stateObject);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginPeek3"]/*' />
/// <devdoc>
/// <para> Initiates an asynchronous peek operation that receives
/// notification through a callback which identifies the event handling method for the
/// operation. The method returns immediately, but the asynchronous operation is not completed
/// until the event handler is called. This occurs when either a message is available
/// in the queue or the timeout
/// expires.</para>
/// </devdoc>
public IAsyncResult BeginPeek(TimeSpan timeout, object stateObject, AsyncCallback callback)
{
return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, callback, stateObject);
}
public IAsyncResult BeginPeek(TimeSpan timeout, Cursor cursor, PeekAction action, object state, AsyncCallback callback)
{
if ((action != PeekAction.Current) && (action != PeekAction.Next))
throw new ArgumentOutOfRangeException(Res.GetString(Res.InvalidParameter, "action", action.ToString()));
if (cursor == null)
throw new ArgumentNullException("cursor");
return ReceiveAsync(timeout, cursor.Handle, (int)action, callback, state);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginReceive"]/*' />
/// <devdoc>
/// <para>
/// Receives the first message available in the queue
/// referenced by the <see cref='System.Messaging.MessageQueue'/>
/// .
/// </para>
/// </devdoc>
public IAsyncResult BeginReceive()
{
return ReceiveAsync(InfiniteTimeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_RECEIVE, null, null);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginReceive1"]/*' />
/// <devdoc>
/// <para>
/// Receives the first message available in the queue
/// referenced by the <see cref='System.Messaging.MessageQueue'/> . Waits the specified interval for
/// the message to be
/// removed.
/// </para>
/// </devdoc>
public IAsyncResult BeginReceive(TimeSpan timeout)
{
return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_RECEIVE, null, null);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginReceive2"]/*' />
/// <devdoc>
/// <para>
/// Receives the first message available in the queue
/// referenced by the <see cref='System.Messaging.MessageQueue'/> . Waits the specified interval
/// for a new message to be removed and uses the specified object to retrieve
/// the result.
/// </para>
/// </devdoc>
public IAsyncResult BeginReceive(TimeSpan timeout, object stateObject)
{
return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_RECEIVE, null, stateObject);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginReceive3"]/*' />
/// <devdoc>
/// <para>Receives the first message available in the queue
/// referenced by the <see cref='System.Messaging.MessageQueue'/> . Waits
/// the specified interval for a new message to be removed, uses the specified
/// object to retrieve the result, and receives notification through a
/// callback.</para>
/// </devdoc>
public IAsyncResult BeginReceive(TimeSpan timeout, object stateObject, AsyncCallback callback)
{
return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_RECEIVE, callback, stateObject);
}
public IAsyncResult BeginReceive(TimeSpan timeout, Cursor cursor, object state, AsyncCallback callback)
{
if (cursor == null)
throw new ArgumentNullException("cursor");
return ReceiveAsync(timeout, cursor.Handle, NativeMethods.QUEUE_ACTION_RECEIVE, callback, state);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ClearConnectionCache"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public static void ClearConnectionCache()
{
formatNameCache.ClearStale(new TimeSpan(0));
queueInfoCache.ClearStale(new TimeSpan(0));
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Close"]/*' />
/// <devdoc>
/// <para>
/// Frees all resources allocated by the <see cref='System.Messaging.MessageQueue'/>
/// .
/// </para>
/// </devdoc>
public void Close()
{
Cleanup(true);
}
private void Cleanup(bool disposing)
{
//This is generated from the path.
//It needs to be cleared.
this.formatName = null;
this.queuePath = null;
this.attached = false;
this.administerGranted = false;
this.browseGranted = false;
this.sendGranted = false;
this.receiveGranted = false;
this.peekGranted = false;
if (disposing)
{
if (this.mqInfo != null)
{
this.mqInfo.Release();
//No need to check references in this case, the only object
//mqInfo is not cached if both conditions are satisified.
if (sharedMode == NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE || !enableCache)
this.mqInfo.Dispose();
this.mqInfo = null;
}
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Create"]/*' />
/// <devdoc>
/// <para>
/// Creates
/// a nontransactional Message Queuing backend queue resource with the
/// specified path.
/// </para>
/// </devdoc>
public static MessageQueue Create(string path)
{
return MessageQueue.Create(path, false);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Create1"]/*' />
/// <devdoc>
/// <para>
/// Creates
/// a transactional or nontransactional Message Queuing backend queue resource with the
/// specified path.
/// </para>
/// </devdoc>
public static MessageQueue Create(string path, bool transactional)
{
if (path == null)
throw new ArgumentNullException("path");
if (path.Length == 0)
throw new ArgumentException(Res.GetString(Res.InvalidParameter, "path", path));
if (!IsCanonicalPath(path, true))
throw new ArgumentException(Res.GetString(Res.InvalidQueuePathToCreate, path));
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Administer, MessageQueuePermission.Any);
permission.Demand();
//Create properties.
QueuePropertyVariants properties = new QueuePropertyVariants();
properties.SetString(NativeMethods.QUEUE_PROPID_PATHNAME, Message.StringToBytes(path));
if (transactional)
properties.SetUI1(NativeMethods.QUEUE_PROPID_TRANSACTION, (byte)NativeMethods.QUEUE_TRANSACTIONAL_TRANSACTIONAL);
else
properties.SetUI1(NativeMethods.QUEUE_PROPID_TRANSACTION, (byte)NativeMethods.QUEUE_TRANSACTIONAL_NONE);
StringBuilder formatName = new StringBuilder(NativeMethods.MAX_LABEL_LEN);
int formatNameLen = NativeMethods.MAX_LABEL_LEN;
int status = 0;
//Try to create queue.
status = UnsafeNativeMethods.MQCreateQueue(IntPtr.Zero, properties.Lock(), formatName, ref formatNameLen);
properties.Unlock();
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
return new MessageQueue(path);
}
public Cursor CreateCursor()
{
return new Cursor(this);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CreateMessageQueuesSnapshot"]/*' />
/// <internalonly/>
private static MessageQueue[] CreateMessageQueuesSnapshot(MessageQueueCriteria criteria)
{
return CreateMessageQueuesSnapshot(criteria, true);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CreateMessageQueuesSnapshot1"]/*' />
/// <internalonly/>
private static MessageQueue[] CreateMessageQueuesSnapshot(MessageQueueCriteria criteria, bool checkSecurity)
{
ArrayList messageQueuesList = new ArrayList();
IEnumerator messageQueues = GetMessageQueueEnumerator(criteria, checkSecurity);
while (messageQueues.MoveNext())
{
MessageQueue messageQueue = (MessageQueue)messageQueues.Current;
messageQueuesList.Add(messageQueue);
}
MessageQueue[] queues = new MessageQueue[messageQueuesList.Count];
messageQueuesList.CopyTo(queues, 0);
return queues;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Delete"]/*' />
/// <devdoc>
/// <para>
/// Deletes a queue backend resource identified by
/// the given path.
/// </para>
/// </devdoc>
public static void Delete(string path)
{
if (path == null)
throw new ArgumentNullException("path");
if (path.Length == 0)
throw new ArgumentException(Res.GetString(Res.InvalidParameter, "path", path));
if (!ValidatePath(path, false))
throw new ArgumentException(Res.GetString(Res.PathSyntax));
int status = 0;
MessageQueue queue = new MessageQueue(path);
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Administer, PREFIX_FORMAT_NAME + queue.FormatName);
permission.Demand();
status = UnsafeNativeMethods.MQDeleteQueue(queue.FormatName);
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
queueInfoCache.Remove(queue.QueueInfoKey);
formatNameCache.Remove(path.ToUpper(CultureInfo.InvariantCulture));
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Dispose"]/*' />
/// <devdoc>
/// <para>
/// </para>
/// </devdoc>
[HostProtection(SharedState = true)] // Overriden member of Component. We should not change Component's behavior in the derived class.
protected override void Dispose(bool disposing)
{
Cleanup(disposing);
base.Dispose(disposing);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.EndPeek"]/*' />
/// <devdoc>
/// <para>Completes an asynchronous peek operation associated with
/// the <paramref name="asyncResult"/>
/// parameter.</para>
/// </devdoc>
public Message EndPeek(IAsyncResult asyncResult)
{
return EndAsyncOperation(asyncResult);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.EndReceive"]/*' />
/// <devdoc>
/// <para>
/// Terminates a receive asynchronous operation identified
/// by the specified interface.
/// </para>
/// </devdoc>
public Message EndReceive(IAsyncResult asyncResult)
{
return EndAsyncOperation(asyncResult);
}
private Message EndAsyncOperation(IAsyncResult asyncResult)
{
if (asyncResult == null)
throw new ArgumentNullException("asyncResult");
if (!(asyncResult is AsynchronousRequest))
throw new ArgumentException(Res.GetString(Res.AsyncResultInvalid));
AsynchronousRequest request = (AsynchronousRequest)asyncResult;
return request.End();
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Exists"]/*' />
/// <devdoc>
/// <para>
/// Determines whether a queue with the specified path
/// exists.
/// </para>
/// </devdoc>
public static bool Exists(string path)
{
if (path == null)
throw new ArgumentNullException("path");
if (!ValidatePath(path, false))
throw new ArgumentException(Res.GetString(Res.PathSyntax));
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Browse, MessageQueuePermission.Any);
permission.Demand();
string pathUpper = path.ToUpper(CultureInfo.InvariantCulture);
if (pathUpper.StartsWith(PREFIX_FORMAT_NAME))
throw new InvalidOperationException(Res.GetString(Res.QueueExistsError));
else if (pathUpper.StartsWith(PREFIX_LABEL))
{
MessageQueue labeledQueue = ResolveQueueFromLabel(path, false);
if (labeledQueue == null)
return false;
else
return true;
}
else
{
string formatName = ResolveFormatNameFromQueuePath(path, false);
if (formatName == null)
return false;
else
return true;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GenerateQueueProperties"]/*' />
/// <internalonly/>
private void GenerateQueueProperties()
{
if (!browseGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Browse, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
browseGranted = true;
}
int status = UnsafeNativeMethods.MQGetQueueProperties(FormatName, Properties.Lock());
Properties.Unlock();
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetAllMessages"]/*' />
/// <devdoc>
/// <para>
/// Returns all the messages available in the queue.
/// </para>
/// </devdoc>
public Message[] GetAllMessages()
{
ArrayList messageList = new ArrayList();
MessageEnumerator messages = GetMessageEnumerator2();
while (messages.MoveNext())
{
Message message = (Message)messages.Current;
messageList.Add(message);
}
Message[] resultMessages = new Message[messageList.Count];
messageList.CopyTo(resultMessages, 0);
return resultMessages;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetEnumerator"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[Obsolete("This method returns a MessageEnumerator that implements RemoveCurrent family of methods incorrectly. Please use GetMessageEnumerator2 instead.")]
public IEnumerator GetEnumerator()
{
return GetMessageEnumerator();
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMachineId"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public static Guid GetMachineId(string machineName)
{
if (!SyntaxCheck.CheckMachineName(machineName))
throw new ArgumentException(Res.GetString(Res.InvalidParameter, "MachineName", machineName));
if (machineName == ".")
machineName = MessageQueue.ComputerName;
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Browse, MessageQueuePermission.Any);
permission.Demand();
MachinePropertyVariants machineProperties = new MachinePropertyVariants();
byte[] bytes = new byte[16];
machineProperties.SetNull(NativeMethods.MACHINE_ID);
int status = UnsafeNativeMethods.MQGetMachineProperties(machineName, IntPtr.Zero, machineProperties.Lock());
machineProperties.Unlock();
IntPtr handle = machineProperties.GetIntPtr(NativeMethods.MACHINE_ID);
if (MessageQueue.IsFatalError(status))
{
if (handle != IntPtr.Zero)
SafeNativeMethods.MQFreeMemory(handle);
throw new MessageQueueException(status);
}
if (handle != IntPtr.Zero)
{
Marshal.Copy(handle, bytes, 0, 16);
SafeNativeMethods.MQFreeMemory(handle);
}
return new Guid(bytes);
}
/// <devdoc>
/// Represents security context that can be used to easily and efficiently
/// send messages in impersonating applications.
/// </devdoc>
public static SecurityContext GetSecurityContext()
{
SecurityContextHandle handle;
// SECURITY: Note that this call is not marked with SUCS attribute (i.e., requires FullTrust)
int status = NativeMethods.MQGetSecurityContextEx(out handle);
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
return new SecurityContext(handle);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageQueueEnumerator"]/*' />
/// <devdoc>
/// <para>
/// Creates an enumerator object for the message queues
/// available on the network.
/// </para>
/// </devdoc>
public static MessageQueueEnumerator GetMessageQueueEnumerator()
{
return new MessageQueueEnumerator(null);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageQueueEnumerator1"]/*' />
/// <devdoc>
/// <para>
/// Creates an enumerator object for the message queues
/// available on the network.
/// </para>
/// </devdoc>
public static MessageQueueEnumerator GetMessageQueueEnumerator(MessageQueueCriteria criteria)
{
return new MessageQueueEnumerator(criteria);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageQueueEnumerator"]/*' />
/// <internalonly/>
internal static MessageQueueEnumerator GetMessageQueueEnumerator(MessageQueueCriteria criteria, bool checkSecurity)
{
return new MessageQueueEnumerator(criteria, checkSecurity);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageEnumerator"]/*' />
/// <devdoc>
/// <para>
/// Creates an enumerator object for the messages in the queue. Superceded by GetMessageEnumerator2.
/// </para>
/// </devdoc>
[Obsolete("This method returns a MessageEnumerator that implements RemoveCurrent family of methods incorrectly. Please use GetMessageEnumerator2 instead.")]
public MessageEnumerator GetMessageEnumerator()
{
if (!peekGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Peek, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
peekGranted = true;
}
return new MessageEnumerator(this, false);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageEnumerator2"]/*' />
/// <devdoc>
/// <para>
/// Creates an enumerator object for the messages in the queue.
/// </para>
/// </devdoc>
public MessageEnumerator GetMessageEnumerator2()
{
if (!peekGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Peek, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
peekGranted = true;
}
return new MessageEnumerator(this, true);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPrivateQueuesByMachine"]/*' />
/// <devdoc>
/// <para>
/// Retrieves all the private queues on
/// the specified computer.
/// </para>
/// </devdoc>
public static MessageQueue[] GetPrivateQueuesByMachine(string machineName)
{
if (!SyntaxCheck.CheckMachineName(machineName))
throw new ArgumentException(Res.GetString(Res.InvalidParameter, "MachineName", machineName));
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Browse, MessageQueuePermission.Any);
permission.Demand();
if (machineName == "." || (String.Compare(machineName, MessageQueue.ComputerName, true, CultureInfo.InvariantCulture) == 0))
machineName = null;
MessagePropertyVariants properties = new MessagePropertyVariants(5, 0);
properties.SetNull(NativeMethods.MANAGEMENT_PRIVATEQ);
int status = UnsafeNativeMethods.MQMgmtGetInfo(machineName, "MACHINE", properties.Lock());
properties.Unlock();
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
uint len = properties.GetStringVectorLength(NativeMethods.MANAGEMENT_PRIVATEQ);
IntPtr basePointer = properties.GetStringVectorBasePointer(NativeMethods.MANAGEMENT_PRIVATEQ);
MessageQueue[] queues = new MessageQueue[len];
for (int index = 0; index < len; ++index)
{
IntPtr stringPointer = Marshal.ReadIntPtr((IntPtr)((long)basePointer + index * IntPtr.Size));
//Using Unicode API even on Win9x
string path = Marshal.PtrToStringUni(stringPointer);
queues[index] = new MessageQueue("FormatName:DIRECT=OS:" + path);
queues[index].queuePath = path;
SafeNativeMethods.MQFreeMemory(stringPointer);
}
SafeNativeMethods.MQFreeMemory(basePointer);
return queues;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueues"]/*' />
/// <devdoc>
/// <para>
/// Retrieves all public queues on the network.
/// </para>
/// </devdoc>
public static MessageQueue[] GetPublicQueues()
{
return CreateMessageQueuesSnapshot(null);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueues1"]/*' />
/// <devdoc>
/// <para>
/// Retrieves a
/// set of public queues filtered by the specified criteria.
/// </para>
/// </devdoc>
public static MessageQueue[] GetPublicQueues(MessageQueueCriteria criteria)
{
return CreateMessageQueuesSnapshot(criteria);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueuesByCategory"]/*' />
/// <devdoc>
/// <para>
/// Retrieves a
/// set of public queues filtered by the specified category.
/// </para>
/// </devdoc>
public static MessageQueue[] GetPublicQueuesByCategory(Guid category)
{
MessageQueueCriteria criteria = new MessageQueueCriteria();
criteria.Category = category;
return CreateMessageQueuesSnapshot(criteria);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueuesByLabel"]/*' />
/// <devdoc>
/// <para>
/// Retrieves a
/// set of public queues filtered by the specified label.
/// </para>
/// </devdoc>
public static MessageQueue[] GetPublicQueuesByLabel(string label)
{
return GetPublicQueuesByLabel(label, true);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueuesByLabel1"]/*' />
/// <internalonly/>
private static MessageQueue[] GetPublicQueuesByLabel(string label, bool checkSecurity)
{
MessageQueueCriteria criteria = new MessageQueueCriteria();
criteria.Label = label;
return CreateMessageQueuesSnapshot(criteria, checkSecurity);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueuesByMachine"]/*' />
/// <devdoc>
/// <para>
/// Retrieves all public queues on the specified computer.
/// </para>
/// </devdoc>
public static MessageQueue[] GetPublicQueuesByMachine(string machineName)
{
if (!SyntaxCheck.CheckMachineName(machineName))
throw new ArgumentException(Res.GetString(Res.InvalidParameter, "MachineName", machineName));
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Browse, MessageQueuePermission.Any);
permission.Demand();
try
{
DirectoryServicesPermission dsPermission = new DirectoryServicesPermission(PermissionState.Unrestricted);
dsPermission.Assert();
DirectorySearcher localComputerSearcher = new DirectorySearcher(String.Format(CultureInfo.InvariantCulture, "(&(CN={0})(objectCategory=Computer))", ComputerName));
SearchResult localComputer = localComputerSearcher.FindOne();
if (localComputer != null)
{
DirectorySearcher localComputerMsmqSearcher = new DirectorySearcher(localComputer.GetDirectoryEntry());
localComputerMsmqSearcher.Filter = "(CN=msmq)";
SearchResult localMsmqNode = localComputerMsmqSearcher.FindOne();
SearchResult remoteMsmqNode = null;
if (localMsmqNode != null)
{
if (machineName != "." && String.Compare(machineName, ComputerName, true, CultureInfo.InvariantCulture) != 0)
{
DirectorySearcher remoteComputerSearcher = new DirectorySearcher(String.Format(CultureInfo.InvariantCulture, "(&(CN={0})(objectCategory=Computer))", machineName));
SearchResult remoteComputer = remoteComputerSearcher.FindOne();
if (remoteComputer == null)
return new MessageQueue[0];
DirectorySearcher remoteComputerMsmqSearcher = new DirectorySearcher(remoteComputer.GetDirectoryEntry());
remoteComputerMsmqSearcher.Filter = "(CN=msmq)";
remoteMsmqNode = remoteComputerMsmqSearcher.FindOne();
if (remoteMsmqNode == null)
return new MessageQueue[0];
}
else
remoteMsmqNode = localMsmqNode;
DirectorySearcher objectsSearcher = new DirectorySearcher(remoteMsmqNode.GetDirectoryEntry());
objectsSearcher.Filter = "(objectClass=mSMQQueue)";
objectsSearcher.PropertiesToLoad.Add("Name");
SearchResultCollection objects = objectsSearcher.FindAll();
MessageQueue[] queues = new MessageQueue[objects.Count];
for (int index = 0; index < queues.Length; ++index)
{
string queueName = (string)objects[index].Properties["Name"][0];
queues[index] = new MessageQueue(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}", machineName, queueName));
}
return queues;
}
}
}
catch
{
//Ignore all exceptions, so we can gracefully downgrade to use MQ locator.
}
finally
{
DirectoryServicesPermission.RevertAssert();
}
MessageQueueCriteria criteria = new MessageQueueCriteria();
criteria.MachineName = machineName;
return CreateMessageQueuesSnapshot(criteria, false);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.IsCanonicalPath"]/*' />
/// <internalonly/>
private static bool IsCanonicalPath(string path, bool checkQueueNameSize)
{
if (!ValidatePath(path, checkQueueNameSize))
return false;
string upperPath = path.ToUpper(CultureInfo.InvariantCulture);
if (upperPath.StartsWith(PREFIX_LABEL) ||
upperPath.StartsWith(PREFIX_FORMAT_NAME) ||
upperPath.EndsWith(SUFIX_DEADLETTER) ||
upperPath.EndsWith(SUFIX_DEADXACT) ||
upperPath.EndsWith(SUFIX_JOURNAL))
return false;
return true;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.IsFatalError"]/*' />
/// <internalonly/>
internal static bool IsFatalError(int value)
{
bool isSuccessful = (value == 0x00000000);
bool isInformation = ((value & unchecked((int)0xC0000000)) == 0x40000000);
return (!isInformation && !isSuccessful);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.IsMemoryError"]/*' />
/// <internalonly/>
internal static bool IsMemoryError(int value)
{
if (value == (int)MessageQueueErrorCode.BufferOverflow ||
value == (int)MessageQueueErrorCode.LabelBufferTooSmall ||
value == (int)MessageQueueErrorCode.ProviderNameBufferTooSmall ||
value == (int)MessageQueueErrorCode.SenderCertificateBufferTooSmall ||
value == (int)MessageQueueErrorCode.SenderIdBufferTooSmall ||
value == (int)MessageQueueErrorCode.SecurityDescriptorBufferTooSmall ||
value == (int)MessageQueueErrorCode.SignatureBufferTooSmall ||
value == (int)MessageQueueErrorCode.SymmetricKeyBufferTooSmall ||
value == (int)MessageQueueErrorCode.UserBufferTooSmall ||
value == (int)MessageQueueErrorCode.FormatNameBufferTooSmall)
return true;
return false;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.OnRequestCompleted"]/*' />
/// <devdoc>
/// Used for component model event support.
/// </devdoc>
/// <internalonly/>
private void OnRequestCompleted(IAsyncResult asyncResult)
{
if (((AsynchronousRequest)asyncResult).Action == NativeMethods.QUEUE_ACTION_PEEK_CURRENT)
{
if (this.onPeekCompleted != null)
{
PeekCompletedEventArgs eventArgs = new PeekCompletedEventArgs(this, asyncResult);
this.onPeekCompleted(this, eventArgs);
}
}
else
{
if (this.onReceiveCompleted != null)
{
ReceiveCompletedEventArgs eventArgs = new ReceiveCompletedEventArgs(this, asyncResult);
this.onReceiveCompleted(this, eventArgs);
}
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Peek"]/*' />
/// <devdoc>
/// <para>
/// Returns without removing (peeks) the first message
/// available in the queue referenced by the <see cref='System.Messaging.MessageQueue'/> . This call
/// is synchronous. It
/// blocks the current
/// thread of execution until a message is
/// available.
/// </para>
/// </devdoc>
public Message Peek()
{
return ReceiveCurrent(InfiniteTimeout, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, CursorHandle.NullHandle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Peek1"]/*' />
/// <devdoc>
/// <para>
/// Returns without removing (peeks) the first message
/// available in the queue referenced by the <see cref='System.Messaging.MessageQueue'/>
/// . Waits
/// the specified interval for a message to become
/// available.
/// </para>
/// </devdoc>
public Message Peek(TimeSpan timeout)
{
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, CursorHandle.NullHandle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
}
public Message Peek(TimeSpan timeout, Cursor cursor, PeekAction action)
{
if ((action != PeekAction.Current) && (action != PeekAction.Next))
throw new ArgumentOutOfRangeException(Res.GetString(Res.InvalidParameter, "action", action.ToString()));
if (cursor == null)
throw new ArgumentNullException("cursor");
return ReceiveCurrent(timeout, (int)action, cursor.Handle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekById"]/*' />
/// <devdoc>
/// <para>
/// Peeks the message that matches the given ID.
/// If there is no message with a matching ID,
/// an exception will be raised.
/// </para>
/// </devdoc>
public Message PeekById(string id)
{
return ReceiveBy(id, TimeSpan.Zero, false, true, false, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekById1"]/*' />
/// <devdoc>
/// <para>
/// Peeks the message that matches the
/// given ID. This method waits until a message with
/// a matching ID is available, or the given timeout
/// expires when no more messages can be
/// inspected.
/// </para>
/// </devdoc>
public Message PeekById(string id, TimeSpan timeout)
{
return ReceiveBy(id, timeout, false, true, true, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekByCorrelationId"]/*' />
/// <devdoc>
/// <para>
/// Peeks the message that matches the
/// given correlation ID. If there is no message with
/// a matching correlation ID, an exception is
/// thrown.
/// </para>
/// </devdoc>
public Message PeekByCorrelationId(string correlationId)
{
return ReceiveBy(correlationId, TimeSpan.Zero, false, false, false, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekByCorrelationId1"]/*' />
/// <devdoc>
/// <para>
/// Peeks the message that matches the
/// given correlation ID. This function will wait
/// until a message with a matching correlation ID is
/// available, or the given timeout expires when
/// no more messages can be inspected.
/// </para>
/// </devdoc>
public Message PeekByCorrelationId(string correlationId, TimeSpan timeout)
{
return ReceiveBy(correlationId, timeout, false, false, true, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Purge"]/*' />
/// <devdoc>
/// <para>
/// Deletes all the messages contained in the queue.
/// </para>
/// </devdoc>
public void Purge()
{
if (!receiveGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Receive, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
receiveGranted = true;
}
int status = StaleSafePurgeQueue();
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive"]/*' />
/// <devdoc>
/// <para>
/// Receives the first message available in the queue referenced by the <see cref='System.Messaging.MessageQueue'/> . This
/// call is synchronous. It blocks the current thread of execution until a message is
/// available.
/// </para>
/// </devdoc>
public Message Receive()
{
return ReceiveCurrent(InfiniteTimeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive1"]/*' />
/// <devdoc>
/// <para>
/// Receives the first message available in the queue referenced by the <see cref='System.Messaging.MessageQueue'/> . This
/// call is synchronous. It blocks the current thread of execution until a message is
/// available.
/// </para>
/// </devdoc>
public Message Receive(MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
return ReceiveCurrent(InfiniteTimeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, transaction, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive5"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Message Receive(MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
return ReceiveCurrent(InfiniteTimeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, null, transactionType);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive2"]/*' />
/// <devdoc>
/// <para>
/// Receives the first message available in the queue
/// referenced by the <see cref='System.Messaging.MessageQueue'/>
/// . Waits the specified interval for a message to become
/// available.
/// </para>
/// </devdoc>
public Message Receive(TimeSpan timeout)
{
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
}
public Message Receive(TimeSpan timeout, Cursor cursor)
{
if (cursor == null)
throw new ArgumentNullException("cursor");
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursor.Handle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive3"]/*' />
/// <devdoc>
/// <para>
/// Receives the first message available in the queue
/// referenced by the <see cref='System.Messaging.MessageQueue'/>
/// . Waits the specified interval for a message to become
/// available.
/// </para>
/// </devdoc>
public Message Receive(TimeSpan timeout, MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, transaction, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive4"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Message Receive(TimeSpan timeout, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, null, transactionType);
}
public Message Receive(TimeSpan timeout, Cursor cursor, MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
if (cursor == null)
throw new ArgumentNullException("cursor");
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursor.Handle, MessageReadPropertyFilter, transaction, MessageQueueTransactionType.None);
}
public Message Receive(TimeSpan timeout, Cursor cursor, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
if (cursor == null)
throw new ArgumentNullException("cursor");
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursor.Handle, MessageReadPropertyFilter, null, transactionType);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveAsync"]/*' />
/// <internalonly/>
private unsafe IAsyncResult ReceiveAsync(TimeSpan timeout, CursorHandle cursorHandle, int action, AsyncCallback callback, object stateObject)
{
long timeoutInMilliseconds = (long)timeout.TotalMilliseconds;
if (timeoutInMilliseconds < 0 || timeoutInMilliseconds > UInt32.MaxValue)
throw new ArgumentException(Res.GetString(Res.InvalidParameter, "timeout", timeout.ToString()));
if (action == NativeMethods.QUEUE_ACTION_RECEIVE)
{
if (!receiveGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Receive, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
receiveGranted = true;
}
}
else
{
if (!peekGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Peek, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
peekGranted = true;
}
}
if (!attached)
{
lock (this)
{
if (!attached)
{
MessageQueueHandle handle = MQInfo.ReadHandle;
int handleInformation;
// If GetHandleInformation returns false, it means that the
// handle created for reading is not a File handle.
if (!SafeNativeMethods.GetHandleInformation(handle, out handleInformation))
// If not a File handle, need to use MSMQ
// APC based async IO.
// We will need to store references to pending async requests (bug 88607)
this.useThreadPool = false;
else
{
// File handle can use IOCompletion ports
// since it only happens for NT
MQInfo.BindToThreadPool();
this.useThreadPool = true;
}
attached = true;
}
}
}
if (callback == null)
{
if (this.onRequestCompleted == null)
this.onRequestCompleted = new AsyncCallback(this.OnRequestCompleted);
callback = this.onRequestCompleted;
}
AsynchronousRequest request = new AsynchronousRequest(this, (uint)timeoutInMilliseconds, cursorHandle, action, this.useThreadPool, stateObject, callback);
//
// Bug 88607 - keep a reference to outstanding asyncresult so its' not GCed
// This applies when GetHandleInformation returns false -> useThreadPool set to false
// It should only happen on dependent client, but we here we cover all GetHandleInformation
// failure paths for robustness.
//
// Need to add reference before calling BeginRead because request can complete by the time
// reference is added, and it will be leaked if added to table after completion
//
if (!this.useThreadPool)
{
OutstandingAsyncRequests[request] = request;
}
request.BeginRead();
return (IAsyncResult)request;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveBy"]/*' />
/// <internalonly/>
private Message ReceiveBy(string id, TimeSpan timeout, bool remove, bool compareId, bool throwTimeout, MessageQueueTransaction transaction, MessageQueueTransactionType transactionType)
{
if (id == null)
throw new ArgumentNullException("id");
if (timeout < TimeSpan.Zero || timeout > InfiniteTimeout)
throw new ArgumentException(Res.GetString(Res.InvalidParameter, "timeout", timeout.ToString()));
MessagePropertyFilter oldFilter = this.receiveFilter;
CursorHandle cursorHandle = null;
try
{
this.receiveFilter = new MessagePropertyFilter();
this.receiveFilter.ClearAll();
if (!compareId)
this.receiveFilter.CorrelationId = true;
else
this.receiveFilter.Id = true;
//
// Use cursor (and not MessageEnumerator) to navigate the queue because enumerator implementation can be incorrect
// in multithreaded scenarios (see bug 329311)
//
//
// Get cursor handle
//
int status = SafeNativeMethods.MQCreateCursor(this.MQInfo.ReadHandle, out cursorHandle);
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
try
{
//
// peek first message in the queue
//
Message message = this.ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, cursorHandle,
MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
while (message != null)
{
if ((compareId && String.Compare(message.Id, id, true, CultureInfo.InvariantCulture) == 0) ||
(!compareId && String.Compare(message.CorrelationId, id, true, CultureInfo.InvariantCulture) == 0))
{
//
// Found matching message, receive it and return
//
this.receiveFilter = oldFilter;
if (remove)
{
if (transaction == null)
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursorHandle,
this.MessageReadPropertyFilter, null, transactionType);
else
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursorHandle,
this.MessageReadPropertyFilter, transaction, MessageQueueTransactionType.None);
}
else
return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, cursorHandle,
this.MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
} //end if
//
// Continue search, peek next message
//
message = this.ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_PEEK_NEXT, cursorHandle,
MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
}
}
catch (MessageQueueException)
{
// don't do anything, just use this catch as convenient means to exit the search
}
}
finally
{
this.receiveFilter = oldFilter;
if (cursorHandle != null)
{
cursorHandle.Close();
}
}
if (!throwTimeout)
throw new InvalidOperationException(Res.GetString("MessageNotFound"));
else
throw new MessageQueueException((int)MessageQueueErrorCode.IOTimeout);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches the given
/// ID. If there is no message with a matching
/// ID, an exception is thrown.
/// </para>
/// </devdoc>
public Message ReceiveById(string id)
{
return ReceiveBy(id, TimeSpan.Zero, true, true, false, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById1"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches the given
/// ID. If there is no message with a matching
/// ID, an exception is thrown.
/// </para>
/// </devdoc>
public Message ReceiveById(string id, MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
return ReceiveBy(id, TimeSpan.Zero, true, true, false, transaction, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById5"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches the given
/// ID. If there is no message with a matching
/// ID, an exception is thrown.
/// </para>
/// </devdoc>
public Message ReceiveById(string id, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
return ReceiveBy(id, TimeSpan.Zero, true, true, false, null, transactionType);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById2"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches the given
/// ID. This method waits until a message with
/// a matching id is available or the given timeout
/// expires when no more messages can be
/// inspected.
/// </para>
/// </devdoc>
public Message ReceiveById(string id, TimeSpan timeout)
{
return ReceiveBy(id, timeout, true, true, true, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById3"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches the given
/// ID. This method waits until a message with
/// a matching id is available or the given timeout
/// expires when no more messages can be
/// inspected.
/// </para>
/// </devdoc>
public Message ReceiveById(string id, TimeSpan timeout, MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
return ReceiveBy(id, timeout, true, true, true, transaction, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById4"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches the given
/// ID. This method waits until a message with
/// a matching id is available or the given timeout
/// expires when no more messages can be
/// inspected.
/// </para>
/// </devdoc>
public Message ReceiveById(string id, TimeSpan timeout, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
return ReceiveBy(id, timeout, true, true, true, null, transactionType);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId"]/*' />
/// <devdoc>
/// <para>
/// Receivess the message that matches the
/// given correlation ID. If there is no message with
/// a matching correlation ID, an exception is
/// thrown.
/// </para>
/// </devdoc>
public Message ReceiveByCorrelationId(string correlationId)
{
return ReceiveBy(correlationId, TimeSpan.Zero, true, false, false, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId1"]/*' />
/// <devdoc>
/// <para>
/// Receivess the message that matches the
/// given correlation ID. If there is no message with
/// a matching correlation ID, an exception is
/// thrown.
/// </para>
/// </devdoc>
public Message ReceiveByCorrelationId(string correlationId, MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
return ReceiveBy(correlationId, TimeSpan.Zero, true, false, false, transaction, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId5"]/*' />
/// <devdoc>
/// <para>
/// Receivess the message that matches the
/// given correlation ID. If there is no message with
/// a matching correlation ID, an exception is
/// thrown.
/// </para>
/// </devdoc>
public Message ReceiveByCorrelationId(string correlationId, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
return ReceiveBy(correlationId, TimeSpan.Zero, true, false, false, null, transactionType);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId2"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches
/// the given correlation ID. This method waits
/// until a message with a matching correlation ID is
/// available or the given timeout expires when
/// no more messages can be inspected.
/// </para>
/// </devdoc>
public Message ReceiveByCorrelationId(string correlationId, TimeSpan timeout)
{
return ReceiveBy(correlationId, timeout, true, false, true, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId3"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches
/// the given correlation ID. This method waits
/// until a message with a matching correlation ID is
/// available or the given timeout expires when
/// no more messages can be inspected.
/// </para>
/// </devdoc>
public Message ReceiveByCorrelationId(string correlationId, TimeSpan timeout, MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
return ReceiveBy(correlationId, timeout, true, false, true, transaction, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId4"]/*' />
/// <devdoc>
/// <para>
/// Receives the message that matches
/// the given correlation ID. This method waits
/// until a message with a matching correlation ID is
/// available or the given timeout expires when
/// no more messages can be inspected.
/// </para>
/// </devdoc>
public Message ReceiveByCorrelationId(string correlationId, TimeSpan timeout, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
return ReceiveBy(correlationId, timeout, true, false, true, null, transactionType);
}
public Message ReceiveByLookupId(long lookupId)
{
return InternalReceiveByLookupId(true, MessageLookupAction.Current, lookupId, null, MessageQueueTransactionType.None);
}
public Message ReceiveByLookupId(MessageLookupAction action, long lookupId, MessageQueueTransactionType transactionType)
{
return InternalReceiveByLookupId(true, action, lookupId, null, transactionType);
}
public Message ReceiveByLookupId(MessageLookupAction action, long lookupId, MessageQueueTransaction transaction)
{
return InternalReceiveByLookupId(true, action, lookupId, transaction, MessageQueueTransactionType.None);
}
public Message PeekByLookupId(long lookupId)
{
return InternalReceiveByLookupId(false, MessageLookupAction.Current, lookupId, null, MessageQueueTransactionType.None);
}
public Message PeekByLookupId(MessageLookupAction action, long lookupId)
{
return InternalReceiveByLookupId(false, action, lookupId, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.InternalReceiveByLookupId"]/*' />
/// <internalonly/>
internal unsafe Message InternalReceiveByLookupId(bool receive, MessageLookupAction lookupAction, long lookupId,
MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
if (!ValidationUtility.ValidateMessageLookupAction(lookupAction))
throw new InvalidEnumArgumentException("action", (int)lookupAction, typeof(MessageLookupAction));
if (!Msmq3OrNewer)
throw new PlatformNotSupportedException(Res.GetString(Res.PlatformNotSupported));
int action;
if (receive)
{
if (!receiveGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Receive, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
receiveGranted = true;
}
action = NativeMethods.LOOKUP_RECEIVE_MASK | (int)lookupAction;
}
else
{
if (!peekGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Peek, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
peekGranted = true;
}
action = NativeMethods.LOOKUP_PEEK_MASK | (int)lookupAction;
}
MessagePropertyFilter filter = MessageReadPropertyFilter;
int status = 0;
Message receiveMessage = null;
MessagePropertyVariants.MQPROPS lockedReceiveMessage = null;
if (filter != null)
{
receiveMessage = new Message((MessagePropertyFilter)filter.Clone());
receiveMessage.SetLookupId(lookupId);
if (this.formatter != null)
receiveMessage.Formatter = (IMessageFormatter)this.formatter.Clone();
lockedReceiveMessage = receiveMessage.Lock();
}
try
{
if ((internalTransaction != null) && receive)
status = StaleSafeReceiveByLookupId(lookupId, action, lockedReceiveMessage, null, null, internalTransaction.BeginQueueOperation());
else
status = StaleSafeReceiveByLookupId(lookupId, action, lockedReceiveMessage, null, null, (IntPtr)transactionType);
if (receiveMessage != null)
{
//Need to keep trying until enough space has been allocated.
//Concurrent scenarions might not succeed on the second retry.
while (MessageQueue.IsMemoryError(status))
{
receiveMessage.Unlock();
receiveMessage.AdjustMemory();
lockedReceiveMessage = receiveMessage.Lock();
if ((internalTransaction != null) && receive)
status = StaleSafeReceiveByLookupId(lookupId, action, lockedReceiveMessage, null, null, internalTransaction.InnerTransaction);
else
status = StaleSafeReceiveByLookupId(lookupId, action, lockedReceiveMessage, null, null, (IntPtr)transactionType);
}
receiveMessage.Unlock();
}
}
finally
{
if ((internalTransaction != null) && receive)
internalTransaction.EndQueueOperation();
}
if (status == (int)MessageQueueErrorCode.MessageNotFound)
throw new InvalidOperationException(Res.GetString("MessageNotFound"));
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
return receiveMessage;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveCurrent"]/*' />
/// <internalonly/>
internal unsafe Message ReceiveCurrent(TimeSpan timeout, int action, CursorHandle cursor, MessagePropertyFilter filter, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
{
long timeoutInMilliseconds = (long)timeout.TotalMilliseconds;
if (timeoutInMilliseconds < 0 || timeoutInMilliseconds > UInt32.MaxValue)
throw new ArgumentException(Res.GetString(Res.InvalidParameter, "timeout", timeout.ToString()));
if (action == NativeMethods.QUEUE_ACTION_RECEIVE)
{
if (!receiveGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Receive, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
receiveGranted = true;
}
}
else
{
if (!peekGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Peek, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
peekGranted = true;
}
}
int status = 0;
Message receiveMessage = null;
MessagePropertyVariants.MQPROPS lockedReceiveMessage = null;
if (filter != null)
{
receiveMessage = new Message((MessagePropertyFilter)filter.Clone());
if (this.formatter != null)
receiveMessage.Formatter = (IMessageFormatter)this.formatter.Clone();
lockedReceiveMessage = receiveMessage.Lock();
}
try
{
if (internalTransaction != null)
status = StaleSafeReceiveMessage((uint)timeoutInMilliseconds, action, lockedReceiveMessage, null, null, cursor, internalTransaction.BeginQueueOperation());
else
status = StaleSafeReceiveMessage((uint)timeoutInMilliseconds, action, lockedReceiveMessage, null, null, cursor, (IntPtr)transactionType);
if (receiveMessage != null)
{
//Need to keep trying until enough space has been allocated.
//Concurrent scenarions might not succeed on the second retry.
while (MessageQueue.IsMemoryError(status))
{
// Need to special-case retrying PeekNext after a buffer overflow
// by using PeekCurrent on retries since otherwise MSMQ will
// advance the cursor, skipping messages
if (action == NativeMethods.QUEUE_ACTION_PEEK_NEXT)
action = NativeMethods.QUEUE_ACTION_PEEK_CURRENT;
receiveMessage.Unlock();
receiveMessage.AdjustMemory();
lockedReceiveMessage = receiveMessage.Lock();
if (internalTransaction != null)
status = StaleSafeReceiveMessage((uint)timeoutInMilliseconds, action, lockedReceiveMessage, null, null, cursor, internalTransaction.InnerTransaction);
else
status = StaleSafeReceiveMessage((uint)timeoutInMilliseconds, action, lockedReceiveMessage, null, null, cursor, (IntPtr)transactionType);
}
}
}
finally
{
if (receiveMessage != null)
receiveMessage.Unlock();
if (internalTransaction != null)
internalTransaction.EndQueueOperation();
}
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
return receiveMessage;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Refresh"]/*' />
/// <devdoc>
/// <para>
/// Refreshes the properties presented by the <see cref='System.Messaging.MessageQueue'/>
/// to reflect the current state of the
/// resource.
/// </para>
/// </devdoc>
//
public void Refresh()
{
this.PropertyFilter.ClearAll();
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SaveQueueProperties"]/*' />
/// <internalonly/>
private void SaveQueueProperties()
{
if (!administerGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Administer, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
administerGranted = true;
}
int status = UnsafeNativeMethods.MQSetQueueProperties(FormatName, Properties.Lock());
Properties.Unlock();
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send"]/*' />
/// <devdoc>
/// <para>
/// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
/// . The object is serialized
/// using the formatter provided.
/// </para>
/// </devdoc>
public void Send(object obj)
{
SendInternal(obj, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send1"]/*' />
/// <devdoc>
/// <para>
/// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
/// . The object is serialized
/// using the formatter provided.
/// </para>
/// </devdoc>
public void Send(object obj, MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
SendInternal(obj, transaction, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send5"]/*' />
/// <devdoc>
/// <para>
/// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
/// . The object is serialized
/// using the formatter provided.
/// </para>
/// </devdoc>
public void Send(object obj, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
SendInternal(obj, null, transactionType);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send2"]/*' />
/// <devdoc>
/// <para>
/// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>.
/// The object will be serialized
/// using the formatter provided.
/// </para>
/// </devdoc>
public void Send(object obj, string label)
{
Send(obj, label, null, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send3"]/*' />
/// <devdoc>
/// <para>
/// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>.
/// The object will be serialized
/// using the formatter provided.
/// </para>
/// </devdoc>
public void Send(object obj, string label, MessageQueueTransaction transaction)
{
if (transaction == null)
throw new ArgumentNullException("transaction");
Send(obj, label, transaction, MessageQueueTransactionType.None);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send4"]/*' />
/// <devdoc>
/// <para>
/// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>.
/// The object will be serialized
/// using the formatter provided.
/// </para>
/// </devdoc>
public void Send(object obj, string label, MessageQueueTransactionType transactionType)
{
if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
Send(obj, label, null, transactionType);
}
private void Send(object obj, string label, MessageQueueTransaction transaction, MessageQueueTransactionType transactionType)
{
if (label == null)
throw new ArgumentNullException("label");
if (obj is Message)
{
((Message)obj).Label = label;
SendInternal(obj, transaction, transactionType);
}
else
{
string oldLabel = this.DefaultPropertiesToSend.Label;
try
{
this.DefaultPropertiesToSend.Label = label;
SendInternal(obj, transaction, transactionType);
}
finally
{
this.DefaultPropertiesToSend.Label = oldLabel;
}
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SendInternal"]/*' />
/// <internalonly/>
private void SendInternal(object obj, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
{
if (!sendGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Send, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
sendGranted = true;
}
Message message = null;
if (obj is Message)
message = (Message)obj;
if (message == null)
{
message = this.DefaultPropertiesToSend.CachedMessage;
message.Formatter = this.Formatter;
message.Body = obj;
}
//Write cached properties and if message is being forwarded Clear queue specific properties
int status = 0;
message.AdjustToSend();
MessagePropertyVariants.MQPROPS properties = message.Lock();
try
{
if (internalTransaction != null)
status = StaleSafeSendMessage(properties, internalTransaction.BeginQueueOperation());
else
status = StaleSafeSendMessage(properties, (IntPtr)transactionType);
}
finally
{
message.Unlock();
if (internalTransaction != null)
internalTransaction.EndQueueOperation();
}
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ResolveQueueFromLabel"]/*' />
/// <internalonly/>
private static MessageQueue ResolveQueueFromLabel(string path, bool throwException)
{
MessageQueue[] queues = GetPublicQueuesByLabel(path.Substring(PREFIX_LABEL.Length), false);
if (queues.Length == 0)
{
if (throwException)
throw new InvalidOperationException(Res.GetString(Res.InvalidLabel, path.Substring(PREFIX_LABEL.Length)));
return null;
}
else if (queues.Length > 1)
throw new InvalidOperationException(Res.GetString(Res.AmbiguousLabel, path.Substring(PREFIX_LABEL.Length)));
return queues[0];
}
/// <internalonly/>
private static string ResolveFormatNameFromQueuePath(string queuePath, bool throwException)
{
string machine = queuePath.Substring(0, queuePath.IndexOf('\\'));
//The name includes the \\
string name = queuePath.Substring(queuePath.IndexOf('\\'));
//Check for machine DeadLetter or Journal
if (String.Compare(name, SUFIX_DEADLETTER, true, CultureInfo.InvariantCulture) == 0 ||
String.Compare(name, SUFIX_DEADXACT, true, CultureInfo.InvariantCulture) == 0 ||
String.Compare(name, SUFIX_JOURNAL, true, CultureInfo.InvariantCulture) == 0)
{
//Need to get the machine Id to construct the format name.
if (machine.CompareTo(".") == 0)
machine = MessageQueue.ComputerName;
//Create a guid to get the right format.
Guid machineId = MessageQueue.GetMachineId(machine);
StringBuilder newFormatName = new StringBuilder();
//System format names:
//MACHINE=guid;DEADXACT
//MACHINE=guid;DEADLETTER
//MACHINE=guid;JOURNAL
newFormatName.Append("MACHINE=");
newFormatName.Append(machineId.ToString());
if (String.Compare(name, SUFIX_DEADXACT, true, CultureInfo.InvariantCulture) == 0)
newFormatName.Append(";DEADXACT");
else if (String.Compare(name, SUFIX_DEADLETTER, true, CultureInfo.InvariantCulture) == 0)
newFormatName.Append(";DEADLETTER");
else
newFormatName.Append(";JOURNAL");
return newFormatName.ToString();
}
else
{
string realPath = queuePath;
bool journal = false;
if (queuePath.ToUpper(CultureInfo.InvariantCulture).EndsWith(SUFIX_JOURNAL))
{
journal = true;
int lastIndex = realPath.LastIndexOf('\\');
realPath = realPath.Substring(0, lastIndex);
}
int result;
int status = 0;
StringBuilder newFormatName = new StringBuilder(NativeMethods.MAX_LABEL_LEN);
result = NativeMethods.MAX_LABEL_LEN;
status = SafeNativeMethods.MQPathNameToFormatName(realPath, newFormatName, ref result);
if (status != 0)
{
if (throwException)
throw new MessageQueueException(status);
else if (status == (int)MessageQueueErrorCode.IllegalQueuePathName)
throw new MessageQueueException(status);
return null;
}
if (journal)
newFormatName.Append(";JOURNAL");
return newFormatName.ToString();
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ResetPermissions"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void ResetPermissions()
{
if (!administerGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Administer, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
administerGranted = true;
}
int result = UnsafeNativeMethods.MQSetQueueSecurity(FormatName, NativeMethods.DACL_SECURITY_INFORMATION, null);
if (result != NativeMethods.MQ_OK)
throw new MessageQueueException(result);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SetPermissions"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void SetPermissions(string user, MessageQueueAccessRights rights)
{
if (user == null)
throw new ArgumentNullException("user");
SetPermissions(user, rights, AccessControlEntryType.Allow);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SetPermissions1"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void SetPermissions(string user, MessageQueueAccessRights rights, AccessControlEntryType entryType)
{
if (user == null)
throw new ArgumentNullException("user");
Trustee t = new Trustee(user);
MessageQueueAccessControlEntry ace = new MessageQueueAccessControlEntry(t, rights, entryType);
AccessControlList dacl = new AccessControlList();
dacl.Add(ace);
SetPermissions(dacl);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SetPermissions2"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void SetPermissions(MessageQueueAccessControlEntry ace)
{
if (ace == null)
throw new ArgumentNullException("ace");
AccessControlList dacl = new AccessControlList();
dacl.Add(ace);
SetPermissions(dacl);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SetPermissions3"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "0#dacl")]
public void SetPermissions(AccessControlList dacl)
{
if (dacl == null)
throw new ArgumentNullException("dacl");
if (!administerGranted)
{
MessageQueuePermission permission = new MessageQueuePermission(MessageQueuePermissionAccess.Administer, PREFIX_FORMAT_NAME + this.FormatName);
permission.Demand();
administerGranted = true;
}
//Access control is not supported in Win9x, need to check
//the environment and take appropriate action.
AccessControlList.CheckEnvironment();
byte[] SecurityDescriptor = new byte[100];
int lengthNeeded = 0;
int mqResult;
GCHandle sdHandle = GCHandle.Alloc(SecurityDescriptor, GCHandleType.Pinned);
try
{
mqResult = UnsafeNativeMethods.MQGetQueueSecurity(FormatName,
NativeMethods.DACL_SECURITY_INFORMATION,
sdHandle.AddrOfPinnedObject(),
SecurityDescriptor.Length,
out lengthNeeded);
if (mqResult == NativeMethods.MQ_ERROR_SECURITY_DESCRIPTOR_TOO_SMALL)
{
sdHandle.Free();
SecurityDescriptor = new byte[lengthNeeded];
sdHandle = GCHandle.Alloc(SecurityDescriptor, GCHandleType.Pinned);
mqResult = UnsafeNativeMethods.MQGetQueueSecurity(FormatName,
NativeMethods.DACL_SECURITY_INFORMATION,
sdHandle.AddrOfPinnedObject(),
SecurityDescriptor.Length,
out lengthNeeded);
}
if (mqResult != NativeMethods.MQ_OK)
{
throw new MessageQueueException(mqResult);
}
bool daclPresent, daclDefaulted;
IntPtr pDacl;
bool success = UnsafeNativeMethods.GetSecurityDescriptorDacl(sdHandle.AddrOfPinnedObject(),
out daclPresent,
out pDacl,
out daclDefaulted);
if (!success)
throw new Win32Exception();
// At this point we have the DACL for the queue. Now we need to create
// a new security descriptor with an updated DACL.
NativeMethods.SECURITY_DESCRIPTOR newSecurityDescriptor = new NativeMethods.SECURITY_DESCRIPTOR();
UnsafeNativeMethods.InitializeSecurityDescriptor(newSecurityDescriptor,
NativeMethods.SECURITY_DESCRIPTOR_REVISION);
IntPtr newDacl = dacl.MakeAcl(pDacl);
try
{
success = UnsafeNativeMethods.SetSecurityDescriptorDacl(newSecurityDescriptor,
true,
newDacl,
false);
if (!success)
throw new Win32Exception();
int result = UnsafeNativeMethods.MQSetQueueSecurity(FormatName,
NativeMethods.DACL_SECURITY_INFORMATION,
newSecurityDescriptor);
if (result != NativeMethods.MQ_OK)
throw new MessageQueueException(result);
}
finally
{
AccessControlList.FreeAcl(newDacl);
}
//If the format name has been cached, let's
//remove it, since the process might no longer
//have access to the corresponding queue.
queueInfoCache.Remove(QueueInfoKey);
formatNameCache.Remove(path.ToUpper(CultureInfo.InvariantCulture));
}
finally
{
if (sdHandle.IsAllocated)
sdHandle.Free();
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ValidatePath"]/*' />
/// <internalonly/>
internal static bool ValidatePath(string path, bool checkQueueNameSize)
{
if (path == null || path.Length == 0)
return true;
String upperPath = path.ToUpper(CultureInfo.InvariantCulture);
if (upperPath.StartsWith(PREFIX_LABEL))
return true;
if (upperPath.StartsWith(PREFIX_FORMAT_NAME))
return true;
int number = 0;
int index = -1;
while (true)
{
int newIndex = upperPath.IndexOf('\\', index + 1);
if (newIndex == -1)
break;
else
index = newIndex;
++number;
}
if (number == 1)
{
if (checkQueueNameSize)
{
long length = path.Length - (index + 1);
if (length > 255)
throw new ArgumentException(Res.GetString(Res.LongQueueName));
}
return true;
}
if (number == 2)
{
if (upperPath.EndsWith(SUFIX_JOURNAL))
return true;
index = upperPath.LastIndexOf(SUFIX_PRIVATE + "\\");
if (index != -1)
return true;
}
if (number == 3 && upperPath.EndsWith(SUFIX_JOURNAL))
{
index = upperPath.LastIndexOf(SUFIX_PRIVATE + "\\");
if (index != -1)
return true;
}
return false;
}
/// <internalonly/>
internal void SetAccessMode(QueueAccessMode accessMode)
{
//
// this method should only be called from a constructor.
// we dont support changing queue access mode after contruction time.
//
if (!ValidationUtility.ValidateQueueAccessMode(accessMode))
throw new InvalidEnumArgumentException("accessMode", (int)accessMode, typeof(QueueAccessMode));
this.accessMode = accessMode;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.QueuePropertyFilter"]/*' />
/// <internalonly/>
private class QueuePropertyFilter
{
public bool Authenticate;
public bool BasePriority;
public bool CreateTime;
public bool EncryptionLevel;
public bool Id;
// disable csharp compiler warning #0414: field assigned unused value
#pragma warning disable 0414
public bool Transactional;
#pragma warning restore 0414
public bool Label;
public bool LastModifyTime;
public bool MaximumJournalSize;
public bool MaximumQueueSize;
public bool MulticastAddress;
// disable csharp compiler warning #0414: field assigned unused value
#pragma warning disable 0414
public bool Path;
#pragma warning restore 0414
public bool Category;
public bool UseJournalQueue;
public void ClearAll()
{
Authenticate = false;
BasePriority = false;
CreateTime = false;
EncryptionLevel = false;
Id = false;
Transactional = false;
Label = false;
LastModifyTime = false;
MaximumJournalSize = false;
MaximumQueueSize = false;
Path = false;
Category = false;
UseJournalQueue = false;
MulticastAddress = false;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest"]/*' />
/// <devdoc>
/// This class is used in asynchronous operations,
/// it keeps the context under which the asynchronous
/// request was posted.
/// </devdoc>
/// <internalonly/>
private class AsynchronousRequest : IAsyncResult
{
private IOCompletionCallback onCompletionStatusChanged;
private SafeNativeMethods.ReceiveCallback onMessageReceived;
private AsyncCallback callback;
private ManualResetEvent resetEvent;
private object asyncState;
private MessageQueue owner;
private bool isCompleted = false;
private int status = 0;
private Message message;
private int action;
private uint timeout;
private CursorHandle cursorHandle;
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.AsynchronousRequest"]/*' />
/// <devdoc>
/// Creates a new asynchronous request that
/// represents a pending asynchronous operation.
/// </devdoc>
/// <internalonly/>
internal unsafe AsynchronousRequest(MessageQueue owner, uint timeout, CursorHandle cursorHandle, int action, bool useThreadPool, object asyncState, AsyncCallback callback)
{
this.owner = owner;
this.asyncState = asyncState;
this.callback = callback;
this.action = action;
this.timeout = timeout;
this.resetEvent = new ManualResetEvent(false);
this.cursorHandle = cursorHandle;
if (!useThreadPool)
this.onMessageReceived = new SafeNativeMethods.ReceiveCallback(this.OnMessageReceived);
else
this.onCompletionStatusChanged = new IOCompletionCallback(this.OnCompletionStatusChanged);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.Action"]/*' />
/// <internalonly/>
internal int Action
{
get
{
return this.action;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.AsyncState"]/*' />
/// <devdoc>
/// IAsyncResult implementation
/// </devdoc>
public object AsyncState
{
get
{
return this.asyncState;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.AsyncWaitHandle"]/*' />
/// <devdoc>
/// IAsyncResult implementation
/// </devdoc>
public WaitHandle AsyncWaitHandle
{
get
{
return this.resetEvent;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.CompletedSynchronously"]/*' />
/// <devdoc>
/// IAsyncResult implementation
/// </devdoc>
public bool CompletedSynchronously
{
get
{
return false;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.IsCompleted"]/*' />
/// <devdoc>
/// IAsyncResult implementation
/// </devdoc>
/// <internalonly/>
public bool IsCompleted
{
get
{
return this.isCompleted;
}
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.BeginRead"]/*' />
/// <devdoc>
/// Does the actual asynchronous receive posting.
/// </devdoc>
/// <internalonly/>
internal unsafe void BeginRead()
{
NativeOverlapped* overlappedPointer = null;
if (this.onCompletionStatusChanged != null)
{
Overlapped overlapped = new Overlapped();
overlapped.AsyncResult = this;
overlappedPointer = overlapped.Pack(this.onCompletionStatusChanged, null);
}
int localStatus = 0;
this.message = new Message(owner.MessageReadPropertyFilter);
try
{
localStatus = this.owner.StaleSafeReceiveMessage(this.timeout, this.action, this.message.Lock(), overlappedPointer, this.onMessageReceived, this.cursorHandle, IntPtr.Zero);
while (MessageQueue.IsMemoryError(localStatus))
{
// Need to special-case retrying PeekNext after a buffer overflow
// by using PeekCurrent on retries since otherwise MSMQ will
// advance the cursor, skipping messages
if (this.action == NativeMethods.QUEUE_ACTION_PEEK_NEXT)
this.action = NativeMethods.QUEUE_ACTION_PEEK_CURRENT;
this.message.Unlock();
this.message.AdjustMemory();
localStatus = this.owner.StaleSafeReceiveMessage(this.timeout, this.action, this.message.Lock(), overlappedPointer, this.onMessageReceived, this.cursorHandle, IntPtr.Zero);
}
}
catch (Exception e)
{
// Here will would do all the cleanup that RaiseCompletionEvent does on failure path,
// but without raising completion event.
// This is to preserve pre-Whidbey Beta 2 behavior, when exception thrown from this method
// would prevent RaiseCompletionEvent from being called (and also leak resources)
this.message.Unlock();
if (overlappedPointer != null)
Overlapped.Free(overlappedPointer);
if (!this.owner.useThreadPool)
this.owner.OutstandingAsyncRequests.Remove(this);
throw e;
}
// NOTE: RaiseCompletionEvent is not in a finally block by design, for two reasons:
// 1) the contract of BeginRead is to throw exception and not to notify event handler.
// 2) we dont know what the value pf localStatus will be in case of exception
if (MessageQueue.IsFatalError(localStatus))
RaiseCompletionEvent(localStatus, overlappedPointer);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.End"]/*' />
/// <devdoc>
/// Waits until the request has been completed.
/// </devdoc>
/// <internalonly/>
internal Message End()
{
this.resetEvent.WaitOne();
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
if (this.owner.formatter != null)
this.message.Formatter = (IMessageFormatter)this.owner.formatter.Clone();
return this.message;
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.OnCompletionStatusChanged"]/*' />
/// <devdoc>
/// Thread pool IOCompletionPort bound callback.
/// </devdoc>
/// <internalonly/>
private unsafe void OnCompletionStatusChanged(uint errorCode, uint numBytes, NativeOverlapped* overlappedPointer)
{
int result = 0;
if (errorCode != 0)
{
// MSMQ does a hacky trick to return the operation
// result through the completion port.
// Microsoft Dec 2004. Bug 419155:
// NativeOverlapped.InternalLow returns IntPtr, which is 64 bits on a 64 bit platform.
// It contains MSMQ error code, which, when set to an error value, is outside of the int range
// Therefore, OverflowException is thrown in checked context.
// However, IntPtr (int) operator ALWAYS runs in checked context on 64 bit platforms.
// Therefore, we first cast to long to avoid OverflowException, and then cast to int
// in unchecked context
long msmqError = (long)overlappedPointer->InternalLow;
unchecked
{
result = (int)msmqError;
}
}
RaiseCompletionEvent(result, overlappedPointer);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.OnMessageReceived"]/*' />
/// <devdoc>
/// MSMQ APC based callback.
/// </devdoc>
/// <internalonly/>
private unsafe void OnMessageReceived(int result, IntPtr handle, int timeout, int action, IntPtr propertiesPointer, NativeOverlapped* overlappedPointer, IntPtr cursorHandle)
{
RaiseCompletionEvent(result, overlappedPointer);
}
/// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.RaiseCompletionEvent"]/*' />
/// <internalonly/>
// See comment explaining this SuppressMessage below
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
private unsafe void RaiseCompletionEvent(int result, NativeOverlapped* overlappedPointer)
{
if (MessageQueue.IsMemoryError(result))
{
while (MessageQueue.IsMemoryError(result))
{
// Need to special-case retrying PeekNext after a buffer overflow
// by using PeekCurrent on retries since otherwise MSMQ will
// advance the cursor, skipping messages
if (this.action == NativeMethods.QUEUE_ACTION_PEEK_NEXT)
this.action = NativeMethods.QUEUE_ACTION_PEEK_CURRENT;
this.message.Unlock();
this.message.AdjustMemory();
try
{
// ReadHandle called from StaleSafeReceiveMessage can throw if the handle has been invalidated
// (for example, by closing it), and subsequent MQOpenQueue fails for some reason.
// Therefore catch exception (otherwise process will die) and propagate error
// Microsoft Jan 2006 (Whidbey bug 570055)
result = this.owner.StaleSafeReceiveMessage(this.timeout, this.action, this.message.Lock(), overlappedPointer, this.onMessageReceived, this.cursorHandle, IntPtr.Zero);
}
catch (MessageQueueException e)
{
result = (int)e.MessageQueueErrorCode;
break;
}
}
if (!MessageQueue.IsFatalError(result))
return;
}
this.message.Unlock();
if (this.owner.IsCashedInfoInvalidOnReceive(result))
{
this.owner.MQInfo.Close();
try
{
// For explanation of this try/catch, see comment above
result = this.owner.StaleSafeReceiveMessage(this.timeout, this.action, this.message.Lock(), overlappedPointer, this.onMessageReceived, this.cursorHandle, IntPtr.Zero);
}
catch (MessageQueueException e)
{
result = (int)e.MessageQueueErrorCode;
}
if (!MessageQueue.IsFatalError(result))
return;
}
this.status = result;
if (overlappedPointer != null)
Overlapped.Free(overlappedPointer);
this.isCompleted = true;
this.resetEvent.Set();
try
{
//
// 511878: The code below breaks the contract of ISynchronizeInvoke.
// We fixed it in 367076, but that fix resulted in a regression that is bug 511878.
// "Proper fix" for 511878 requires special-casing Form. That causes us to
// load System.Windows.Forms and System.Drawing,
// which were previously not loaded on this path.
// As only one customer complained about 367076, we decided to revert to
// Everett behavior
//
if (this.owner.SynchronizingObject != null &&
this.owner.SynchronizingObject.InvokeRequired)
{
this.owner.SynchronizingObject.BeginInvoke(this.callback, new object[] { this });
}
else
this.callback(this);
}
catch (Exception)
{
// Microsoft, Dec 2004: ----ing exceptions here is a serious bug.
// However, it would be a breaking change to remove this catch,
// therefore we decided to preserve the existing behavior
}
finally
{
if (!this.owner.useThreadPool)
{
Debug.Assert(this.owner.OutstandingAsyncRequests.Contains(this));
this.owner.OutstandingAsyncRequests.Remove(this);
}
}
}
}
private int StaleSafePurgeQueue()
{
int status = UnsafeNativeMethods.MQPurgeQueue(MQInfo.ReadHandle);
if (status == (int)MessageQueueErrorCode.StaleHandle || status == (int)MessageQueueErrorCode.QueueDeleted)
{
MQInfo.Close();
status = UnsafeNativeMethods.MQPurgeQueue(MQInfo.ReadHandle);
}
return status;
}
private int StaleSafeSendMessage(MessagePropertyVariants.MQPROPS properties, IntPtr transaction)
{
//
// TransactionType.Automatic uses current System.Transactions transaction, if one is available;
// otherwise, it passes Automatic to MSMQ to support COM+ transactions
// NOTE: Need careful qualification of class names,
// since ITransaction is defined by System.Messaging.Interop, System.Transactions and System.EnterpriseServices
//
if ((MessageQueueTransactionType)transaction == MessageQueueTransactionType.Automatic)
{
System.Transactions.Transaction tx = System.Transactions.Transaction.Current;
if (tx != null)
{
System.Transactions.IDtcTransaction ntx =
System.Transactions.TransactionInterop.GetDtcTransaction(tx);
return StaleSafeSendMessage(properties, (ITransaction)ntx);
}
}
int status = UnsafeNativeMethods.MQSendMessage(MQInfo.WriteHandle, properties, transaction);
if (status == (int)MessageQueueErrorCode.StaleHandle || status == (int)MessageQueueErrorCode.QueueDeleted)
{
MQInfo.Close();
status = UnsafeNativeMethods.MQSendMessage(MQInfo.WriteHandle, properties, transaction);
}
return status;
}
private int StaleSafeSendMessage(MessagePropertyVariants.MQPROPS properties, ITransaction transaction)
{
int status = UnsafeNativeMethods.MQSendMessage(MQInfo.WriteHandle, properties, transaction);
if (status == (int)MessageQueueErrorCode.StaleHandle || status == (int)MessageQueueErrorCode.QueueDeleted)
{
MQInfo.Close();
status = UnsafeNativeMethods.MQSendMessage(MQInfo.WriteHandle, properties, transaction);
}
return status;
}
internal unsafe int StaleSafeReceiveMessage(uint timeout, int action, MessagePropertyVariants.MQPROPS properties, NativeOverlapped* overlapped,
SafeNativeMethods.ReceiveCallback receiveCallback, CursorHandle cursorHandle, IntPtr transaction)
{
//
// TransactionType.Automatic uses current System.Transactions transaction, if one is available;
// otherwise, it passes Automatic to MSMQ to support COM+ transactions
// NOTE: Need careful qualification of class names,
// since ITransaction is defined by System.Messaging.Interop, System.Transactions and System.EnterpriseServices
//
if ((MessageQueueTransactionType)transaction == MessageQueueTransactionType.Automatic)
{
System.Transactions.Transaction tx = System.Transactions.Transaction.Current;
if (tx != null)
{
System.Transactions.IDtcTransaction ntx =
System.Transactions.TransactionInterop.GetDtcTransaction(tx);
return StaleSafeReceiveMessage(timeout, action, properties, overlapped, receiveCallback, cursorHandle, (ITransaction)ntx);
}
}
int status = UnsafeNativeMethods.MQReceiveMessage(MQInfo.ReadHandle, timeout, action, properties, overlapped, receiveCallback, cursorHandle, transaction);
if (IsCashedInfoInvalidOnReceive(status))
{
MQInfo.Close(); //invalidate cached ReadHandle, so it will be refreshed on next access
status = UnsafeNativeMethods.MQReceiveMessage(MQInfo.ReadHandle, timeout, action, properties, overlapped, receiveCallback, cursorHandle, transaction);
}
return status;
}
private unsafe int StaleSafeReceiveMessage(uint timeout, int action, MessagePropertyVariants.MQPROPS properties, NativeOverlapped* overlapped,
SafeNativeMethods.ReceiveCallback receiveCallback, CursorHandle cursorHandle, ITransaction transaction)
{
int status = UnsafeNativeMethods.MQReceiveMessage(MQInfo.ReadHandle, timeout, action, properties, overlapped, receiveCallback, cursorHandle, transaction);
if (IsCashedInfoInvalidOnReceive(status))
{
MQInfo.Close(); //invalidate cached ReadHandle, so it will be refreshed on next access
status = UnsafeNativeMethods.MQReceiveMessage(MQInfo.ReadHandle, timeout, action, properties, overlapped, receiveCallback, cursorHandle, transaction);
}
return status;
}
private unsafe int StaleSafeReceiveByLookupId(long lookupId, int action, MessagePropertyVariants.MQPROPS properties,
NativeOverlapped* overlapped, SafeNativeMethods.ReceiveCallback receiveCallback, IntPtr transaction)
{
if ((MessageQueueTransactionType)transaction == MessageQueueTransactionType.Automatic)
{
System.Transactions.Transaction tx = System.Transactions.Transaction.Current;
if (tx != null)
{
System.Transactions.IDtcTransaction ntx =
System.Transactions.TransactionInterop.GetDtcTransaction(tx);
return StaleSafeReceiveByLookupId(lookupId, action, properties, overlapped, receiveCallback, (ITransaction)ntx);
}
}
int status = UnsafeNativeMethods.MQReceiveMessageByLookupId(MQInfo.ReadHandle, lookupId, action, properties, overlapped, receiveCallback, transaction);
if (IsCashedInfoInvalidOnReceive(status))
{
MQInfo.Close(); //invalidate cached ReadHandle, so it will be refreshed on next access
status = UnsafeNativeMethods.MQReceiveMessageByLookupId(MQInfo.ReadHandle, lookupId, action, properties, overlapped, receiveCallback, transaction);
}
return status;
}
private unsafe int StaleSafeReceiveByLookupId(long lookupId, int action, MessagePropertyVariants.MQPROPS properties,
NativeOverlapped* overlapped, SafeNativeMethods.ReceiveCallback receiveCallback, ITransaction transaction)
{
int status = UnsafeNativeMethods.MQReceiveMessageByLookupId(MQInfo.ReadHandle, lookupId, action, properties, overlapped, receiveCallback, transaction);
if (IsCashedInfoInvalidOnReceive(status))
{
MQInfo.Close(); //invalidate cached ReadHandle, so it will be refreshed on next access
status = UnsafeNativeMethods.MQReceiveMessageByLookupId(MQInfo.ReadHandle, lookupId, action, properties, overlapped, receiveCallback, transaction);
}
return status;
}
private bool IsCashedInfoInvalidOnReceive(int receiveResult)
{
// returns true if return code of ReceiveMessage indicates
// that cached handle used for receive has become invalid
return (receiveResult == (int)MessageQueueErrorCode.StaleHandle || //both qm and ac restarted
receiveResult == (int)MessageQueueErrorCode.InvalidHandle || //get this if ac is not restarted
receiveResult == (int)MessageQueueErrorCode.InvalidParameter); // get this on w2k
}
internal class CacheTable<Key, Value>
{
private Dictionary<Key, CacheEntry<Value>> table;
private ReaderWriterLock rwLock;
// used for debugging
private string name;
// when the number of entries in the hashtable gets larger than capacity,
// the "stale" entries are removed and capacity is reset to twice the number
// of remaining entries
private int capacity;
private int originalCapacity;
// time, in seconds, after which an entry is considerred stale (if the reference
// count is zero)
private TimeSpan staleTime;
public CacheTable(string name, int capacity, TimeSpan staleTime)
{
this.originalCapacity = capacity;
this.capacity = capacity;
this.staleTime = staleTime;
this.name = name;
this.rwLock = new System.Threading.ReaderWriterLock();
this.table = new Dictionary<Key, CacheEntry<Value>>();
}
public Value Get(Key key)
{
Value val = default(Value); // This keyword might change with C# compiler
rwLock.AcquireReaderLock(-1);
try
{
if (table.ContainsKey(key))
{
CacheEntry<Value> entry = table[key];
if (entry != null)
{
entry.timeStamp = System.DateTime.UtcNow;
val = entry.contents;
}
}
}
finally
{
rwLock.ReleaseReaderLock();
}
return val;
}
public void Put(Key key, Value val)
{
rwLock.AcquireWriterLock(-1);
try
{
if (val == null /* not Value.default - bug in C# compiler? */)
{
table[key] = null;
}
else
{
CacheEntry<Value> entry = null;
if (table.ContainsKey(key))
entry = table[key]; //which could be null also
if (entry == null)
{
entry = new CacheEntry<Value>();
table[key] = entry;
if (table.Count >= capacity)
{
ClearStale(staleTime);
}
}
entry.timeStamp = System.DateTime.UtcNow;
entry.contents = val;
}
}
finally
{
rwLock.ReleaseWriterLock();
}
}
public void Remove(Key key)
{
rwLock.AcquireWriterLock(-1);
try
{
if (table.ContainsKey(key))
table.Remove(key);
}
finally
{
rwLock.ReleaseWriterLock();
}
}
public void ClearStale(TimeSpan staleAge)
{
DateTime now = System.DateTime.UtcNow;
Dictionary<Key, CacheEntry<Value>> newTable = new Dictionary<Key, CacheEntry<Value>>();
rwLock.AcquireReaderLock(-1);
try
{
foreach (KeyValuePair<Key, CacheEntry<Value>> kv in table)
{
CacheEntry<Value> iterEntry = kv.Value;
// see if this entry is stale (ticks are 100 nano-sec.)
if (now - iterEntry.timeStamp < staleAge)
{
newTable[kv.Key] = kv.Value;
}
}
}
finally
{
rwLock.ReleaseReaderLock();
}
rwLock.AcquireWriterLock(-1);
table = newTable;
capacity = 2 * table.Count;
if (capacity < originalCapacity) capacity = originalCapacity;
rwLock.ReleaseWriterLock();
}
private class CacheEntry<T>
{
public T contents;
public DateTime timeStamp;
}
}
internal class MQCacheableInfo
{
// Double-checked locking pattern requires volatile for read/write synchronization
private volatile MessageQueueHandle readHandle = MessageQueueHandle.InvalidHandle;
// Double-checked locking pattern requires volatile for read/write synchronization
private volatile MessageQueueHandle writeHandle = MessageQueueHandle.InvalidHandle;
private bool isTransactional;
// Double-checked locking pattern requires volatile for read/write synchronization
private volatile bool isTransactional_valid = false;
// Double-checked locking pattern requires volatile for read/write synchronization
private volatile bool boundToThreadPool;
private string formatName;
private int shareMode;
private QueueAccessModeHolder accessMode;
private int refCount;
private bool disposed;
private object syncRoot = new object();
public MQCacheableInfo(string formatName, QueueAccessMode accessMode, int shareMode)
{
this.formatName = formatName;
this.shareMode = shareMode;
// For each accessMode, corresponding QueueAccessModeHolder is a singleton.
// Call factory method to return existing holder for this access mode,
// or make a new one if noone used this access mode before.
//
this.accessMode = QueueAccessModeHolder.GetQueueAccessModeHolder(accessMode);
}
public bool CanRead
{
get
{
if (!accessMode.CanRead())
return false;
if (readHandle.IsInvalid)
{
if (this.disposed)
throw new ObjectDisposedException(GetType().Name);
lock (this.syncRoot)
{
if (readHandle.IsInvalid)
{
MessageQueueHandle result;
int status = UnsafeNativeMethods.MQOpenQueue(this.formatName, accessMode.GetReadAccessMode(), shareMode, out result);
if (MessageQueue.IsFatalError(status))
return false;
readHandle = result;
}
}
}
return true;
}
}
public bool CanWrite
{
get
{
if (!accessMode.CanWrite())
return false;
if (writeHandle.IsInvalid)
{
if (this.disposed)
throw new ObjectDisposedException(GetType().Name);
lock (this.syncRoot)
{
if (writeHandle.IsInvalid)
{
MessageQueueHandle result;
int status = UnsafeNativeMethods.MQOpenQueue(this.formatName, accessMode.GetWriteAccessMode(), 0, out result);
if (MessageQueue.IsFatalError(status))
return false;
writeHandle = result;
}
}
}
return true;
}
}
public int RefCount
{
get
{
return this.refCount;
}
}
public MessageQueueHandle ReadHandle
{
get
{
if (readHandle.IsInvalid)
{
if (this.disposed)
throw new ObjectDisposedException(GetType().Name);
lock (this.syncRoot)
{
if (readHandle.IsInvalid)
{
MessageQueueHandle result;
int status = UnsafeNativeMethods.MQOpenQueue(this.formatName, accessMode.GetReadAccessMode(), shareMode, out result);
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
readHandle = result;
}
}
}
return readHandle;
}
}
public MessageQueueHandle WriteHandle
{
get
{
if (writeHandle.IsInvalid)
{
if (this.disposed)
throw new ObjectDisposedException(GetType().Name);
lock (this.syncRoot)
{
if (writeHandle.IsInvalid)
{
MessageQueueHandle result;
int status = UnsafeNativeMethods.MQOpenQueue(this.formatName, accessMode.GetWriteAccessMode(), 0, out result);
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
writeHandle = result;
}
}
}
return writeHandle;
}
}
public bool Transactional
{
get
{
if (!isTransactional_valid)
{
lock (this.syncRoot)
{
if (!isTransactional_valid)
{
QueuePropertyVariants props = new QueuePropertyVariants();
props.SetUI1(NativeMethods.QUEUE_PROPID_TRANSACTION, (byte)0);
int status = UnsafeNativeMethods.MQGetQueueProperties(formatName, props.Lock());
props.Unlock();
if (MessageQueue.IsFatalError(status))
throw new MessageQueueException(status);
this.isTransactional = (props.GetUI1(NativeMethods.QUEUE_PROPID_TRANSACTION) != NativeMethods.QUEUE_TRANSACTIONAL_NONE);
isTransactional_valid = true;
}
}
}
return isTransactional;
}
}
public void AddRef()
{
lock (this)
{
++refCount;
}
}
public void BindToThreadPool()
{
if (!this.boundToThreadPool)
{
lock (this)
{
if (!this.boundToThreadPool)
{
//SECREVIEW: At this point at least MessageQueue permission with Browse
// access has already been demanded.
SecurityPermission permission = new SecurityPermission(PermissionState.Unrestricted);
permission.Assert();
try
{
ThreadPool.BindHandle(ReadHandle);
}
finally
{
SecurityPermission.RevertAssert();
}
this.boundToThreadPool = true;
}
}
}
}
public void CloseIfNotReferenced()
{
lock (this)
{
if (RefCount == 0)
Close();
}
}
public void Close()
{
this.boundToThreadPool = false;
if (!this.writeHandle.IsInvalid)
{
lock (this.syncRoot)
{
if (!this.writeHandle.IsInvalid)
{
this.writeHandle.Close();
}
}
}
if (!this.readHandle.IsInvalid)
{
lock (this.syncRoot)
{
if (!this.readHandle.IsInvalid)
{
this.readHandle.Close();
}
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
this.Close();
}
this.disposed = true;
}
public void Release()
{
lock (this)
{
--refCount;
}
}
}
internal class QueueInfoKeyHolder
{
private string formatName;
private QueueAccessMode accessMode;
public QueueInfoKeyHolder(string formatName, QueueAccessMode accessMode)
{
this.formatName = formatName.ToUpper(CultureInfo.InvariantCulture);
this.accessMode = accessMode;
}
public override int GetHashCode()
{
return formatName.GetHashCode() + (int)accessMode;
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType()) return false;
QueueInfoKeyHolder qik = (QueueInfoKeyHolder)obj;
return this.Equals(qik);
}
public bool Equals(QueueInfoKeyHolder qik)
{
if (qik == null) return false;
// string.Equals performs case-sensitive and culture-insensitive comparison
// we address case sensitivity by normalizing format name in the constructor
return ((this.accessMode == qik.accessMode) && this.formatName.Equals(qik.formatName));
}
}
}
}
|