123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- //------------------------------------------------------------------------------
- // <copyright file="MessageQueueEnumerator.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- //------------------------------------------------------------------------------
- using Experimental.System.Messaging.Interop;
- using System;
- using System.Collections;
- using System.Diagnostics.CodeAnalysis;
- using System.Globalization;
- using System.Runtime.InteropServices;
- namespace Experimental.System.Messaging
- {
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator"]/*' />
- /// <devdoc>
- /// <para>Provides (forward-only) cursor semantics to enumerate the queues on a
- /// computer.</para>
- /// <note type="rnotes">
- /// I'm assuming all the queues have to
- /// be
- /// on the same computer. Is this the case? Do we want to translate this reference
- /// to "cursor semantics" into English, or is it okay as it stands? Will the users
- /// understand the concept of a cursor?
- /// </note>
- /// </devdoc>
- public class MessageQueueEnumerator : MarshalByRefObject, IEnumerator, IDisposable
- {
- private MessageQueueCriteria criteria;
- private LocatorHandle locatorHandle = System.Messaging.Interop.LocatorHandle.InvalidHandle;
- private MessageQueue currentMessageQueue;
- private bool checkSecurity;
- private bool disposed;
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.MessageQueueEnumerator"]/*' />
- /// <internalonly/>
- internal MessageQueueEnumerator(MessageQueueCriteria criteria)
- {
- this.criteria = criteria;
- this.checkSecurity = true;
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.MessageQueueEnumerator1"]/*' />
- /// <internalonly/>
- internal MessageQueueEnumerator(MessageQueueCriteria criteria, bool checkSecurity)
- {
- this.criteria = criteria;
- this.checkSecurity = checkSecurity;
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Current"]/*' />
- /// <devdoc>
- /// Returns the current MessageQueue of the enumeration.
- /// Before the first call to MoveNext and following a call to MoveNext that
- /// returned false an InvalidOperationException will be thrown. Multiple
- /// calls to Current with no intervening calls to MoveNext will return the
- /// same MessageQueue object.
- /// </devdoc>
- public MessageQueue Current
- {
- get
- {
- if (this.currentMessageQueue == null)
- throw new InvalidOperationException(Res.GetString(Res.NoCurrentMessageQueue));
- return this.currentMessageQueue;
- }
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.IEnumerator.Current"]/*' />
- /// <internalonly/>
- object IEnumerator.Current
- {
- get
- {
- return this.Current;
- }
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Close"]/*' />
- /// <devdoc>
- /// <para>Frees the managed resources associated with the enumerator.</para>
- /// </devdoc>
- public void Close()
- {
- if (!this.locatorHandle.IsInvalid)
- {
- this.locatorHandle.Close();
- this.currentMessageQueue = null;
- }
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Dispose"]/*' />
- /// <devdoc>
- /// </devdoc>
- [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed")]
- public void Dispose()
- {
- Dispose(true);
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Dispose1"]/*' />
- /// <devdoc>
- /// <para>
- /// </para>
- /// </devdoc>
- [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "currentMessageQueue")]
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- this.Close();
- }
- this.disposed = true;
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.LocatorHandle"]/*' />
- /// <devdoc>
- /// <para>Indicates the native Message Queuing handle used to locate queues in a network. This
- /// property is read-only.</para>
- /// </devdoc>
- public IntPtr LocatorHandle
- {
- get { return this.Handle.DangerousGetHandle(); }
- }
- LocatorHandle Handle
- {
- get
- {
- if (this.locatorHandle.IsInvalid)
- {
- //Cannot allocate the locatorHandle if the object has been disposed, since finalization has been suppressed.
- if (this.disposed)
- throw new ObjectDisposedException(GetType().Name);
-
- Columns columns = new Columns(2);
- LocatorHandle enumHandle;
- columns.AddColumnId(NativeMethods.QUEUE_PROPID_PATHNAME);
- //Adding the instance property avoids accessing the DS a second
- //time, the formatName can be resolved by calling MQInstanceToFormatName
- columns.AddColumnId(NativeMethods.QUEUE_PROPID_INSTANCE);
- int status;
- if (this.criteria != null)
- status = UnsafeNativeMethods.MQLocateBegin(null, this.criteria.Reference, columns.GetColumnsRef(), out enumHandle);
- else
- status = UnsafeNativeMethods.MQLocateBegin(null, null, columns.GetColumnsRef(), out enumHandle);
- if (MessageQueue.IsFatalError(status))
- throw new MessageQueueException(status);
- this.locatorHandle = enumHandle;
- }
- return this.locatorHandle;
- }
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.MoveNext"]/*' />
- /// <devdoc>
- /// <para>
- /// Advances the enumerator to the next queue of the enumeration, if one
- /// is currently available.</para>
- /// </devdoc>
- public bool MoveNext()
- {
- MQPROPVARIANTS[] array = new MQPROPVARIANTS[2];
- int propertyCount;
- string currentItem;
- byte[] currentGuid = new byte[16];
- string machineName = null;
- if (this.criteria != null && this.criteria.FilterMachine)
- {
- if (this.criteria.MachineName.CompareTo(".") == 0)
- machineName = MessageQueue.ComputerName + "\\";
- else
- machineName = this.criteria.MachineName + "\\";
- }
- do
- {
- propertyCount = 2;
- int status;
- status = SafeNativeMethods.MQLocateNext(this.Handle, ref propertyCount, array);
- if (MessageQueue.IsFatalError(status))
- throw new MessageQueueException(status);
- if (propertyCount != 2)
- {
- this.currentMessageQueue = null;
- return false;
- }
- //Using Unicode API even on Win9x
- currentItem = Marshal.PtrToStringUni(array[0].ptr);
- Marshal.Copy(array[1].ptr, currentGuid, 0, 16);
- //MSMQ allocated this memory, lets free it.
- SafeNativeMethods.MQFreeMemory(array[0].ptr);
- SafeNativeMethods.MQFreeMemory(array[1].ptr);
- }
- while (machineName != null && (machineName.Length >= currentItem.Length ||
- String.Compare(machineName, 0, currentItem, 0, machineName.Length, true, CultureInfo.InvariantCulture) != 0));
- this.currentMessageQueue = new MessageQueue(currentItem, new Guid(currentGuid));
- return true;
- }
- /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Reset"]/*' />
- /// <devdoc>
- /// <para>Resets the cursor, so it points to the head of the list..</para>
- /// </devdoc>
- public void Reset()
- {
- this.Close();
- }
- }
- }
|