MessageQueueEnumerator.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. //------------------------------------------------------------------------------
  2. // <copyright file="MessageQueueEnumerator.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. //------------------------------------------------------------------------------
  6. using Experimental.System.Messaging.Interop;
  7. using System;
  8. using System.Collections;
  9. using System.Diagnostics.CodeAnalysis;
  10. using System.Globalization;
  11. using System.Runtime.InteropServices;
  12. namespace Experimental.System.Messaging
  13. {
  14. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator"]/*' />
  15. /// <devdoc>
  16. /// <para>Provides (forward-only) cursor semantics to enumerate the queues on a
  17. /// computer.</para>
  18. /// <note type="rnotes">
  19. /// I'm assuming all the queues have to
  20. /// be
  21. /// on the same computer. Is this the case? Do we want to translate this reference
  22. /// to "cursor semantics" into English, or is it okay as it stands? Will the users
  23. /// understand the concept of a cursor?
  24. /// </note>
  25. /// </devdoc>
  26. public class MessageQueueEnumerator : MarshalByRefObject, IEnumerator, IDisposable
  27. {
  28. private MessageQueueCriteria criteria;
  29. private LocatorHandle locatorHandle = System.Messaging.Interop.LocatorHandle.InvalidHandle;
  30. private MessageQueue currentMessageQueue;
  31. private bool checkSecurity;
  32. private bool disposed;
  33. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.MessageQueueEnumerator"]/*' />
  34. /// <internalonly/>
  35. internal MessageQueueEnumerator(MessageQueueCriteria criteria)
  36. {
  37. this.criteria = criteria;
  38. this.checkSecurity = true;
  39. }
  40. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.MessageQueueEnumerator1"]/*' />
  41. /// <internalonly/>
  42. internal MessageQueueEnumerator(MessageQueueCriteria criteria, bool checkSecurity)
  43. {
  44. this.criteria = criteria;
  45. this.checkSecurity = checkSecurity;
  46. }
  47. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Current"]/*' />
  48. /// <devdoc>
  49. /// Returns the current MessageQueue of the enumeration.
  50. /// Before the first call to MoveNext and following a call to MoveNext that
  51. /// returned false an InvalidOperationException will be thrown. Multiple
  52. /// calls to Current with no intervening calls to MoveNext will return the
  53. /// same MessageQueue object.
  54. /// </devdoc>
  55. public MessageQueue Current
  56. {
  57. get
  58. {
  59. if (this.currentMessageQueue == null)
  60. throw new InvalidOperationException(Res.GetString(Res.NoCurrentMessageQueue));
  61. return this.currentMessageQueue;
  62. }
  63. }
  64. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.IEnumerator.Current"]/*' />
  65. /// <internalonly/>
  66. object IEnumerator.Current
  67. {
  68. get
  69. {
  70. return this.Current;
  71. }
  72. }
  73. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Close"]/*' />
  74. /// <devdoc>
  75. /// <para>Frees the managed resources associated with the enumerator.</para>
  76. /// </devdoc>
  77. public void Close()
  78. {
  79. if (!this.locatorHandle.IsInvalid)
  80. {
  81. this.locatorHandle.Close();
  82. this.currentMessageQueue = null;
  83. }
  84. }
  85. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Dispose"]/*' />
  86. /// <devdoc>
  87. /// </devdoc>
  88. [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed")]
  89. public void Dispose()
  90. {
  91. Dispose(true);
  92. }
  93. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Dispose1"]/*' />
  94. /// <devdoc>
  95. /// <para>
  96. /// </para>
  97. /// </devdoc>
  98. [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "currentMessageQueue")]
  99. protected virtual void Dispose(bool disposing)
  100. {
  101. if (disposing)
  102. {
  103. this.Close();
  104. }
  105. this.disposed = true;
  106. }
  107. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.LocatorHandle"]/*' />
  108. /// <devdoc>
  109. /// <para>Indicates the native Message Queuing handle used to locate queues in a network. This
  110. /// property is read-only.</para>
  111. /// </devdoc>
  112. public IntPtr LocatorHandle
  113. {
  114. get { return this.Handle.DangerousGetHandle(); }
  115. }
  116. LocatorHandle Handle
  117. {
  118. get
  119. {
  120. if (this.locatorHandle.IsInvalid)
  121. {
  122. //Cannot allocate the locatorHandle if the object has been disposed, since finalization has been suppressed.
  123. if (this.disposed)
  124. throw new ObjectDisposedException(GetType().Name);
  125. Columns columns = new Columns(2);
  126. LocatorHandle enumHandle;
  127. columns.AddColumnId(NativeMethods.QUEUE_PROPID_PATHNAME);
  128. //Adding the instance property avoids accessing the DS a second
  129. //time, the formatName can be resolved by calling MQInstanceToFormatName
  130. columns.AddColumnId(NativeMethods.QUEUE_PROPID_INSTANCE);
  131. int status;
  132. if (this.criteria != null)
  133. status = UnsafeNativeMethods.MQLocateBegin(null, this.criteria.Reference, columns.GetColumnsRef(), out enumHandle);
  134. else
  135. status = UnsafeNativeMethods.MQLocateBegin(null, null, columns.GetColumnsRef(), out enumHandle);
  136. if (MessageQueue.IsFatalError(status))
  137. throw new MessageQueueException(status);
  138. this.locatorHandle = enumHandle;
  139. }
  140. return this.locatorHandle;
  141. }
  142. }
  143. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.MoveNext"]/*' />
  144. /// <devdoc>
  145. /// <para>
  146. /// Advances the enumerator to the next queue of the enumeration, if one
  147. /// is currently available.</para>
  148. /// </devdoc>
  149. public bool MoveNext()
  150. {
  151. MQPROPVARIANTS[] array = new MQPROPVARIANTS[2];
  152. int propertyCount;
  153. string currentItem;
  154. byte[] currentGuid = new byte[16];
  155. string machineName = null;
  156. if (this.criteria != null && this.criteria.FilterMachine)
  157. {
  158. if (this.criteria.MachineName.CompareTo(".") == 0)
  159. machineName = MessageQueue.ComputerName + "\\";
  160. else
  161. machineName = this.criteria.MachineName + "\\";
  162. }
  163. do
  164. {
  165. propertyCount = 2;
  166. int status;
  167. status = SafeNativeMethods.MQLocateNext(this.Handle, ref propertyCount, array);
  168. if (MessageQueue.IsFatalError(status))
  169. throw new MessageQueueException(status);
  170. if (propertyCount != 2)
  171. {
  172. this.currentMessageQueue = null;
  173. return false;
  174. }
  175. //Using Unicode API even on Win9x
  176. currentItem = Marshal.PtrToStringUni(array[0].ptr);
  177. Marshal.Copy(array[1].ptr, currentGuid, 0, 16);
  178. //MSMQ allocated this memory, lets free it.
  179. SafeNativeMethods.MQFreeMemory(array[0].ptr);
  180. SafeNativeMethods.MQFreeMemory(array[1].ptr);
  181. }
  182. while (machineName != null && (machineName.Length >= currentItem.Length ||
  183. String.Compare(machineName, 0, currentItem, 0, machineName.Length, true, CultureInfo.InvariantCulture) != 0));
  184. this.currentMessageQueue = new MessageQueue(currentItem, new Guid(currentGuid));
  185. return true;
  186. }
  187. /// <include file='doc\MessageQueueEnumerator.uex' path='docs/doc[@for="MessageQueueEnumerator.Reset"]/*' />
  188. /// <devdoc>
  189. /// <para>Resets the cursor, so it points to the head of the list..</para>
  190. /// </devdoc>
  191. public void Reset()
  192. {
  193. this.Close();
  194. }
  195. }
  196. }