MessageQueue.cs 168 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143
  1. //------------------------------------------------------------------------------
  2. // <copyright file="MessageQueue.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.Collections.Generic;
  10. using System.ComponentModel;
  11. using System.ComponentModel.Design;
  12. using System.Diagnostics;
  13. using System.Diagnostics.CodeAnalysis;
  14. using System.Globalization;
  15. using System.Runtime.InteropServices;
  16. using System.Text;
  17. using System.Threading;
  18. using System.Transactions;
  19. namespace Experimental.System.Messaging
  20. {
  21. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue"]/*' />
  22. /// <devdoc>
  23. /// <para>
  24. /// Provides
  25. /// access to a Message Queuing backend queue resource.
  26. /// </para>
  27. /// </devdoc>
  28. [DefaultEvent("ReceiveCompleted"),
  29. TypeConverterAttribute(typeof(System.Messaging.Design.MessageQueueConverter)),
  30. MessagingDescription(Res.MessageQueueDesc)]
  31. [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
  32. [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
  33. public class MessageQueue : Component, IEnumerable
  34. {
  35. //Public constants
  36. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.InfiniteTimeout"]/*' />
  37. /// <devdoc>
  38. /// <para>
  39. /// Specifies that
  40. /// there is no
  41. /// timeout period for calls to peek or receive messages.
  42. /// </para>
  43. /// </devdoc>
  44. public static readonly TimeSpan InfiniteTimeout = TimeSpan.FromMilliseconds(UInt32.MaxValue);
  45. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.InfiniteQueueSize"]/*' />
  46. /// <devdoc>
  47. /// <para>[To be supplied.]</para>
  48. /// </devdoc>
  49. public static readonly long InfiniteQueueSize = UInt32.MaxValue;
  50. //Internal members
  51. private DefaultPropertiesToSend defaultProperties;
  52. private MessagePropertyFilter receiveFilter;
  53. private QueueAccessMode accessMode;
  54. private int sharedMode;
  55. private string formatName;
  56. private string queuePath;
  57. private string path;
  58. private bool enableCache;
  59. private QueuePropertyVariants properties;
  60. private IMessageFormatter formatter;
  61. // Double-checked locking pattern requires volatile for read/write synchronization
  62. private static volatile string computerName;
  63. internal static readonly Version OSVersion = Environment.OSVersion.Version;
  64. internal static readonly Version WinXP = new Version(5, 1);
  65. internal static readonly bool Msmq3OrNewer = OSVersion >= WinXP;
  66. //Cached properties
  67. private QueuePropertyFilter filter;
  68. private bool authenticate;
  69. private short basePriority;
  70. private DateTime createTime;
  71. private int encryptionLevel;
  72. private Guid id;
  73. private string label;
  74. private string multicastAddress;
  75. private DateTime lastModifyTime;
  76. private long journalSize;
  77. private long queueSize;
  78. private Guid queueType;
  79. private bool useJournaling;
  80. private MQCacheableInfo mqInfo;
  81. // Double-checked locking pattern requires volatile for read/write synchronization
  82. //Async IO support
  83. private volatile bool attached;
  84. private bool useThreadPool;
  85. private AsyncCallback onRequestCompleted;
  86. private PeekCompletedEventHandler onPeekCompleted;
  87. private ReceiveCompletedEventHandler onReceiveCompleted;
  88. private ISynchronizeInvoke synchronizingObject;
  89. // Double-checked locking pattern requires volatile for read/write synchronization
  90. private volatile Hashtable outstandingAsyncRequests;
  91. //Path sufixes
  92. private static readonly string SUFIX_PRIVATE = "\\PRIVATE$";
  93. private static readonly string SUFIX_JOURNAL = "\\JOURNAL$";
  94. private static readonly string SUFIX_DEADLETTER = "\\DEADLETTER$";
  95. private static readonly string SUFIX_DEADXACT = "\\XACTDEADLETTER$";
  96. //Path prefixes
  97. private static readonly string PREFIX_LABEL = "LABEL:";
  98. private static readonly string PREFIX_FORMAT_NAME = "FORMATNAME:";
  99. //Connection pooling support
  100. private static CacheTable<string, string> formatNameCache =
  101. new CacheTable<string, string>("formatNameCache", 4, new TimeSpan(0, 0, 100)); // path -> formatname
  102. private static CacheTable<QueueInfoKeyHolder, MQCacheableInfo> queueInfoCache =
  103. new CacheTable<QueueInfoKeyHolder, MQCacheableInfo>("queue info", 4, new TimeSpan(0, 0, 100)); // <formatname, accessMode> -> <readHandle. writeHandle, isTrans>
  104. // Whidbey Beta 2 SECREVIEW (Dec 2004 Microsoft):
  105. // Connection Cache can be a security vulnerability (see bug 422227)
  106. // Therefore, disable it by default
  107. private static bool enableConnectionCache = false;
  108. // Double-checked locking pattern requires volatile for read/write synchronization
  109. private volatile QueueInfoKeyHolder queueInfoKey = null;
  110. private object syncRoot = new object();
  111. private static object staticSyncRoot = new object();
  112. /*
  113. static MessageQueue()
  114. {
  115. try
  116. {
  117. using (TelemetryEventSource eventSource = new TelemetryEventSource())
  118. {
  119. eventSource.MessageQueue();
  120. }
  121. }
  122. catch
  123. {
  124. }
  125. }
  126. */
  127. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue"]/*' />
  128. /// <devdoc>
  129. /// <para>
  130. /// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/> class. To use the object instantiated by the default
  131. /// constructor, the <see cref='System.Messaging.MessageQueue.Path'/>
  132. /// property must be set.
  133. /// </para>
  134. /// </devdoc>
  135. //
  136. public MessageQueue()
  137. {
  138. this.path = String.Empty;
  139. this.accessMode = QueueAccessMode.SendAndReceive;
  140. }
  141. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue1"]/*' />
  142. /// <devdoc>
  143. /// <para>
  144. /// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/>
  145. /// class that references the Message Queuing application resource specified by the
  146. /// <paramref name="path"/>
  147. /// parameter.
  148. /// </para>
  149. /// </devdoc>
  150. public MessageQueue(string path)
  151. : this(path, false, enableConnectionCache)
  152. {
  153. }
  154. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue5"]/*' />
  155. /// <devdoc>
  156. /// <para>
  157. /// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/>
  158. /// class that references the Message Queuing application resource specified by the
  159. /// <paramref name="path"/> parameter and having the specifed access mode.
  160. /// </para>
  161. /// </devdoc>
  162. public MessageQueue(string path, QueueAccessMode accessMode)
  163. : this(path, false, enableConnectionCache, accessMode)
  164. {
  165. }
  166. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue2"]/*' />
  167. /// <devdoc>
  168. /// <para>
  169. /// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/> class that references the
  170. /// Message Queuing application resource specified by the <paramref name="path"/> parameter,
  171. /// and has the specified queue read access restriction.
  172. /// </para>
  173. /// </devdoc>
  174. public MessageQueue(string path, bool sharedModeDenyReceive)
  175. : this(path, sharedModeDenyReceive, enableConnectionCache)
  176. {
  177. }
  178. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue3"]/*' />
  179. /// <devdoc>
  180. /// <para>
  181. /// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/> class that references the
  182. /// Message Queuing application resource specified by the <paramref name="path"/> parameter,
  183. /// has the specified queue read access restriction and whether to cache handles
  184. /// </para>
  185. /// </devdoc>
  186. public MessageQueue(string path, bool sharedModeDenyReceive, bool enableCache)
  187. {
  188. this.path = path;
  189. this.enableCache = enableCache;
  190. if (sharedModeDenyReceive)
  191. {
  192. this.sharedMode = NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE;
  193. }
  194. this.accessMode = QueueAccessMode.SendAndReceive;
  195. }
  196. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue4"]/*' />
  197. /// <devdoc>
  198. /// <para>
  199. /// Initializes a new instance of the <see cref='System.Messaging.MessageQueue'/> class that references the
  200. /// Message Queuing application resource specified by the <paramref name="path"/> parameter,
  201. /// has the specified queue read access restriction, whether to cache handles,
  202. /// and specified access mode.
  203. /// </para>
  204. /// </devdoc>
  205. public MessageQueue(string path, bool sharedModeDenyReceive,
  206. bool enableCache, QueueAccessMode accessMode)
  207. {
  208. this.path = path;
  209. this.enableCache = enableCache;
  210. if (sharedModeDenyReceive)
  211. {
  212. this.sharedMode = NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE;
  213. }
  214. SetAccessMode(accessMode);
  215. }
  216. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageQueue3"]/*' />
  217. /// <internalonly/>
  218. internal MessageQueue(string path, Guid id)
  219. {
  220. PropertyFilter.Id = true;
  221. this.id = id;
  222. this.path = path;
  223. this.accessMode = QueueAccessMode.SendAndReceive;
  224. }
  225. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AccessMode"]/*' />
  226. /// <devdoc>
  227. /// <para>
  228. /// Gets value specifying access mode of the queue
  229. /// </para>
  230. /// </devdoc>
  231. public QueueAccessMode AccessMode
  232. {
  233. get
  234. {
  235. return this.accessMode;
  236. }
  237. }
  238. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Authenticate"]/*' />
  239. /// <devdoc>
  240. /// <para>
  241. /// Gets or sets a value specifying whether the queue only accepts authenticated
  242. /// messages.
  243. /// </para>
  244. /// </devdoc>
  245. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_Authenticate)]
  246. public bool Authenticate
  247. {
  248. get
  249. {
  250. if (!PropertyFilter.Authenticate)
  251. {
  252. Properties.SetUI1(NativeMethods.QUEUE_PROPID_AUTHENTICATE, (byte)0);
  253. GenerateQueueProperties();
  254. this.authenticate = (Properties.GetUI1(NativeMethods.QUEUE_PROPID_AUTHENTICATE) != NativeMethods.QUEUE_AUTHENTICATE_NONE);
  255. PropertyFilter.Authenticate = true;
  256. Properties.Remove(NativeMethods.QUEUE_PROPID_AUTHENTICATE);
  257. }
  258. return this.authenticate;
  259. }
  260. set
  261. {
  262. if (value)
  263. Properties.SetUI1(NativeMethods.QUEUE_PROPID_AUTHENTICATE, (byte)NativeMethods.QUEUE_AUTHENTICATE_AUTHENTICATE);
  264. else
  265. Properties.SetUI1(NativeMethods.QUEUE_PROPID_AUTHENTICATE, (byte)NativeMethods.QUEUE_AUTHENTICATE_NONE);
  266. SaveQueueProperties();
  267. this.authenticate = value;
  268. PropertyFilter.Authenticate = true;
  269. Properties.Remove(NativeMethods.QUEUE_PROPID_AUTHENTICATE);
  270. }
  271. }
  272. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BasePriority"]/*' />
  273. /// <devdoc>
  274. /// <para>Gets or sets a value indicating the base
  275. /// priority used to route a public queue's messages over the network.</para>
  276. /// </devdoc>
  277. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_BasePriority)]
  278. public short BasePriority
  279. {
  280. get
  281. {
  282. if (!PropertyFilter.BasePriority)
  283. {
  284. Properties.SetI2(NativeMethods.QUEUE_PROPID_BASEPRIORITY, (short)0);
  285. GenerateQueueProperties();
  286. this.basePriority = properties.GetI2(NativeMethods.QUEUE_PROPID_BASEPRIORITY);
  287. PropertyFilter.BasePriority = true;
  288. Properties.Remove(NativeMethods.QUEUE_PROPID_BASEPRIORITY);
  289. }
  290. return this.basePriority;
  291. }
  292. set
  293. {
  294. Properties.SetI2(NativeMethods.QUEUE_PROPID_BASEPRIORITY, value);
  295. SaveQueueProperties();
  296. this.basePriority = value;
  297. PropertyFilter.BasePriority = true;
  298. Properties.Remove(NativeMethods.QUEUE_PROPID_BASEPRIORITY);
  299. }
  300. }
  301. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CanRead"]/*' />
  302. /// <devdoc>
  303. /// <para>
  304. /// Gets a value indicating whether the <see cref='System.Messaging.MessageQueue'/>
  305. /// has read permission.
  306. /// </para>
  307. /// </devdoc>
  308. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_CanRead)]
  309. public bool CanRead
  310. {
  311. get
  312. {
  313. return MQInfo.CanRead;
  314. }
  315. }
  316. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CanWrite"]/*' />
  317. /// <devdoc>
  318. /// <para>
  319. /// Gets a value indicating whether the <see cref='System.Messaging.MessageQueue'/>
  320. /// has write permission.
  321. /// </para>
  322. /// </devdoc>
  323. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_CanWrite)]
  324. public bool CanWrite
  325. {
  326. get
  327. {
  328. return MQInfo.CanWrite;
  329. }
  330. }
  331. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Category"]/*' />
  332. /// <devdoc>
  333. /// <para>Gets or sets the queue type.</para>
  334. /// </devdoc>
  335. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_Category)]
  336. public Guid Category
  337. {
  338. get
  339. {
  340. if (!PropertyFilter.Category)
  341. {
  342. Properties.SetNull(NativeMethods.QUEUE_PROPID_TYPE);
  343. GenerateQueueProperties();
  344. byte[] bytes = new byte[16];
  345. IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_TYPE);
  346. if (handle != IntPtr.Zero)
  347. {
  348. Marshal.Copy(handle, bytes, 0, 16);
  349. //MSMQ allocated memory for this operation, needs to be freed
  350. SafeNativeMethods.MQFreeMemory(handle);
  351. }
  352. this.queueType = new Guid(bytes);
  353. PropertyFilter.Category = true;
  354. Properties.Remove(NativeMethods.QUEUE_PROPID_TYPE);
  355. }
  356. return this.queueType;
  357. }
  358. set
  359. {
  360. Properties.SetGuid(NativeMethods.QUEUE_PROPID_TYPE, value.ToByteArray());
  361. SaveQueueProperties();
  362. this.queueType = value;
  363. PropertyFilter.Category = true;
  364. Properties.Remove(NativeMethods.QUEUE_PROPID_TYPE);
  365. }
  366. }
  367. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ComputerName"]/*' />
  368. /// <internalonly/>
  369. internal static string ComputerName
  370. {
  371. get
  372. {
  373. if (computerName == null)
  374. {
  375. lock (MessageQueue.staticSyncRoot)
  376. {
  377. if (computerName == null)
  378. {
  379. StringBuilder sb = new StringBuilder(256);
  380. SafeNativeMethods.GetComputerName(sb, new int[] { sb.Capacity });
  381. computerName = sb.ToString();
  382. }
  383. }
  384. }
  385. return computerName;
  386. }
  387. }
  388. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CreateTime"]/*' />
  389. /// <devdoc>
  390. /// <para>
  391. /// Gets the time and date of the queue's creation.
  392. /// </para>
  393. /// </devdoc>
  394. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_CreateTime)]
  395. public DateTime CreateTime
  396. {
  397. get
  398. {
  399. if (!PropertyFilter.CreateTime)
  400. {
  401. DateTime time = new DateTime(1970, 1, 1);
  402. Properties.SetI4(NativeMethods.QUEUE_PROPID_CREATE_TIME, 0);
  403. GenerateQueueProperties();
  404. this.createTime = time.AddSeconds(properties.GetI4(NativeMethods.QUEUE_PROPID_CREATE_TIME)).ToLocalTime();
  405. PropertyFilter.CreateTime = true;
  406. Properties.Remove(NativeMethods.QUEUE_PROPID_CREATE_TIME);
  407. }
  408. return this.createTime;
  409. }
  410. }
  411. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.DefaultPropertiesToSend"]/*' />
  412. /// <devdoc>
  413. /// <para>
  414. /// Gets or sets the properties to be used by
  415. /// default when sending messages to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
  416. /// .
  417. /// </para>
  418. /// </devdoc>
  419. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MessagingDescription(Res.MQ_DefaultPropertiesToSend)]
  420. public DefaultPropertiesToSend DefaultPropertiesToSend
  421. {
  422. get
  423. {
  424. if (this.defaultProperties == null)
  425. {
  426. if (this.DesignMode)
  427. this.defaultProperties = new DefaultPropertiesToSend(true);
  428. else
  429. this.defaultProperties = new DefaultPropertiesToSend();
  430. }
  431. return this.defaultProperties;
  432. }
  433. set
  434. {
  435. this.defaultProperties = value;
  436. }
  437. }
  438. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.DenySharedReceive"]/*' />
  439. /// <devdoc>
  440. /// <para>
  441. /// Specifies the shared mode for the queue that this object
  442. /// references. If <see langword='true'/> ,
  443. /// no other queue object will be able to receive messages from the queue resource.
  444. /// </para>
  445. /// </devdoc>
  446. [Browsable(false), DefaultValueAttribute(false), MessagingDescription(Res.MQ_DenySharedReceive)]
  447. public bool DenySharedReceive
  448. {
  449. get
  450. {
  451. return (this.sharedMode == NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE);
  452. }
  453. set
  454. {
  455. if (value && (this.sharedMode != NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE))
  456. {
  457. this.Close();
  458. this.sharedMode = NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE;
  459. }
  460. else if (!value && (this.sharedMode == NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE))
  461. {
  462. this.Close();
  463. this.sharedMode = NativeMethods.QUEUE_SHARED_MODE_DENY_NONE;
  464. }
  465. }
  466. }
  467. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.EnableConnectionCache"]/*' />
  468. /// <devdoc>
  469. /// <para>[To be supplied.]</para>
  470. /// </devdoc>
  471. [Browsable(false)]
  472. public static bool EnableConnectionCache
  473. {
  474. get
  475. {
  476. return enableConnectionCache;
  477. }
  478. set
  479. {
  480. enableConnectionCache = value;
  481. }
  482. }
  483. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.EncryptionRequired"]/*' />
  484. /// <devdoc>
  485. /// <para>
  486. /// Gets or sets a value indicating whether the queue only accepts non-private
  487. /// (non-encrypted) messages.
  488. /// </para>
  489. /// </devdoc>
  490. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_EncryptionRequired)]
  491. public EncryptionRequired EncryptionRequired
  492. {
  493. get
  494. {
  495. if (!PropertyFilter.EncryptionLevel)
  496. {
  497. Properties.SetUI4(NativeMethods.QUEUE_PROPID_PRIV_LEVEL, 0);
  498. GenerateQueueProperties();
  499. this.encryptionLevel = Properties.GetUI4(NativeMethods.QUEUE_PROPID_PRIV_LEVEL);
  500. PropertyFilter.EncryptionLevel = true;
  501. Properties.Remove(NativeMethods.QUEUE_PROPID_PRIV_LEVEL);
  502. }
  503. return (EncryptionRequired)this.encryptionLevel;
  504. }
  505. set
  506. {
  507. if (!ValidationUtility.ValidateEncryptionRequired(value))
  508. throw new InvalidEnumArgumentException("value", (int)value, typeof(EncryptionRequired));
  509. Properties.SetUI4(NativeMethods.QUEUE_PROPID_PRIV_LEVEL, (int)value);
  510. SaveQueueProperties();
  511. this.encryptionLevel = properties.GetUI4(NativeMethods.QUEUE_PROPID_PRIV_LEVEL);
  512. PropertyFilter.EncryptionLevel = true;
  513. Properties.Remove(NativeMethods.QUEUE_PROPID_PRIV_LEVEL);
  514. }
  515. }
  516. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.FormatName"]/*' />
  517. /// <devdoc>
  518. /// <para>
  519. /// Gets the unique name that was generated for the queue when the queue was created.
  520. /// </para>
  521. /// </devdoc>
  522. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_FormatName)]
  523. public string FormatName
  524. {
  525. get
  526. {
  527. if (this.formatName == null)
  528. {
  529. if (this.path == null || path.Length == 0)
  530. {
  531. return string.Empty;
  532. }
  533. string pathUpper = this.path.ToUpper(CultureInfo.InvariantCulture);
  534. // see if we already have this cached
  535. if (enableCache)
  536. this.formatName = MessageQueue.formatNameCache.Get(pathUpper);
  537. // not in the cache? keep working.
  538. if (formatName == null)
  539. {
  540. if (PropertyFilter.Id)
  541. {
  542. //Improves performance when enumerating queues.
  543. //This codepath will only be executed when accessing
  544. //a queue returned by MessageQueueEnumerator.
  545. int result;
  546. int status = 0;
  547. StringBuilder newFormatName = new StringBuilder(NativeMethods.MAX_LABEL_LEN);
  548. result = NativeMethods.MAX_LABEL_LEN;
  549. status = SafeNativeMethods.MQInstanceToFormatName(this.id.ToByteArray(), newFormatName, ref result);
  550. if (status != 0)
  551. throw new MessageQueueException(status);
  552. this.formatName = newFormatName.ToString();
  553. return this.formatName;
  554. }
  555. if (pathUpper.StartsWith(PREFIX_FORMAT_NAME))
  556. {
  557. this.formatName = this.path.Substring(PREFIX_FORMAT_NAME.Length);
  558. }
  559. else if (pathUpper.StartsWith(PREFIX_LABEL))
  560. {
  561. MessageQueue labeledQueue = ResolveQueueFromLabel(this.path, true);
  562. this.formatName = labeledQueue.FormatName;
  563. this.queuePath = labeledQueue.QueuePath;
  564. }
  565. else
  566. {
  567. this.queuePath = this.path;
  568. this.formatName = ResolveFormatNameFromQueuePath(this.queuePath, true);
  569. }
  570. MessageQueue.formatNameCache.Put(pathUpper, formatName);
  571. }
  572. }
  573. return this.formatName;
  574. }
  575. }
  576. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Formatter"]/*' />
  577. /// <devdoc>
  578. /// <para>
  579. /// Gets or
  580. /// sets a
  581. /// formatter class used to serialize messages read or written to
  582. /// the message body.
  583. /// </para>
  584. /// </devdoc>
  585. [DefaultValueAttribute(null),
  586. TypeConverterAttribute(typeof(System.Messaging.Design.MessageFormatterConverter)),
  587. Browsable(false),
  588. MessagingDescription(Res.MQ_Formatter)]
  589. public IMessageFormatter Formatter
  590. {
  591. get
  592. {
  593. if (this.formatter == null && !DesignMode)
  594. this.formatter = new XmlMessageFormatter();
  595. return this.formatter;
  596. }
  597. set
  598. {
  599. this.formatter = value;
  600. }
  601. }
  602. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Id"]/*' />
  603. /// <devdoc>
  604. /// <para>
  605. /// Gets the Message Queuing unique identifier for the queue.
  606. /// </para>
  607. /// </devdoc>
  608. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_GuidId)]
  609. public Guid Id
  610. {
  611. get
  612. {
  613. if (!PropertyFilter.Id)
  614. {
  615. Properties.SetNull(NativeMethods.QUEUE_PROPID_INSTANCE);
  616. GenerateQueueProperties();
  617. byte[] bytes = new byte[16];
  618. IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_INSTANCE);
  619. if (handle != IntPtr.Zero)
  620. {
  621. Marshal.Copy(handle, bytes, 0, 16);
  622. //MSMQ allocated memory for this operation, needs to be freed
  623. SafeNativeMethods.MQFreeMemory(handle);
  624. }
  625. this.id = new Guid(bytes);
  626. PropertyFilter.Id = true;
  627. Properties.Remove(NativeMethods.QUEUE_PROPID_INSTANCE);
  628. }
  629. return this.id;
  630. }
  631. }
  632. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Label"]/*' />
  633. /// <devdoc>
  634. /// <para>Gets or sets the queue description.</para>
  635. /// </devdoc>
  636. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_Label)]
  637. public string Label
  638. {
  639. get
  640. {
  641. if (!PropertyFilter.Label)
  642. {
  643. Properties.SetNull(NativeMethods.QUEUE_PROPID_LABEL);
  644. GenerateQueueProperties();
  645. string description = null;
  646. IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_LABEL);
  647. if (handle != IntPtr.Zero)
  648. {
  649. //Using Unicode API even on Win9x
  650. description = Marshal.PtrToStringUni(handle);
  651. //MSMQ allocated memory for this operation, needs to be freed
  652. SafeNativeMethods.MQFreeMemory(handle);
  653. }
  654. this.label = description;
  655. PropertyFilter.Label = true;
  656. Properties.Remove(NativeMethods.QUEUE_PROPID_LABEL);
  657. }
  658. return this.label;
  659. }
  660. set
  661. {
  662. if (value == null)
  663. throw new ArgumentNullException("value");
  664. //Borrow this function from message
  665. Properties.SetString(NativeMethods.QUEUE_PROPID_LABEL, Message.StringToBytes(value));
  666. SaveQueueProperties();
  667. this.label = value;
  668. PropertyFilter.Label = true;
  669. Properties.Remove(NativeMethods.QUEUE_PROPID_LABEL);
  670. }
  671. }
  672. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.LastModifyTime"]/*' />
  673. /// <devdoc>
  674. /// <para>
  675. /// Indicates the last time the properties of a queue were modified.
  676. /// </para>
  677. /// </devdoc>
  678. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_LastModifyTime)]
  679. public DateTime LastModifyTime
  680. {
  681. get
  682. {
  683. if (!PropertyFilter.LastModifyTime)
  684. {
  685. DateTime time = new DateTime(1970, 1, 1);
  686. Properties.SetI4(NativeMethods.QUEUE_PROPID_MODIFY_TIME, 0);
  687. GenerateQueueProperties();
  688. this.lastModifyTime = time.AddSeconds(properties.GetI4(NativeMethods.QUEUE_PROPID_MODIFY_TIME)).ToLocalTime();
  689. PropertyFilter.LastModifyTime = true;
  690. Properties.Remove(NativeMethods.QUEUE_PROPID_MODIFY_TIME);
  691. }
  692. return this.lastModifyTime;
  693. }
  694. }
  695. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MachineName"]/*' />
  696. /// <devdoc>
  697. /// <para>
  698. /// Gets or sets the name of the computer where
  699. /// the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
  700. /// is located.
  701. /// </para>
  702. /// </devdoc>
  703. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_MachineName)]
  704. public string MachineName
  705. {
  706. get
  707. {
  708. string queuePath = QueuePath;
  709. if (queuePath.Length == 0)
  710. {
  711. return queuePath;
  712. }
  713. return queuePath.Substring(0, queuePath.IndexOf('\\'));
  714. }
  715. set
  716. {
  717. if (value == null)
  718. throw new ArgumentNullException("value");
  719. if (!SyntaxCheck.CheckMachineName(value))
  720. throw new ArgumentException(Res.GetString(Res.InvalidProperty, "MachineName", value));
  721. StringBuilder newPath = new StringBuilder();
  722. if ((this.path == null || this.path.Length == 0) && this.formatName == null)
  723. {
  724. //Need to default to an existing queue, for instance Journal.
  725. newPath.Append(value);
  726. newPath.Append(SUFIX_JOURNAL);
  727. }
  728. else
  729. {
  730. newPath.Append(value);
  731. newPath.Append("\\");
  732. newPath.Append(QueueName);
  733. }
  734. Path = newPath.ToString();
  735. }
  736. }
  737. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MaximumJournalSize"]/*' />
  738. /// <devdoc>
  739. /// <para>
  740. /// Gets or sets the maximum size of the journal queue.
  741. /// </para>
  742. /// </devdoc>
  743. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  744. MessagingDescription(Res.MQ_MaximumJournalSize),
  745. TypeConverterAttribute(typeof(System.Messaging.Design.SizeConverter))]
  746. public long MaximumJournalSize
  747. {
  748. get
  749. {
  750. if (!PropertyFilter.MaximumJournalSize)
  751. {
  752. Properties.SetUI4(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA, 0);
  753. GenerateQueueProperties();
  754. this.journalSize = (long)((uint)properties.GetUI4(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA));
  755. PropertyFilter.MaximumJournalSize = true;
  756. Properties.Remove(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA);
  757. }
  758. return this.journalSize;
  759. }
  760. set
  761. {
  762. if (value > InfiniteQueueSize || value < 0)
  763. throw new ArgumentException(Res.GetString(Res.InvalidProperty, "MaximumJournalSize", value));
  764. Properties.SetUI4(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA, (int)((uint)value));
  765. SaveQueueProperties();
  766. this.journalSize = value;
  767. PropertyFilter.MaximumJournalSize = true;
  768. Properties.Remove(NativeMethods.QUEUE_PROPID_JOURNAL_QUOTA);
  769. }
  770. }
  771. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MaximumQueueSize"]/*' />
  772. /// <devdoc>
  773. /// <para>
  774. /// Gets or sets the maximum size of the queue.
  775. /// </para>
  776. /// </devdoc>
  777. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  778. MessagingDescription(Res.MQ_MaximumQueueSize),
  779. TypeConverterAttribute(typeof(System.Messaging.Design.SizeConverter))]
  780. public long MaximumQueueSize
  781. {
  782. get
  783. {
  784. if (!PropertyFilter.MaximumQueueSize)
  785. {
  786. Properties.SetUI4(NativeMethods.QUEUE_PROPID_QUOTA, 0);
  787. GenerateQueueProperties();
  788. this.queueSize = (long)((uint)properties.GetUI4(NativeMethods.QUEUE_PROPID_QUOTA));
  789. PropertyFilter.MaximumQueueSize = true;
  790. Properties.Remove(NativeMethods.QUEUE_PROPID_QUOTA);
  791. }
  792. return this.queueSize;
  793. }
  794. set
  795. {
  796. if (value > InfiniteQueueSize || value < 0)
  797. throw new ArgumentException(Res.GetString(Res.InvalidProperty, "MaximumQueueSize", value));
  798. Properties.SetUI4(NativeMethods.QUEUE_PROPID_QUOTA, (int)((uint)value));
  799. SaveQueueProperties();
  800. this.queueSize = value;
  801. PropertyFilter.MaximumQueueSize = true;
  802. Properties.Remove(NativeMethods.QUEUE_PROPID_QUOTA);
  803. }
  804. }
  805. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MessageReadPropertyFilter"]/*' />
  806. /// <devdoc>
  807. /// <para>
  808. /// Gets or sets the property filter for
  809. /// receiving messages.
  810. /// </para>
  811. /// </devdoc>
  812. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MessagingDescription(Res.MQ_MessageReadPropertyFilter)]
  813. public MessagePropertyFilter MessageReadPropertyFilter
  814. {
  815. get
  816. {
  817. if (this.receiveFilter == null)
  818. {
  819. this.receiveFilter = new MessagePropertyFilter();
  820. this.receiveFilter.SetDefaults();
  821. }
  822. return this.receiveFilter;
  823. }
  824. set
  825. {
  826. if (value == null)
  827. throw new ArgumentNullException("value");
  828. this.receiveFilter = value;
  829. }
  830. }
  831. internal MQCacheableInfo MQInfo
  832. {
  833. get
  834. {
  835. if (mqInfo == null)
  836. {
  837. MQCacheableInfo cachedInfo = queueInfoCache.Get(QueueInfoKey);
  838. if (sharedMode == NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE || !enableCache)
  839. {
  840. if (cachedInfo != null)
  841. cachedInfo.CloseIfNotReferenced();
  842. // don't use the cache
  843. mqInfo = new MQCacheableInfo(this.FormatName, accessMode, sharedMode);
  844. mqInfo.AddRef();
  845. }
  846. else
  847. {
  848. // use the cache
  849. if (cachedInfo != null)
  850. {
  851. cachedInfo.AddRef();
  852. mqInfo = cachedInfo;
  853. }
  854. else
  855. {
  856. mqInfo = new MQCacheableInfo(this.FormatName, accessMode, sharedMode);
  857. mqInfo.AddRef();
  858. queueInfoCache.Put(QueueInfoKey, mqInfo);
  859. }
  860. }
  861. }
  862. return mqInfo;
  863. }
  864. }
  865. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.MulticastAddress"]/*' />
  866. /// <devdoc>
  867. /// <para>Gets or sets the IP multicast address associated with the queue.</para>
  868. /// </devdoc>
  869. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
  870. DefaultValue(""),
  871. MessagingDescription(Res.MQ_MulticastAddress)]
  872. public string MulticastAddress
  873. {
  874. get
  875. {
  876. if (!Msmq3OrNewer)
  877. { //this feature is unavailable on win2k
  878. // don't throw in design mode: this makes component unusable
  879. if (DesignMode)
  880. return String.Empty;
  881. else
  882. throw new PlatformNotSupportedException(Res.GetString(Res.PlatformNotSupported));
  883. }
  884. if (!PropertyFilter.MulticastAddress)
  885. {
  886. Properties.SetNull(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
  887. GenerateQueueProperties();
  888. string address = null;
  889. IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
  890. if (handle != IntPtr.Zero)
  891. {
  892. address = Marshal.PtrToStringUni(handle);
  893. //MSMQ allocated memory for this operation, needs to be freed
  894. SafeNativeMethods.MQFreeMemory(handle);
  895. }
  896. this.multicastAddress = address;
  897. PropertyFilter.MulticastAddress = true;
  898. Properties.Remove(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
  899. }
  900. return this.multicastAddress;
  901. }
  902. set
  903. {
  904. if (value == null)
  905. throw new ArgumentNullException("value");
  906. if (!Msmq3OrNewer) //this feature is unavailable on win2k
  907. throw new PlatformNotSupportedException(Res.GetString(Res.PlatformNotSupported));
  908. if (value.Length == 0) // used to disassocciate queue from a muliticast address
  909. Properties.SetEmpty(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
  910. else //Borrow this function from message
  911. Properties.SetString(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS, Message.StringToBytes(value));
  912. SaveQueueProperties();
  913. this.multicastAddress = value;
  914. PropertyFilter.MulticastAddress = true;
  915. Properties.Remove(NativeMethods.QUEUE_PROPID_MULTICAST_ADDRESS);
  916. }
  917. }
  918. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Path"]/*' />
  919. /// <devdoc>
  920. /// <para>
  921. /// Gets or sets the queue's path. When setting the <see cref='System.Messaging.MessageQueue.Path'/>, this points the <see cref='System.Messaging.MessageQueue'/>
  922. /// to a new queue.
  923. /// </para>
  924. /// </devdoc>
  925. [SettingsBindable(true),
  926. RefreshProperties(RefreshProperties.All),
  927. Browsable(false),
  928. DefaultValue(""),
  929. TypeConverter("System.Diagnostics.Design.StringValueConverter, " + AssemblyRef.SystemDesign),
  930. MessagingDescription(Res.MQ_Path)]
  931. public string Path
  932. {
  933. get
  934. {
  935. return this.path;
  936. }
  937. set
  938. {
  939. if (value == null)
  940. value = String.Empty;
  941. if (!ValidatePath(value, false))
  942. throw new ArgumentException(Res.GetString(Res.PathSyntax));
  943. if (!String.IsNullOrEmpty(this.path))
  944. this.Close();
  945. this.path = value;
  946. }
  947. }
  948. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Properties"]/*' />
  949. /// <internalonly/>
  950. private QueuePropertyVariants Properties
  951. {
  952. get
  953. {
  954. if (this.properties == null)
  955. this.properties = new QueuePropertyVariants();
  956. return this.properties;
  957. }
  958. }
  959. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PropertyFilter"]/*' />
  960. /// <internalonly/>
  961. private QueuePropertyFilter PropertyFilter
  962. {
  963. get
  964. {
  965. if (this.filter == null)
  966. this.filter = new QueuePropertyFilter();
  967. return this.filter;
  968. }
  969. }
  970. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.QueueName"]/*' />
  971. /// <devdoc>
  972. /// <para>
  973. /// Gets or sets the friendly
  974. /// name that identifies the queue.
  975. /// </para>
  976. /// </devdoc>
  977. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_QueueName)]
  978. public string QueueName
  979. {
  980. get
  981. {
  982. string queuePath = QueuePath;
  983. if (queuePath.Length == 0)
  984. {
  985. return queuePath;
  986. }
  987. return queuePath.Substring(queuePath.IndexOf('\\') + 1);
  988. }
  989. set
  990. {
  991. if (value == null)
  992. throw new ArgumentNullException("value");
  993. StringBuilder newPath = new StringBuilder();
  994. if ((this.path == null || this.path.Length == 0) && this.formatName == null)
  995. {
  996. newPath.Append(".\\");
  997. newPath.Append(value);
  998. }
  999. else
  1000. {
  1001. newPath.Append(MachineName);
  1002. newPath.Append("\\");
  1003. newPath.Append(value);
  1004. }
  1005. Path = newPath.ToString();
  1006. }
  1007. }
  1008. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.QueuePath"]/*' />
  1009. /// <internalonly/>
  1010. internal string QueuePath
  1011. {
  1012. get
  1013. {
  1014. if (this.queuePath == null)
  1015. {
  1016. if (this.path == null || this.path.Length == 0)
  1017. {
  1018. return string.Empty;
  1019. }
  1020. string pathUpper = this.path.ToUpper(CultureInfo.InvariantCulture);
  1021. if (pathUpper.StartsWith(PREFIX_LABEL))
  1022. {
  1023. MessageQueue labeledQueue = ResolveQueueFromLabel(this.path, true);
  1024. this.formatName = labeledQueue.FormatName;
  1025. this.queuePath = labeledQueue.QueuePath;
  1026. }
  1027. else if (pathUpper.StartsWith(PREFIX_FORMAT_NAME))
  1028. {
  1029. Properties.SetNull(NativeMethods.QUEUE_PROPID_PATHNAME);
  1030. GenerateQueueProperties();
  1031. string description = null;
  1032. IntPtr handle = Properties.GetIntPtr(NativeMethods.QUEUE_PROPID_PATHNAME);
  1033. if (handle != IntPtr.Zero)
  1034. {
  1035. //Using Unicode API even on Win9x
  1036. description = Marshal.PtrToStringUni(handle);
  1037. //MSMQ allocated memory for this operation, needs to be freed
  1038. SafeNativeMethods.MQFreeMemory(handle);
  1039. }
  1040. Properties.Remove(NativeMethods.QUEUE_PROPID_PATHNAME);
  1041. this.queuePath = description;
  1042. }
  1043. else
  1044. this.queuePath = path;
  1045. }
  1046. return this.queuePath;
  1047. }
  1048. }
  1049. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReadHandle"]/*' />
  1050. /// <devdoc>
  1051. /// <para>
  1052. /// The native handle used to receive messages from the message queue
  1053. /// </para>
  1054. /// </devdoc>
  1055. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_ReadHandle)]
  1056. public IntPtr ReadHandle
  1057. {
  1058. get
  1059. {
  1060. return MQInfo.ReadHandle.DangerousGetHandle();
  1061. }
  1062. }
  1063. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SynchronizingObject"]/*' />
  1064. /// <devdoc>
  1065. /// Represents the object used to marshal the event handler
  1066. /// calls issued as a result of a BeginReceive or BeginPeek
  1067. /// request into a specific thread. Normally this property will
  1068. /// be set when the component is placed inside a control or
  1069. /// a from, since those components are bound to a specific
  1070. /// thread.
  1071. /// </devdoc>
  1072. [Browsable(false), DefaultValue(null), MessagingDescription(Res.MQ_SynchronizingObject)]
  1073. public ISynchronizeInvoke SynchronizingObject
  1074. {
  1075. get
  1076. {
  1077. if (this.synchronizingObject == null && DesignMode)
  1078. {
  1079. IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
  1080. if (host != null)
  1081. {
  1082. object baseComponent = host.RootComponent;
  1083. if (baseComponent != null && baseComponent is ISynchronizeInvoke)
  1084. this.synchronizingObject = (ISynchronizeInvoke)baseComponent;
  1085. }
  1086. }
  1087. return this.synchronizingObject;
  1088. }
  1089. set
  1090. {
  1091. this.synchronizingObject = value;
  1092. }
  1093. }
  1094. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Transactional"]/*' />
  1095. /// <devdoc>
  1096. /// <para>
  1097. /// Gets
  1098. /// a value indicating whether the queue supports transactions.
  1099. /// </para>
  1100. /// </devdoc>
  1101. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_Transactional)]
  1102. public bool Transactional
  1103. {
  1104. get
  1105. {
  1106. return MQInfo.Transactional;
  1107. }
  1108. }
  1109. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.UseJournalQueue"]/*' />
  1110. /// <devdoc>
  1111. /// <para>
  1112. /// Gets or sets a value indicating whether retrieved messages are copied to the
  1113. /// journal queue.
  1114. /// </para>
  1115. /// </devdoc>
  1116. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_UseJournalQueue)]
  1117. public bool UseJournalQueue
  1118. {
  1119. get
  1120. {
  1121. if (!PropertyFilter.UseJournalQueue)
  1122. {
  1123. Properties.SetUI1(NativeMethods.QUEUE_PROPID_JOURNAL, (byte)0);
  1124. GenerateQueueProperties();
  1125. this.useJournaling = (Properties.GetUI1(NativeMethods.QUEUE_PROPID_JOURNAL) != NativeMethods.QUEUE_JOURNAL_NONE);
  1126. PropertyFilter.UseJournalQueue = true;
  1127. Properties.Remove(NativeMethods.QUEUE_PROPID_JOURNAL);
  1128. }
  1129. return this.useJournaling;
  1130. }
  1131. set
  1132. {
  1133. if (value)
  1134. Properties.SetUI1(NativeMethods.QUEUE_PROPID_JOURNAL, (byte)NativeMethods.QUEUE_JOURNAL_JOURNAL);
  1135. else
  1136. Properties.SetUI1(NativeMethods.QUEUE_PROPID_JOURNAL, (byte)NativeMethods.QUEUE_JOURNAL_NONE);
  1137. SaveQueueProperties();
  1138. this.useJournaling = value;
  1139. PropertyFilter.UseJournalQueue = true;
  1140. Properties.Remove(NativeMethods.QUEUE_PROPID_JOURNAL);
  1141. }
  1142. }
  1143. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.WriteHandle"]/*' />
  1144. /// <devdoc>
  1145. /// <para>
  1146. /// The native handle used to send messages to the message queue
  1147. /// </para>
  1148. /// </devdoc>
  1149. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), MessagingDescription(Res.MQ_WriteHandle)]
  1150. public IntPtr WriteHandle
  1151. {
  1152. get
  1153. {
  1154. return MQInfo.WriteHandle.DangerousGetHandle();
  1155. }
  1156. }
  1157. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekCompleted"]/*' />
  1158. /// <devdoc>
  1159. /// <para>Occurs when a message is read without being removed
  1160. /// from the queue. This is a result of the asynchronous operation, <see cref='System.Messaging.MessageQueue.BeginPeek'/>
  1161. /// .</para>
  1162. /// </devdoc>
  1163. [MessagingDescription(Res.MQ_PeekCompleted)]
  1164. public event PeekCompletedEventHandler PeekCompleted
  1165. {
  1166. add
  1167. {
  1168. onPeekCompleted += value;
  1169. }
  1170. remove
  1171. {
  1172. onPeekCompleted -= value;
  1173. }
  1174. }
  1175. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveCompleted"]/*' />
  1176. /// <devdoc>
  1177. /// <para>
  1178. /// Occurs when a message has been taken out of the queue.
  1179. /// This is a result of the asynchronous operation <see cref='System.Messaging.MessageQueue.BeginReceive'/>
  1180. /// .
  1181. /// </para>
  1182. /// </devdoc>
  1183. [MessagingDescription(Res.MQ_ReceiveCompleted)]
  1184. public event ReceiveCompletedEventHandler ReceiveCompleted
  1185. {
  1186. add
  1187. {
  1188. onReceiveCompleted += value;
  1189. }
  1190. remove
  1191. {
  1192. onReceiveCompleted -= value;
  1193. }
  1194. }
  1195. private Hashtable OutstandingAsyncRequests
  1196. {
  1197. get
  1198. {
  1199. if (outstandingAsyncRequests == null)
  1200. {
  1201. lock (this.syncRoot)
  1202. {
  1203. if (outstandingAsyncRequests == null)
  1204. {
  1205. Hashtable requests = Hashtable.Synchronized(new Hashtable());
  1206. Thread.MemoryBarrier();
  1207. outstandingAsyncRequests = requests;
  1208. }
  1209. }
  1210. }
  1211. return outstandingAsyncRequests;
  1212. }
  1213. }
  1214. private QueueInfoKeyHolder QueueInfoKey
  1215. {
  1216. get
  1217. {
  1218. if (queueInfoKey == null)
  1219. {
  1220. lock (this.syncRoot)
  1221. {
  1222. if (queueInfoKey == null)
  1223. {
  1224. QueueInfoKeyHolder keyHolder = new QueueInfoKeyHolder(FormatName, accessMode);
  1225. Thread.MemoryBarrier();
  1226. queueInfoKey = keyHolder;
  1227. }
  1228. }
  1229. }
  1230. return this.queueInfoKey;
  1231. }
  1232. }
  1233. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginPeek"]/*' />
  1234. /// <devdoc>
  1235. /// <para>Initiates an asynchronous peek operation with no timeout. The method
  1236. /// returns immediately, but the asynchronous operation is not completed until
  1237. /// the event handler is called. This occurs when a message is
  1238. /// available in the
  1239. /// queue.</para>
  1240. /// </devdoc>
  1241. public IAsyncResult BeginPeek()
  1242. {
  1243. return ReceiveAsync(InfiniteTimeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, null, null);
  1244. }
  1245. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginPeek1"]/*' />
  1246. /// <devdoc>
  1247. /// <para> Initiates an asynchronous peek operation with the timeout specified.
  1248. /// The method returns immediately, but the asynchronous operation is not completed until
  1249. /// the event handler is called. This occurs when either a message is available in
  1250. /// the queue or the timeout
  1251. /// expires.</para>
  1252. /// </devdoc>
  1253. public IAsyncResult BeginPeek(TimeSpan timeout)
  1254. {
  1255. return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, null, null);
  1256. }
  1257. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginPeek2"]/*' />
  1258. /// <devdoc>
  1259. /// <para> Initiates an asynchronous peek operation with a state object that associates
  1260. /// information with the operation throughout the operation's
  1261. /// lifetime. The method returns immediately, but the asynchronous operation is not completed
  1262. /// until the event handler
  1263. /// is called. This occurs when either a message is available in the
  1264. /// queue or the timeout
  1265. /// expires.</para>
  1266. /// </devdoc>
  1267. public IAsyncResult BeginPeek(TimeSpan timeout, object stateObject)
  1268. {
  1269. return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, null, stateObject);
  1270. }
  1271. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginPeek3"]/*' />
  1272. /// <devdoc>
  1273. /// <para> Initiates an asynchronous peek operation that receives
  1274. /// notification through a callback which identifies the event handling method for the
  1275. /// operation. The method returns immediately, but the asynchronous operation is not completed
  1276. /// until the event handler is called. This occurs when either a message is available
  1277. /// in the queue or the timeout
  1278. /// expires.</para>
  1279. /// </devdoc>
  1280. public IAsyncResult BeginPeek(TimeSpan timeout, object stateObject, AsyncCallback callback)
  1281. {
  1282. return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, callback, stateObject);
  1283. }
  1284. public IAsyncResult BeginPeek(TimeSpan timeout, Cursor cursor, PeekAction action, object state, AsyncCallback callback)
  1285. {
  1286. if ((action != PeekAction.Current) && (action != PeekAction.Next))
  1287. throw new ArgumentOutOfRangeException(Res.GetString(Res.InvalidParameter, "action", action.ToString()));
  1288. if (cursor == null)
  1289. throw new ArgumentNullException("cursor");
  1290. return ReceiveAsync(timeout, cursor.Handle, (int)action, callback, state);
  1291. }
  1292. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginReceive"]/*' />
  1293. /// <devdoc>
  1294. /// <para>
  1295. /// Receives the first message available in the queue
  1296. /// referenced by the <see cref='System.Messaging.MessageQueue'/>
  1297. /// .
  1298. /// </para>
  1299. /// </devdoc>
  1300. public IAsyncResult BeginReceive()
  1301. {
  1302. return ReceiveAsync(InfiniteTimeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_RECEIVE, null, null);
  1303. }
  1304. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginReceive1"]/*' />
  1305. /// <devdoc>
  1306. /// <para>
  1307. /// Receives the first message available in the queue
  1308. /// referenced by the <see cref='System.Messaging.MessageQueue'/> . Waits the specified interval for
  1309. /// the message to be
  1310. /// removed.
  1311. /// </para>
  1312. /// </devdoc>
  1313. public IAsyncResult BeginReceive(TimeSpan timeout)
  1314. {
  1315. return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_RECEIVE, null, null);
  1316. }
  1317. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginReceive2"]/*' />
  1318. /// <devdoc>
  1319. /// <para>
  1320. /// Receives the first message available in the queue
  1321. /// referenced by the <see cref='System.Messaging.MessageQueue'/> . Waits the specified interval
  1322. /// for a new message to be removed and uses the specified object to retrieve
  1323. /// the result.
  1324. /// </para>
  1325. /// </devdoc>
  1326. public IAsyncResult BeginReceive(TimeSpan timeout, object stateObject)
  1327. {
  1328. return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_RECEIVE, null, stateObject);
  1329. }
  1330. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.BeginReceive3"]/*' />
  1331. /// <devdoc>
  1332. /// <para>Receives the first message available in the queue
  1333. /// referenced by the <see cref='System.Messaging.MessageQueue'/> . Waits
  1334. /// the specified interval for a new message to be removed, uses the specified
  1335. /// object to retrieve the result, and receives notification through a
  1336. /// callback.</para>
  1337. /// </devdoc>
  1338. public IAsyncResult BeginReceive(TimeSpan timeout, object stateObject, AsyncCallback callback)
  1339. {
  1340. return ReceiveAsync(timeout, CursorHandle.NullHandle, NativeMethods.QUEUE_ACTION_RECEIVE, callback, stateObject);
  1341. }
  1342. public IAsyncResult BeginReceive(TimeSpan timeout, Cursor cursor, object state, AsyncCallback callback)
  1343. {
  1344. if (cursor == null)
  1345. throw new ArgumentNullException("cursor");
  1346. return ReceiveAsync(timeout, cursor.Handle, NativeMethods.QUEUE_ACTION_RECEIVE, callback, state);
  1347. }
  1348. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ClearConnectionCache"]/*' />
  1349. /// <devdoc>
  1350. /// <para>[To be supplied.]</para>
  1351. /// </devdoc>
  1352. public static void ClearConnectionCache()
  1353. {
  1354. formatNameCache.ClearStale(new TimeSpan(0));
  1355. queueInfoCache.ClearStale(new TimeSpan(0));
  1356. }
  1357. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Close"]/*' />
  1358. /// <devdoc>
  1359. /// <para>
  1360. /// Frees all resources allocated by the <see cref='System.Messaging.MessageQueue'/>
  1361. /// .
  1362. /// </para>
  1363. /// </devdoc>
  1364. public void Close()
  1365. {
  1366. Cleanup(true);
  1367. }
  1368. private void Cleanup(bool disposing)
  1369. {
  1370. //This is generated from the path.
  1371. //It needs to be cleared.
  1372. this.formatName = null;
  1373. this.queuePath = null;
  1374. this.attached = false;
  1375. if (disposing)
  1376. {
  1377. if (this.mqInfo != null)
  1378. {
  1379. this.mqInfo.Release();
  1380. //No need to check references in this case, the only object
  1381. //mqInfo is not cached if both conditions are satisified.
  1382. if (sharedMode == NativeMethods.QUEUE_SHARED_MODE_DENY_RECEIVE || !enableCache)
  1383. this.mqInfo.Dispose();
  1384. this.mqInfo = null;
  1385. }
  1386. }
  1387. }
  1388. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Create"]/*' />
  1389. /// <devdoc>
  1390. /// <para>
  1391. /// Creates
  1392. /// a nontransactional Message Queuing backend queue resource with the
  1393. /// specified path.
  1394. /// </para>
  1395. /// </devdoc>
  1396. public static MessageQueue Create(string path)
  1397. {
  1398. return MessageQueue.Create(path, false);
  1399. }
  1400. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Create1"]/*' />
  1401. /// <devdoc>
  1402. /// <para>
  1403. /// Creates
  1404. /// a transactional or nontransactional Message Queuing backend queue resource with the
  1405. /// specified path.
  1406. /// </para>
  1407. /// </devdoc>
  1408. public static MessageQueue Create(string path, bool transactional)
  1409. {
  1410. if (path == null)
  1411. throw new ArgumentNullException("path");
  1412. if (path.Length == 0)
  1413. throw new ArgumentException(Res.GetString(Res.InvalidParameter, "path", path));
  1414. if (!IsCanonicalPath(path, true))
  1415. throw new ArgumentException(Res.GetString(Res.InvalidQueuePathToCreate, path));
  1416. //Create properties.
  1417. QueuePropertyVariants properties = new QueuePropertyVariants();
  1418. properties.SetString(NativeMethods.QUEUE_PROPID_PATHNAME, Message.StringToBytes(path));
  1419. if (transactional)
  1420. properties.SetUI1(NativeMethods.QUEUE_PROPID_TRANSACTION, (byte)NativeMethods.QUEUE_TRANSACTIONAL_TRANSACTIONAL);
  1421. else
  1422. properties.SetUI1(NativeMethods.QUEUE_PROPID_TRANSACTION, (byte)NativeMethods.QUEUE_TRANSACTIONAL_NONE);
  1423. StringBuilder formatName = new StringBuilder(NativeMethods.MAX_LABEL_LEN);
  1424. int formatNameLen = NativeMethods.MAX_LABEL_LEN;
  1425. int status = 0;
  1426. //Try to create queue.
  1427. status = UnsafeNativeMethods.MQCreateQueue(IntPtr.Zero, properties.Lock(), formatName, ref formatNameLen);
  1428. properties.Unlock();
  1429. if (MessageQueue.IsFatalError(status))
  1430. throw new MessageQueueException(status);
  1431. return new MessageQueue(path);
  1432. }
  1433. public Cursor CreateCursor()
  1434. {
  1435. return new Cursor(this);
  1436. }
  1437. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CreateMessageQueuesSnapshot"]/*' />
  1438. /// <internalonly/>
  1439. private static MessageQueue[] CreateMessageQueuesSnapshot(MessageQueueCriteria criteria)
  1440. {
  1441. return CreateMessageQueuesSnapshot(criteria, true);
  1442. }
  1443. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.CreateMessageQueuesSnapshot1"]/*' />
  1444. /// <internalonly/>
  1445. private static MessageQueue[] CreateMessageQueuesSnapshot(MessageQueueCriteria criteria, bool checkSecurity)
  1446. {
  1447. ArrayList messageQueuesList = new ArrayList();
  1448. IEnumerator messageQueues = GetMessageQueueEnumerator(criteria, checkSecurity);
  1449. while (messageQueues.MoveNext())
  1450. {
  1451. MessageQueue messageQueue = (MessageQueue)messageQueues.Current;
  1452. messageQueuesList.Add(messageQueue);
  1453. }
  1454. MessageQueue[] queues = new MessageQueue[messageQueuesList.Count];
  1455. messageQueuesList.CopyTo(queues, 0);
  1456. return queues;
  1457. }
  1458. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Delete"]/*' />
  1459. /// <devdoc>
  1460. /// <para>
  1461. /// Deletes a queue backend resource identified by
  1462. /// the given path.
  1463. /// </para>
  1464. /// </devdoc>
  1465. public static void Delete(string path)
  1466. {
  1467. if (path == null)
  1468. throw new ArgumentNullException("path");
  1469. if (path.Length == 0)
  1470. throw new ArgumentException(Res.GetString(Res.InvalidParameter, "path", path));
  1471. if (!ValidatePath(path, false))
  1472. throw new ArgumentException(Res.GetString(Res.PathSyntax));
  1473. int status = 0;
  1474. MessageQueue queue = new MessageQueue(path);
  1475. status = UnsafeNativeMethods.MQDeleteQueue(queue.FormatName);
  1476. if (MessageQueue.IsFatalError(status))
  1477. throw new MessageQueueException(status);
  1478. queueInfoCache.Remove(queue.QueueInfoKey);
  1479. formatNameCache.Remove(path.ToUpper(CultureInfo.InvariantCulture));
  1480. }
  1481. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Dispose"]/*' />
  1482. /// <devdoc>
  1483. /// <para>
  1484. /// </para>
  1485. /// </devdoc>
  1486. protected override void Dispose(bool disposing)
  1487. {
  1488. Cleanup(disposing);
  1489. base.Dispose(disposing);
  1490. }
  1491. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.EndPeek"]/*' />
  1492. /// <devdoc>
  1493. /// <para>Completes an asynchronous peek operation associated with
  1494. /// the <paramref name="asyncResult"/>
  1495. /// parameter.</para>
  1496. /// </devdoc>
  1497. public Message EndPeek(IAsyncResult asyncResult)
  1498. {
  1499. return EndAsyncOperation(asyncResult);
  1500. }
  1501. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.EndReceive"]/*' />
  1502. /// <devdoc>
  1503. /// <para>
  1504. /// Terminates a receive asynchronous operation identified
  1505. /// by the specified interface.
  1506. /// </para>
  1507. /// </devdoc>
  1508. public Message EndReceive(IAsyncResult asyncResult)
  1509. {
  1510. return EndAsyncOperation(asyncResult);
  1511. }
  1512. private Message EndAsyncOperation(IAsyncResult asyncResult)
  1513. {
  1514. if (asyncResult == null)
  1515. throw new ArgumentNullException("asyncResult");
  1516. if (!(asyncResult is AsynchronousRequest))
  1517. throw new ArgumentException(Res.GetString(Res.AsyncResultInvalid));
  1518. AsynchronousRequest request = (AsynchronousRequest)asyncResult;
  1519. return request.End();
  1520. }
  1521. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Exists"]/*' />
  1522. /// <devdoc>
  1523. /// <para>
  1524. /// Determines whether a queue with the specified path
  1525. /// exists.
  1526. /// </para>
  1527. /// </devdoc>
  1528. public static bool Exists(string path)
  1529. {
  1530. if (path == null)
  1531. throw new ArgumentNullException("path");
  1532. if (!ValidatePath(path, false))
  1533. throw new ArgumentException(Res.GetString(Res.PathSyntax));
  1534. string pathUpper = path.ToUpper(CultureInfo.InvariantCulture);
  1535. if (pathUpper.StartsWith(PREFIX_FORMAT_NAME))
  1536. throw new InvalidOperationException(Res.GetString(Res.QueueExistsError));
  1537. else if (pathUpper.StartsWith(PREFIX_LABEL))
  1538. {
  1539. MessageQueue labeledQueue = ResolveQueueFromLabel(path, false);
  1540. if (labeledQueue == null)
  1541. return false;
  1542. else
  1543. return true;
  1544. }
  1545. else
  1546. {
  1547. string formatName = ResolveFormatNameFromQueuePath(path, false);
  1548. if (formatName == null)
  1549. return false;
  1550. else
  1551. return true;
  1552. }
  1553. }
  1554. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GenerateQueueProperties"]/*' />
  1555. /// <internalonly/>
  1556. private void GenerateQueueProperties()
  1557. {
  1558. int status = UnsafeNativeMethods.MQGetQueueProperties(FormatName, Properties.Lock());
  1559. Properties.Unlock();
  1560. if (MessageQueue.IsFatalError(status))
  1561. throw new MessageQueueException(status);
  1562. }
  1563. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetAllMessages"]/*' />
  1564. /// <devdoc>
  1565. /// <para>
  1566. /// Returns all the messages available in the queue.
  1567. /// </para>
  1568. /// </devdoc>
  1569. public Message[] GetAllMessages()
  1570. {
  1571. ArrayList messageList = new ArrayList();
  1572. MessageEnumerator messages = GetMessageEnumerator2();
  1573. while (messages.MoveNext())
  1574. {
  1575. Message message = (Message)messages.Current;
  1576. messageList.Add(message);
  1577. }
  1578. Message[] resultMessages = new Message[messageList.Count];
  1579. messageList.CopyTo(resultMessages, 0);
  1580. return resultMessages;
  1581. }
  1582. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetEnumerator"]/*' />
  1583. /// <devdoc>
  1584. /// <para>[To be supplied.]</para>
  1585. /// </devdoc>
  1586. [Obsolete("This method returns a MessageEnumerator that implements RemoveCurrent family of methods incorrectly. Please use GetMessageEnumerator2 instead.")]
  1587. public IEnumerator GetEnumerator()
  1588. {
  1589. return GetMessageEnumerator();
  1590. }
  1591. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMachineId"]/*' />
  1592. /// <devdoc>
  1593. /// <para>[To be supplied.]</para>
  1594. /// </devdoc>
  1595. public static Guid GetMachineId(string machineName)
  1596. {
  1597. if (!SyntaxCheck.CheckMachineName(machineName))
  1598. throw new ArgumentException(Res.GetString(Res.InvalidParameter, "MachineName", machineName));
  1599. if (machineName == ".")
  1600. machineName = MessageQueue.ComputerName;
  1601. MachinePropertyVariants machineProperties = new MachinePropertyVariants();
  1602. byte[] bytes = new byte[16];
  1603. machineProperties.SetNull(NativeMethods.MACHINE_ID);
  1604. int status = UnsafeNativeMethods.MQGetMachineProperties(machineName, IntPtr.Zero, machineProperties.Lock());
  1605. machineProperties.Unlock();
  1606. IntPtr handle = machineProperties.GetIntPtr(NativeMethods.MACHINE_ID);
  1607. if (MessageQueue.IsFatalError(status))
  1608. {
  1609. if (handle != IntPtr.Zero)
  1610. SafeNativeMethods.MQFreeMemory(handle);
  1611. throw new MessageQueueException(status);
  1612. }
  1613. if (handle != IntPtr.Zero)
  1614. {
  1615. Marshal.Copy(handle, bytes, 0, 16);
  1616. SafeNativeMethods.MQFreeMemory(handle);
  1617. }
  1618. return new Guid(bytes);
  1619. }
  1620. /// <devdoc>
  1621. /// Represents security context that can be used to easily and efficiently
  1622. /// send messages in impersonating applications.
  1623. /// </devdoc>
  1624. public static SecurityContext GetSecurityContext()
  1625. {
  1626. SecurityContextHandle handle;
  1627. // SECURITY: Note that this call is not marked with SUCS attribute (i.e., requires FullTrust)
  1628. int status = NativeMethods.MQGetSecurityContextEx(out handle);
  1629. if (MessageQueue.IsFatalError(status))
  1630. throw new MessageQueueException(status);
  1631. return new SecurityContext(handle);
  1632. }
  1633. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageQueueEnumerator"]/*' />
  1634. /// <devdoc>
  1635. /// <para>
  1636. /// Creates an enumerator object for the message queues
  1637. /// available on the network.
  1638. /// </para>
  1639. /// </devdoc>
  1640. public static MessageQueueEnumerator GetMessageQueueEnumerator()
  1641. {
  1642. return new MessageQueueEnumerator(null);
  1643. }
  1644. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageQueueEnumerator1"]/*' />
  1645. /// <devdoc>
  1646. /// <para>
  1647. /// Creates an enumerator object for the message queues
  1648. /// available on the network.
  1649. /// </para>
  1650. /// </devdoc>
  1651. public static MessageQueueEnumerator GetMessageQueueEnumerator(MessageQueueCriteria criteria)
  1652. {
  1653. return new MessageQueueEnumerator(criteria);
  1654. }
  1655. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageQueueEnumerator"]/*' />
  1656. /// <internalonly/>
  1657. internal static MessageQueueEnumerator GetMessageQueueEnumerator(MessageQueueCriteria criteria, bool checkSecurity)
  1658. {
  1659. return new MessageQueueEnumerator(criteria, checkSecurity);
  1660. }
  1661. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageEnumerator"]/*' />
  1662. /// <devdoc>
  1663. /// <para>
  1664. /// Creates an enumerator object for the messages in the queue. Superceded by GetMessageEnumerator2.
  1665. /// </para>
  1666. /// </devdoc>
  1667. [Obsolete("This method returns a MessageEnumerator that implements RemoveCurrent family of methods incorrectly. Please use GetMessageEnumerator2 instead.")]
  1668. public MessageEnumerator GetMessageEnumerator()
  1669. {
  1670. return new MessageEnumerator(this, false);
  1671. }
  1672. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetMessageEnumerator2"]/*' />
  1673. /// <devdoc>
  1674. /// <para>
  1675. /// Creates an enumerator object for the messages in the queue.
  1676. /// </para>
  1677. /// </devdoc>
  1678. public MessageEnumerator GetMessageEnumerator2()
  1679. {
  1680. return new MessageEnumerator(this, true);
  1681. }
  1682. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPrivateQueuesByMachine"]/*' />
  1683. /// <devdoc>
  1684. /// <para>
  1685. /// Retrieves all the private queues on
  1686. /// the specified computer.
  1687. /// </para>
  1688. /// </devdoc>
  1689. public static MessageQueue[] GetPrivateQueuesByMachine(string machineName)
  1690. {
  1691. if (!SyntaxCheck.CheckMachineName(machineName))
  1692. throw new ArgumentException(Res.GetString(Res.InvalidParameter, "MachineName", machineName));
  1693. if (machineName == "." || (String.Compare(machineName, MessageQueue.ComputerName, true, CultureInfo.InvariantCulture) == 0))
  1694. machineName = null;
  1695. MessagePropertyVariants properties = new MessagePropertyVariants(5, 0);
  1696. properties.SetNull(NativeMethods.MANAGEMENT_PRIVATEQ);
  1697. int status = UnsafeNativeMethods.MQMgmtGetInfo(machineName, "MACHINE", properties.Lock());
  1698. properties.Unlock();
  1699. if (MessageQueue.IsFatalError(status))
  1700. throw new MessageQueueException(status);
  1701. uint len = properties.GetStringVectorLength(NativeMethods.MANAGEMENT_PRIVATEQ);
  1702. IntPtr basePointer = properties.GetStringVectorBasePointer(NativeMethods.MANAGEMENT_PRIVATEQ);
  1703. MessageQueue[] queues = new MessageQueue[len];
  1704. for (int index = 0; index < len; ++index)
  1705. {
  1706. IntPtr stringPointer = Marshal.ReadIntPtr((IntPtr)((long)basePointer + index * IntPtr.Size));
  1707. //Using Unicode API even on Win9x
  1708. string path = Marshal.PtrToStringUni(stringPointer);
  1709. queues[index] = new MessageQueue("FormatName:DIRECT=OS:" + path);
  1710. queues[index].queuePath = path;
  1711. SafeNativeMethods.MQFreeMemory(stringPointer);
  1712. }
  1713. SafeNativeMethods.MQFreeMemory(basePointer);
  1714. return queues;
  1715. }
  1716. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueues"]/*' />
  1717. /// <devdoc>
  1718. /// <para>
  1719. /// Retrieves all public queues on the network.
  1720. /// </para>
  1721. /// </devdoc>
  1722. public static MessageQueue[] GetPublicQueues()
  1723. {
  1724. return CreateMessageQueuesSnapshot(null);
  1725. }
  1726. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueues1"]/*' />
  1727. /// <devdoc>
  1728. /// <para>
  1729. /// Retrieves a
  1730. /// set of public queues filtered by the specified criteria.
  1731. /// </para>
  1732. /// </devdoc>
  1733. public static MessageQueue[] GetPublicQueues(MessageQueueCriteria criteria)
  1734. {
  1735. return CreateMessageQueuesSnapshot(criteria);
  1736. }
  1737. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueuesByCategory"]/*' />
  1738. /// <devdoc>
  1739. /// <para>
  1740. /// Retrieves a
  1741. /// set of public queues filtered by the specified category.
  1742. /// </para>
  1743. /// </devdoc>
  1744. public static MessageQueue[] GetPublicQueuesByCategory(Guid category)
  1745. {
  1746. MessageQueueCriteria criteria = new MessageQueueCriteria();
  1747. criteria.Category = category;
  1748. return CreateMessageQueuesSnapshot(criteria);
  1749. }
  1750. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueuesByLabel"]/*' />
  1751. /// <devdoc>
  1752. /// <para>
  1753. /// Retrieves a
  1754. /// set of public queues filtered by the specified label.
  1755. /// </para>
  1756. /// </devdoc>
  1757. public static MessageQueue[] GetPublicQueuesByLabel(string label)
  1758. {
  1759. return GetPublicQueuesByLabel(label, true);
  1760. }
  1761. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.GetPublicQueuesByLabel1"]/*' />
  1762. /// <internalonly/>
  1763. private static MessageQueue[] GetPublicQueuesByLabel(string label, bool checkSecurity)
  1764. {
  1765. MessageQueueCriteria criteria = new MessageQueueCriteria();
  1766. criteria.Label = label;
  1767. return CreateMessageQueuesSnapshot(criteria, checkSecurity);
  1768. }
  1769. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.IsCanonicalPath"]/*' />
  1770. /// <internalonly/>
  1771. private static bool IsCanonicalPath(string path, bool checkQueueNameSize)
  1772. {
  1773. if (!ValidatePath(path, checkQueueNameSize))
  1774. return false;
  1775. string upperPath = path.ToUpper(CultureInfo.InvariantCulture);
  1776. if (upperPath.StartsWith(PREFIX_LABEL) ||
  1777. upperPath.StartsWith(PREFIX_FORMAT_NAME) ||
  1778. upperPath.EndsWith(SUFIX_DEADLETTER) ||
  1779. upperPath.EndsWith(SUFIX_DEADXACT) ||
  1780. upperPath.EndsWith(SUFIX_JOURNAL))
  1781. return false;
  1782. return true;
  1783. }
  1784. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.IsFatalError"]/*' />
  1785. /// <internalonly/>
  1786. internal static bool IsFatalError(int value)
  1787. {
  1788. bool isSuccessful = (value == 0x00000000);
  1789. bool isInformation = ((value & unchecked((int)0xC0000000)) == 0x40000000);
  1790. return (!isInformation && !isSuccessful);
  1791. }
  1792. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.IsMemoryError"]/*' />
  1793. /// <internalonly/>
  1794. internal static bool IsMemoryError(int value)
  1795. {
  1796. if (value == (int)MessageQueueErrorCode.BufferOverflow ||
  1797. value == (int)MessageQueueErrorCode.LabelBufferTooSmall ||
  1798. value == (int)MessageQueueErrorCode.ProviderNameBufferTooSmall ||
  1799. value == (int)MessageQueueErrorCode.SenderCertificateBufferTooSmall ||
  1800. value == (int)MessageQueueErrorCode.SenderIdBufferTooSmall ||
  1801. value == (int)MessageQueueErrorCode.SecurityDescriptorBufferTooSmall ||
  1802. value == (int)MessageQueueErrorCode.SignatureBufferTooSmall ||
  1803. value == (int)MessageQueueErrorCode.SymmetricKeyBufferTooSmall ||
  1804. value == (int)MessageQueueErrorCode.UserBufferTooSmall ||
  1805. value == (int)MessageQueueErrorCode.FormatNameBufferTooSmall)
  1806. return true;
  1807. return false;
  1808. }
  1809. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.OnRequestCompleted"]/*' />
  1810. /// <devdoc>
  1811. /// Used for component model event support.
  1812. /// </devdoc>
  1813. /// <internalonly/>
  1814. private void OnRequestCompleted(IAsyncResult asyncResult)
  1815. {
  1816. if (((AsynchronousRequest)asyncResult).Action == NativeMethods.QUEUE_ACTION_PEEK_CURRENT)
  1817. {
  1818. if (this.onPeekCompleted != null)
  1819. {
  1820. PeekCompletedEventArgs eventArgs = new PeekCompletedEventArgs(this, asyncResult);
  1821. this.onPeekCompleted(this, eventArgs);
  1822. }
  1823. }
  1824. else
  1825. {
  1826. if (this.onReceiveCompleted != null)
  1827. {
  1828. ReceiveCompletedEventArgs eventArgs = new ReceiveCompletedEventArgs(this, asyncResult);
  1829. this.onReceiveCompleted(this, eventArgs);
  1830. }
  1831. }
  1832. }
  1833. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Peek"]/*' />
  1834. /// <devdoc>
  1835. /// <para>
  1836. /// Returns without removing (peeks) the first message
  1837. /// available in the queue referenced by the <see cref='System.Messaging.MessageQueue'/> . This call
  1838. /// is synchronous. It
  1839. /// blocks the current
  1840. /// thread of execution until a message is
  1841. /// available.
  1842. /// </para>
  1843. /// </devdoc>
  1844. public Message Peek()
  1845. {
  1846. return ReceiveCurrent(InfiniteTimeout, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, CursorHandle.NullHandle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  1847. }
  1848. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Peek1"]/*' />
  1849. /// <devdoc>
  1850. /// <para>
  1851. /// Returns without removing (peeks) the first message
  1852. /// available in the queue referenced by the <see cref='System.Messaging.MessageQueue'/>
  1853. /// . Waits
  1854. /// the specified interval for a message to become
  1855. /// available.
  1856. /// </para>
  1857. /// </devdoc>
  1858. public Message Peek(TimeSpan timeout)
  1859. {
  1860. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, CursorHandle.NullHandle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  1861. }
  1862. public Message Peek(TimeSpan timeout, Cursor cursor, PeekAction action)
  1863. {
  1864. if ((action != PeekAction.Current) && (action != PeekAction.Next))
  1865. throw new ArgumentOutOfRangeException(Res.GetString(Res.InvalidParameter, "action", action.ToString()));
  1866. if (cursor == null)
  1867. throw new ArgumentNullException("cursor");
  1868. return ReceiveCurrent(timeout, (int)action, cursor.Handle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  1869. }
  1870. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekById"]/*' />
  1871. /// <devdoc>
  1872. /// <para>
  1873. /// Peeks the message that matches the given ID.
  1874. /// If there is no message with a matching ID,
  1875. /// an exception will be raised.
  1876. /// </para>
  1877. /// </devdoc>
  1878. public Message PeekById(string id)
  1879. {
  1880. return ReceiveBy(id, TimeSpan.Zero, false, true, false, null, MessageQueueTransactionType.None);
  1881. }
  1882. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekById1"]/*' />
  1883. /// <devdoc>
  1884. /// <para>
  1885. /// Peeks the message that matches the
  1886. /// given ID. This method waits until a message with
  1887. /// a matching ID is available, or the given timeout
  1888. /// expires when no more messages can be
  1889. /// inspected.
  1890. /// </para>
  1891. /// </devdoc>
  1892. public Message PeekById(string id, TimeSpan timeout)
  1893. {
  1894. return ReceiveBy(id, timeout, false, true, true, null, MessageQueueTransactionType.None);
  1895. }
  1896. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekByCorrelationId"]/*' />
  1897. /// <devdoc>
  1898. /// <para>
  1899. /// Peeks the message that matches the
  1900. /// given correlation ID. If there is no message with
  1901. /// a matching correlation ID, an exception is
  1902. /// thrown.
  1903. /// </para>
  1904. /// </devdoc>
  1905. public Message PeekByCorrelationId(string correlationId)
  1906. {
  1907. return ReceiveBy(correlationId, TimeSpan.Zero, false, false, false, null, MessageQueueTransactionType.None);
  1908. }
  1909. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.PeekByCorrelationId1"]/*' />
  1910. /// <devdoc>
  1911. /// <para>
  1912. /// Peeks the message that matches the
  1913. /// given correlation ID. This function will wait
  1914. /// until a message with a matching correlation ID is
  1915. /// available, or the given timeout expires when
  1916. /// no more messages can be inspected.
  1917. /// </para>
  1918. /// </devdoc>
  1919. public Message PeekByCorrelationId(string correlationId, TimeSpan timeout)
  1920. {
  1921. return ReceiveBy(correlationId, timeout, false, false, true, null, MessageQueueTransactionType.None);
  1922. }
  1923. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Purge"]/*' />
  1924. /// <devdoc>
  1925. /// <para>
  1926. /// Deletes all the messages contained in the queue.
  1927. /// </para>
  1928. /// </devdoc>
  1929. public void Purge()
  1930. {
  1931. int status = StaleSafePurgeQueue();
  1932. if (MessageQueue.IsFatalError(status))
  1933. throw new MessageQueueException(status);
  1934. }
  1935. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive"]/*' />
  1936. /// <devdoc>
  1937. /// <para>
  1938. /// Receives the first message available in the queue referenced by the <see cref='System.Messaging.MessageQueue'/> . This
  1939. /// call is synchronous. It blocks the current thread of execution until a message is
  1940. /// available.
  1941. /// </para>
  1942. /// </devdoc>
  1943. public Message Receive()
  1944. {
  1945. return ReceiveCurrent(InfiniteTimeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  1946. }
  1947. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive1"]/*' />
  1948. /// <devdoc>
  1949. /// <para>
  1950. /// Receives the first message available in the queue referenced by the <see cref='System.Messaging.MessageQueue'/> . This
  1951. /// call is synchronous. It blocks the current thread of execution until a message is
  1952. /// available.
  1953. /// </para>
  1954. /// </devdoc>
  1955. public Message Receive(MessageQueueTransaction transaction)
  1956. {
  1957. if (transaction == null)
  1958. throw new ArgumentNullException("transaction");
  1959. return ReceiveCurrent(InfiniteTimeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, transaction, MessageQueueTransactionType.None);
  1960. }
  1961. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive5"]/*' />
  1962. /// <devdoc>
  1963. /// <para>[To be supplied.]</para>
  1964. /// </devdoc>
  1965. public Message Receive(MessageQueueTransactionType transactionType)
  1966. {
  1967. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  1968. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  1969. return ReceiveCurrent(InfiniteTimeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, null, transactionType);
  1970. }
  1971. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive2"]/*' />
  1972. /// <devdoc>
  1973. /// <para>
  1974. /// Receives the first message available in the queue
  1975. /// referenced by the <see cref='System.Messaging.MessageQueue'/>
  1976. /// . Waits the specified interval for a message to become
  1977. /// available.
  1978. /// </para>
  1979. /// </devdoc>
  1980. public Message Receive(TimeSpan timeout)
  1981. {
  1982. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  1983. }
  1984. public Message Receive(TimeSpan timeout, Cursor cursor)
  1985. {
  1986. if (cursor == null)
  1987. throw new ArgumentNullException("cursor");
  1988. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursor.Handle, MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  1989. }
  1990. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive3"]/*' />
  1991. /// <devdoc>
  1992. /// <para>
  1993. /// Receives the first message available in the queue
  1994. /// referenced by the <see cref='System.Messaging.MessageQueue'/>
  1995. /// . Waits the specified interval for a message to become
  1996. /// available.
  1997. /// </para>
  1998. /// </devdoc>
  1999. public Message Receive(TimeSpan timeout, MessageQueueTransaction transaction)
  2000. {
  2001. if (transaction == null)
  2002. throw new ArgumentNullException("transaction");
  2003. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, transaction, MessageQueueTransactionType.None);
  2004. }
  2005. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Receive4"]/*' />
  2006. /// <devdoc>
  2007. /// <para>[To be supplied.]</para>
  2008. /// </devdoc>
  2009. public Message Receive(TimeSpan timeout, MessageQueueTransactionType transactionType)
  2010. {
  2011. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2012. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2013. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, CursorHandle.NullHandle, MessageReadPropertyFilter, null, transactionType);
  2014. }
  2015. public Message Receive(TimeSpan timeout, Cursor cursor, MessageQueueTransaction transaction)
  2016. {
  2017. if (transaction == null)
  2018. throw new ArgumentNullException("transaction");
  2019. if (cursor == null)
  2020. throw new ArgumentNullException("cursor");
  2021. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursor.Handle, MessageReadPropertyFilter, transaction, MessageQueueTransactionType.None);
  2022. }
  2023. public Message Receive(TimeSpan timeout, Cursor cursor, MessageQueueTransactionType transactionType)
  2024. {
  2025. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2026. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2027. if (cursor == null)
  2028. throw new ArgumentNullException("cursor");
  2029. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursor.Handle, MessageReadPropertyFilter, null, transactionType);
  2030. }
  2031. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveAsync"]/*' />
  2032. /// <internalonly/>
  2033. private unsafe IAsyncResult ReceiveAsync(TimeSpan timeout, CursorHandle cursorHandle, int action, AsyncCallback callback, object stateObject)
  2034. {
  2035. long timeoutInMilliseconds = (long)timeout.TotalMilliseconds;
  2036. if (timeoutInMilliseconds < 0 || timeoutInMilliseconds > UInt32.MaxValue)
  2037. throw new ArgumentException(Res.GetString(Res.InvalidParameter, "timeout", timeout.ToString()));
  2038. if (!attached)
  2039. {
  2040. lock (this)
  2041. {
  2042. if (!attached)
  2043. {
  2044. MessageQueueHandle handle = MQInfo.ReadHandle;
  2045. int handleInformation;
  2046. // If GetHandleInformation returns false, it means that the
  2047. // handle created for reading is not a File handle.
  2048. if (!SafeNativeMethods.GetHandleInformation(handle, out handleInformation))
  2049. // If not a File handle, need to use MSMQ
  2050. // APC based async IO.
  2051. // We will need to store references to pending async requests (bug 88607)
  2052. this.useThreadPool = false;
  2053. else
  2054. {
  2055. // File handle can use IOCompletion ports
  2056. // since it only happens for NT
  2057. MQInfo.BindToThreadPool();
  2058. this.useThreadPool = true;
  2059. }
  2060. attached = true;
  2061. }
  2062. }
  2063. }
  2064. if (callback == null)
  2065. {
  2066. if (this.onRequestCompleted == null)
  2067. this.onRequestCompleted = new AsyncCallback(this.OnRequestCompleted);
  2068. callback = this.onRequestCompleted;
  2069. }
  2070. AsynchronousRequest request = new AsynchronousRequest(this, (uint)timeoutInMilliseconds, cursorHandle, action, this.useThreadPool, stateObject, callback);
  2071. //
  2072. // Bug 88607 - keep a reference to outstanding asyncresult so its' not GCed
  2073. // This applies when GetHandleInformation returns false -> useThreadPool set to false
  2074. // It should only happen on dependent client, but we here we cover all GetHandleInformation
  2075. // failure paths for robustness.
  2076. //
  2077. // Need to add reference before calling BeginRead because request can complete by the time
  2078. // reference is added, and it will be leaked if added to table after completion
  2079. //
  2080. if (!this.useThreadPool)
  2081. {
  2082. OutstandingAsyncRequests[request] = request;
  2083. }
  2084. request.BeginRead();
  2085. return (IAsyncResult)request;
  2086. }
  2087. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveBy"]/*' />
  2088. /// <internalonly/>
  2089. private Message ReceiveBy(string id, TimeSpan timeout, bool remove, bool compareId, bool throwTimeout, MessageQueueTransaction transaction, MessageQueueTransactionType transactionType)
  2090. {
  2091. if (id == null)
  2092. throw new ArgumentNullException("id");
  2093. if (timeout < TimeSpan.Zero || timeout > InfiniteTimeout)
  2094. throw new ArgumentException(Res.GetString(Res.InvalidParameter, "timeout", timeout.ToString()));
  2095. MessagePropertyFilter oldFilter = this.receiveFilter;
  2096. CursorHandle cursorHandle = null;
  2097. try
  2098. {
  2099. this.receiveFilter = new MessagePropertyFilter();
  2100. this.receiveFilter.ClearAll();
  2101. if (!compareId)
  2102. this.receiveFilter.CorrelationId = true;
  2103. else
  2104. this.receiveFilter.Id = true;
  2105. //
  2106. // Use cursor (and not MessageEnumerator) to navigate the queue because enumerator implementation can be incorrect
  2107. // in multithreaded scenarios (see bug 329311)
  2108. //
  2109. //
  2110. // Get cursor handle
  2111. //
  2112. int status = SafeNativeMethods.MQCreateCursor(this.MQInfo.ReadHandle, out cursorHandle);
  2113. if (MessageQueue.IsFatalError(status))
  2114. throw new MessageQueueException(status);
  2115. try
  2116. {
  2117. //
  2118. // peek first message in the queue
  2119. //
  2120. Message message = this.ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, cursorHandle,
  2121. MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  2122. while (message != null)
  2123. {
  2124. if ((compareId && String.Compare(message.Id, id, true, CultureInfo.InvariantCulture) == 0) ||
  2125. (!compareId && String.Compare(message.CorrelationId, id, true, CultureInfo.InvariantCulture) == 0))
  2126. {
  2127. //
  2128. // Found matching message, receive it and return
  2129. //
  2130. this.receiveFilter = oldFilter;
  2131. if (remove)
  2132. {
  2133. if (transaction == null)
  2134. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursorHandle,
  2135. this.MessageReadPropertyFilter, null, transactionType);
  2136. else
  2137. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_RECEIVE, cursorHandle,
  2138. this.MessageReadPropertyFilter, transaction, MessageQueueTransactionType.None);
  2139. }
  2140. else
  2141. return ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_PEEK_CURRENT, cursorHandle,
  2142. this.MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  2143. } //end if
  2144. //
  2145. // Continue search, peek next message
  2146. //
  2147. message = this.ReceiveCurrent(timeout, NativeMethods.QUEUE_ACTION_PEEK_NEXT, cursorHandle,
  2148. MessageReadPropertyFilter, null, MessageQueueTransactionType.None);
  2149. }
  2150. }
  2151. catch (MessageQueueException)
  2152. {
  2153. // don't do anything, just use this catch as convenient means to exit the search
  2154. }
  2155. }
  2156. finally
  2157. {
  2158. this.receiveFilter = oldFilter;
  2159. if (cursorHandle != null)
  2160. {
  2161. cursorHandle.Close();
  2162. }
  2163. }
  2164. if (!throwTimeout)
  2165. throw new InvalidOperationException(Res.GetString("MessageNotFound"));
  2166. else
  2167. throw new MessageQueueException((int)MessageQueueErrorCode.IOTimeout);
  2168. }
  2169. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById"]/*' />
  2170. /// <devdoc>
  2171. /// <para>
  2172. /// Receives the message that matches the given
  2173. /// ID. If there is no message with a matching
  2174. /// ID, an exception is thrown.
  2175. /// </para>
  2176. /// </devdoc>
  2177. public Message ReceiveById(string id)
  2178. {
  2179. return ReceiveBy(id, TimeSpan.Zero, true, true, false, null, MessageQueueTransactionType.None);
  2180. }
  2181. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById1"]/*' />
  2182. /// <devdoc>
  2183. /// <para>
  2184. /// Receives the message that matches the given
  2185. /// ID. If there is no message with a matching
  2186. /// ID, an exception is thrown.
  2187. /// </para>
  2188. /// </devdoc>
  2189. public Message ReceiveById(string id, MessageQueueTransaction transaction)
  2190. {
  2191. if (transaction == null)
  2192. throw new ArgumentNullException("transaction");
  2193. return ReceiveBy(id, TimeSpan.Zero, true, true, false, transaction, MessageQueueTransactionType.None);
  2194. }
  2195. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById5"]/*' />
  2196. /// <devdoc>
  2197. /// <para>
  2198. /// Receives the message that matches the given
  2199. /// ID. If there is no message with a matching
  2200. /// ID, an exception is thrown.
  2201. /// </para>
  2202. /// </devdoc>
  2203. public Message ReceiveById(string id, MessageQueueTransactionType transactionType)
  2204. {
  2205. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2206. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2207. return ReceiveBy(id, TimeSpan.Zero, true, true, false, null, transactionType);
  2208. }
  2209. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById2"]/*' />
  2210. /// <devdoc>
  2211. /// <para>
  2212. /// Receives the message that matches the given
  2213. /// ID. This method waits until a message with
  2214. /// a matching id is available or the given timeout
  2215. /// expires when no more messages can be
  2216. /// inspected.
  2217. /// </para>
  2218. /// </devdoc>
  2219. public Message ReceiveById(string id, TimeSpan timeout)
  2220. {
  2221. return ReceiveBy(id, timeout, true, true, true, null, MessageQueueTransactionType.None);
  2222. }
  2223. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById3"]/*' />
  2224. /// <devdoc>
  2225. /// <para>
  2226. /// Receives the message that matches the given
  2227. /// ID. This method waits until a message with
  2228. /// a matching id is available or the given timeout
  2229. /// expires when no more messages can be
  2230. /// inspected.
  2231. /// </para>
  2232. /// </devdoc>
  2233. public Message ReceiveById(string id, TimeSpan timeout, MessageQueueTransaction transaction)
  2234. {
  2235. if (transaction == null)
  2236. throw new ArgumentNullException("transaction");
  2237. return ReceiveBy(id, timeout, true, true, true, transaction, MessageQueueTransactionType.None);
  2238. }
  2239. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveById4"]/*' />
  2240. /// <devdoc>
  2241. /// <para>
  2242. /// Receives the message that matches the given
  2243. /// ID. This method waits until a message with
  2244. /// a matching id is available or the given timeout
  2245. /// expires when no more messages can be
  2246. /// inspected.
  2247. /// </para>
  2248. /// </devdoc>
  2249. public Message ReceiveById(string id, TimeSpan timeout, MessageQueueTransactionType transactionType)
  2250. {
  2251. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2252. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2253. return ReceiveBy(id, timeout, true, true, true, null, transactionType);
  2254. }
  2255. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId"]/*' />
  2256. /// <devdoc>
  2257. /// <para>
  2258. /// Receivess the message that matches the
  2259. /// given correlation ID. If there is no message with
  2260. /// a matching correlation ID, an exception is
  2261. /// thrown.
  2262. /// </para>
  2263. /// </devdoc>
  2264. public Message ReceiveByCorrelationId(string correlationId)
  2265. {
  2266. return ReceiveBy(correlationId, TimeSpan.Zero, true, false, false, null, MessageQueueTransactionType.None);
  2267. }
  2268. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId1"]/*' />
  2269. /// <devdoc>
  2270. /// <para>
  2271. /// Receivess the message that matches the
  2272. /// given correlation ID. If there is no message with
  2273. /// a matching correlation ID, an exception is
  2274. /// thrown.
  2275. /// </para>
  2276. /// </devdoc>
  2277. public Message ReceiveByCorrelationId(string correlationId, MessageQueueTransaction transaction)
  2278. {
  2279. if (transaction == null)
  2280. throw new ArgumentNullException("transaction");
  2281. return ReceiveBy(correlationId, TimeSpan.Zero, true, false, false, transaction, MessageQueueTransactionType.None);
  2282. }
  2283. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId5"]/*' />
  2284. /// <devdoc>
  2285. /// <para>
  2286. /// Receivess the message that matches the
  2287. /// given correlation ID. If there is no message with
  2288. /// a matching correlation ID, an exception is
  2289. /// thrown.
  2290. /// </para>
  2291. /// </devdoc>
  2292. public Message ReceiveByCorrelationId(string correlationId, MessageQueueTransactionType transactionType)
  2293. {
  2294. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2295. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2296. return ReceiveBy(correlationId, TimeSpan.Zero, true, false, false, null, transactionType);
  2297. }
  2298. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId2"]/*' />
  2299. /// <devdoc>
  2300. /// <para>
  2301. /// Receives the message that matches
  2302. /// the given correlation ID. This method waits
  2303. /// until a message with a matching correlation ID is
  2304. /// available or the given timeout expires when
  2305. /// no more messages can be inspected.
  2306. /// </para>
  2307. /// </devdoc>
  2308. public Message ReceiveByCorrelationId(string correlationId, TimeSpan timeout)
  2309. {
  2310. return ReceiveBy(correlationId, timeout, true, false, true, null, MessageQueueTransactionType.None);
  2311. }
  2312. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId3"]/*' />
  2313. /// <devdoc>
  2314. /// <para>
  2315. /// Receives the message that matches
  2316. /// the given correlation ID. This method waits
  2317. /// until a message with a matching correlation ID is
  2318. /// available or the given timeout expires when
  2319. /// no more messages can be inspected.
  2320. /// </para>
  2321. /// </devdoc>
  2322. public Message ReceiveByCorrelationId(string correlationId, TimeSpan timeout, MessageQueueTransaction transaction)
  2323. {
  2324. if (transaction == null)
  2325. throw new ArgumentNullException("transaction");
  2326. return ReceiveBy(correlationId, timeout, true, false, true, transaction, MessageQueueTransactionType.None);
  2327. }
  2328. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveByCorrelationId4"]/*' />
  2329. /// <devdoc>
  2330. /// <para>
  2331. /// Receives the message that matches
  2332. /// the given correlation ID. This method waits
  2333. /// until a message with a matching correlation ID is
  2334. /// available or the given timeout expires when
  2335. /// no more messages can be inspected.
  2336. /// </para>
  2337. /// </devdoc>
  2338. public Message ReceiveByCorrelationId(string correlationId, TimeSpan timeout, MessageQueueTransactionType transactionType)
  2339. {
  2340. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2341. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2342. return ReceiveBy(correlationId, timeout, true, false, true, null, transactionType);
  2343. }
  2344. public Message ReceiveByLookupId(long lookupId)
  2345. {
  2346. return InternalReceiveByLookupId(true, MessageLookupAction.Current, lookupId, null, MessageQueueTransactionType.None);
  2347. }
  2348. public Message ReceiveByLookupId(MessageLookupAction action, long lookupId, MessageQueueTransactionType transactionType)
  2349. {
  2350. return InternalReceiveByLookupId(true, action, lookupId, null, transactionType);
  2351. }
  2352. public Message ReceiveByLookupId(MessageLookupAction action, long lookupId, MessageQueueTransaction transaction)
  2353. {
  2354. return InternalReceiveByLookupId(true, action, lookupId, transaction, MessageQueueTransactionType.None);
  2355. }
  2356. public Message PeekByLookupId(long lookupId)
  2357. {
  2358. return InternalReceiveByLookupId(false, MessageLookupAction.Current, lookupId, null, MessageQueueTransactionType.None);
  2359. }
  2360. public Message PeekByLookupId(MessageLookupAction action, long lookupId)
  2361. {
  2362. return InternalReceiveByLookupId(false, action, lookupId, null, MessageQueueTransactionType.None);
  2363. }
  2364. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.InternalReceiveByLookupId"]/*' />
  2365. /// <internalonly/>
  2366. internal unsafe Message InternalReceiveByLookupId(bool receive, MessageLookupAction lookupAction, long lookupId,
  2367. MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
  2368. {
  2369. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2370. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2371. if (!ValidationUtility.ValidateMessageLookupAction(lookupAction))
  2372. throw new InvalidEnumArgumentException("action", (int)lookupAction, typeof(MessageLookupAction));
  2373. if (!Msmq3OrNewer)
  2374. throw new PlatformNotSupportedException(Res.GetString(Res.PlatformNotSupported));
  2375. int action;
  2376. if (receive)
  2377. {
  2378. action = NativeMethods.LOOKUP_RECEIVE_MASK | (int)lookupAction;
  2379. }
  2380. else
  2381. {
  2382. action = NativeMethods.LOOKUP_PEEK_MASK | (int)lookupAction;
  2383. }
  2384. MessagePropertyFilter filter = MessageReadPropertyFilter;
  2385. int status = 0;
  2386. Message receiveMessage = null;
  2387. MessagePropertyVariants.MQPROPS lockedReceiveMessage = null;
  2388. if (filter != null)
  2389. {
  2390. receiveMessage = new Message((MessagePropertyFilter)filter.Clone());
  2391. receiveMessage.SetLookupId(lookupId);
  2392. if (this.formatter != null)
  2393. receiveMessage.Formatter = (IMessageFormatter)this.formatter.Clone();
  2394. lockedReceiveMessage = receiveMessage.Lock();
  2395. }
  2396. try
  2397. {
  2398. if ((internalTransaction != null) && receive)
  2399. status = StaleSafeReceiveByLookupId(lookupId, action, lockedReceiveMessage, null, null, internalTransaction.BeginQueueOperation());
  2400. else
  2401. status = StaleSafeReceiveByLookupId(lookupId, action, lockedReceiveMessage, null, null, (IntPtr)transactionType);
  2402. if (receiveMessage != null)
  2403. {
  2404. //Need to keep trying until enough space has been allocated.
  2405. //Concurrent scenarions might not succeed on the second retry.
  2406. while (MessageQueue.IsMemoryError(status))
  2407. {
  2408. receiveMessage.Unlock();
  2409. receiveMessage.AdjustMemory();
  2410. lockedReceiveMessage = receiveMessage.Lock();
  2411. if ((internalTransaction != null) && receive)
  2412. status = StaleSafeReceiveByLookupId(lookupId, action, lockedReceiveMessage, null, null, internalTransaction.InnerTransaction);
  2413. else
  2414. status = StaleSafeReceiveByLookupId(lookupId, action, lockedReceiveMessage, null, null, (IntPtr)transactionType);
  2415. }
  2416. receiveMessage.Unlock();
  2417. }
  2418. }
  2419. finally
  2420. {
  2421. if ((internalTransaction != null) && receive)
  2422. internalTransaction.EndQueueOperation();
  2423. }
  2424. if (status == (int)MessageQueueErrorCode.MessageNotFound)
  2425. throw new InvalidOperationException(Res.GetString("MessageNotFound"));
  2426. if (MessageQueue.IsFatalError(status))
  2427. throw new MessageQueueException(status);
  2428. return receiveMessage;
  2429. }
  2430. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ReceiveCurrent"]/*' />
  2431. /// <internalonly/>
  2432. internal unsafe Message ReceiveCurrent(TimeSpan timeout, int action, CursorHandle cursor, MessagePropertyFilter filter, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
  2433. {
  2434. long timeoutInMilliseconds = (long)timeout.TotalMilliseconds;
  2435. if (timeoutInMilliseconds < 0 || timeoutInMilliseconds > UInt32.MaxValue)
  2436. throw new ArgumentException(Res.GetString(Res.InvalidParameter, "timeout", timeout.ToString()));
  2437. int status = 0;
  2438. Message receiveMessage = null;
  2439. MessagePropertyVariants.MQPROPS lockedReceiveMessage = null;
  2440. if (filter != null)
  2441. {
  2442. receiveMessage = new Message((MessagePropertyFilter)filter.Clone());
  2443. if (this.formatter != null)
  2444. receiveMessage.Formatter = (IMessageFormatter)this.formatter.Clone();
  2445. lockedReceiveMessage = receiveMessage.Lock();
  2446. }
  2447. try
  2448. {
  2449. if (internalTransaction != null)
  2450. status = StaleSafeReceiveMessage((uint)timeoutInMilliseconds, action, lockedReceiveMessage, null, null, cursor, internalTransaction.BeginQueueOperation());
  2451. else
  2452. status = StaleSafeReceiveMessage((uint)timeoutInMilliseconds, action, lockedReceiveMessage, null, null, cursor, (IntPtr)transactionType);
  2453. if (receiveMessage != null)
  2454. {
  2455. //Need to keep trying until enough space has been allocated.
  2456. //Concurrent scenarions might not succeed on the second retry.
  2457. while (MessageQueue.IsMemoryError(status))
  2458. {
  2459. // Need to special-case retrying PeekNext after a buffer overflow
  2460. // by using PeekCurrent on retries since otherwise MSMQ will
  2461. // advance the cursor, skipping messages
  2462. if (action == NativeMethods.QUEUE_ACTION_PEEK_NEXT)
  2463. action = NativeMethods.QUEUE_ACTION_PEEK_CURRENT;
  2464. receiveMessage.Unlock();
  2465. receiveMessage.AdjustMemory();
  2466. lockedReceiveMessage = receiveMessage.Lock();
  2467. if (internalTransaction != null)
  2468. status = StaleSafeReceiveMessage((uint)timeoutInMilliseconds, action, lockedReceiveMessage, null, null, cursor, internalTransaction.InnerTransaction);
  2469. else
  2470. status = StaleSafeReceiveMessage((uint)timeoutInMilliseconds, action, lockedReceiveMessage, null, null, cursor, (IntPtr)transactionType);
  2471. }
  2472. }
  2473. }
  2474. finally
  2475. {
  2476. if (receiveMessage != null)
  2477. receiveMessage.Unlock();
  2478. if (internalTransaction != null)
  2479. internalTransaction.EndQueueOperation();
  2480. }
  2481. if (MessageQueue.IsFatalError(status))
  2482. throw new MessageQueueException(status);
  2483. return receiveMessage;
  2484. }
  2485. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Refresh"]/*' />
  2486. /// <devdoc>
  2487. /// <para>
  2488. /// Refreshes the properties presented by the <see cref='System.Messaging.MessageQueue'/>
  2489. /// to reflect the current state of the
  2490. /// resource.
  2491. /// </para>
  2492. /// </devdoc>
  2493. //
  2494. public void Refresh()
  2495. {
  2496. this.PropertyFilter.ClearAll();
  2497. }
  2498. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SaveQueueProperties"]/*' />
  2499. /// <internalonly/>
  2500. private void SaveQueueProperties()
  2501. {
  2502. int status = UnsafeNativeMethods.MQSetQueueProperties(FormatName, Properties.Lock());
  2503. Properties.Unlock();
  2504. if (MessageQueue.IsFatalError(status))
  2505. throw new MessageQueueException(status);
  2506. }
  2507. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send"]/*' />
  2508. /// <devdoc>
  2509. /// <para>
  2510. /// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
  2511. /// . The object is serialized
  2512. /// using the formatter provided.
  2513. /// </para>
  2514. /// </devdoc>
  2515. public void Send(object obj)
  2516. {
  2517. SendInternal(obj, null, MessageQueueTransactionType.None);
  2518. }
  2519. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send1"]/*' />
  2520. /// <devdoc>
  2521. /// <para>
  2522. /// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
  2523. /// . The object is serialized
  2524. /// using the formatter provided.
  2525. /// </para>
  2526. /// </devdoc>
  2527. public void Send(object obj, MessageQueueTransaction transaction)
  2528. {
  2529. if (transaction == null)
  2530. throw new ArgumentNullException("transaction");
  2531. SendInternal(obj, transaction, MessageQueueTransactionType.None);
  2532. }
  2533. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send5"]/*' />
  2534. /// <devdoc>
  2535. /// <para>
  2536. /// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>
  2537. /// . The object is serialized
  2538. /// using the formatter provided.
  2539. /// </para>
  2540. /// </devdoc>
  2541. public void Send(object obj, MessageQueueTransactionType transactionType)
  2542. {
  2543. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2544. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2545. SendInternal(obj, null, transactionType);
  2546. }
  2547. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send2"]/*' />
  2548. /// <devdoc>
  2549. /// <para>
  2550. /// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>.
  2551. /// The object will be serialized
  2552. /// using the formatter provided.
  2553. /// </para>
  2554. /// </devdoc>
  2555. public void Send(object obj, string label)
  2556. {
  2557. Send(obj, label, null, MessageQueueTransactionType.None);
  2558. }
  2559. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send3"]/*' />
  2560. /// <devdoc>
  2561. /// <para>
  2562. /// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>.
  2563. /// The object will be serialized
  2564. /// using the formatter provided.
  2565. /// </para>
  2566. /// </devdoc>
  2567. public void Send(object obj, string label, MessageQueueTransaction transaction)
  2568. {
  2569. if (transaction == null)
  2570. throw new ArgumentNullException("transaction");
  2571. Send(obj, label, transaction, MessageQueueTransactionType.None);
  2572. }
  2573. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.Send4"]/*' />
  2574. /// <devdoc>
  2575. /// <para>
  2576. /// Sends an object to the queue referenced by this <see cref='System.Messaging.MessageQueue'/>.
  2577. /// The object will be serialized
  2578. /// using the formatter provided.
  2579. /// </para>
  2580. /// </devdoc>
  2581. public void Send(object obj, string label, MessageQueueTransactionType transactionType)
  2582. {
  2583. if (!ValidationUtility.ValidateMessageQueueTransactionType(transactionType))
  2584. throw new InvalidEnumArgumentException("transactionType", (int)transactionType, typeof(MessageQueueTransactionType));
  2585. Send(obj, label, null, transactionType);
  2586. }
  2587. private void Send(object obj, string label, MessageQueueTransaction transaction, MessageQueueTransactionType transactionType)
  2588. {
  2589. if (label == null)
  2590. throw new ArgumentNullException("label");
  2591. if (obj is Message)
  2592. {
  2593. ((Message)obj).Label = label;
  2594. SendInternal(obj, transaction, transactionType);
  2595. }
  2596. else
  2597. {
  2598. string oldLabel = this.DefaultPropertiesToSend.Label;
  2599. try
  2600. {
  2601. this.DefaultPropertiesToSend.Label = label;
  2602. SendInternal(obj, transaction, transactionType);
  2603. }
  2604. finally
  2605. {
  2606. this.DefaultPropertiesToSend.Label = oldLabel;
  2607. }
  2608. }
  2609. }
  2610. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.SendInternal"]/*' />
  2611. /// <internalonly/>
  2612. private void SendInternal(object obj, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType)
  2613. {
  2614. Message message = null;
  2615. if (obj is Message)
  2616. message = (Message)obj;
  2617. if (message == null)
  2618. {
  2619. message = this.DefaultPropertiesToSend.CachedMessage;
  2620. message.Formatter = this.Formatter;
  2621. message.Body = obj;
  2622. }
  2623. //Write cached properties and if message is being forwarded Clear queue specific properties
  2624. int status = 0;
  2625. message.AdjustToSend();
  2626. MessagePropertyVariants.MQPROPS properties = message.Lock();
  2627. try
  2628. {
  2629. if (internalTransaction != null)
  2630. status = StaleSafeSendMessage(properties, internalTransaction.BeginQueueOperation());
  2631. else
  2632. status = StaleSafeSendMessage(properties, (IntPtr)transactionType);
  2633. }
  2634. finally
  2635. {
  2636. message.Unlock();
  2637. if (internalTransaction != null)
  2638. internalTransaction.EndQueueOperation();
  2639. }
  2640. if (MessageQueue.IsFatalError(status))
  2641. throw new MessageQueueException(status);
  2642. }
  2643. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ResolveQueueFromLabel"]/*' />
  2644. /// <internalonly/>
  2645. private static MessageQueue ResolveQueueFromLabel(string path, bool throwException)
  2646. {
  2647. MessageQueue[] queues = GetPublicQueuesByLabel(path.Substring(PREFIX_LABEL.Length), false);
  2648. if (queues.Length == 0)
  2649. {
  2650. if (throwException)
  2651. throw new InvalidOperationException(Res.GetString(Res.InvalidLabel, path.Substring(PREFIX_LABEL.Length)));
  2652. return null;
  2653. }
  2654. else if (queues.Length > 1)
  2655. throw new InvalidOperationException(Res.GetString(Res.AmbiguousLabel, path.Substring(PREFIX_LABEL.Length)));
  2656. return queues[0];
  2657. }
  2658. /// <internalonly/>
  2659. private static string ResolveFormatNameFromQueuePath(string queuePath, bool throwException)
  2660. {
  2661. string machine = queuePath.Substring(0, queuePath.IndexOf('\\'));
  2662. //The name includes the \\
  2663. string name = queuePath.Substring(queuePath.IndexOf('\\'));
  2664. //Check for machine DeadLetter or Journal
  2665. if (String.Compare(name, SUFIX_DEADLETTER, true, CultureInfo.InvariantCulture) == 0 ||
  2666. String.Compare(name, SUFIX_DEADXACT, true, CultureInfo.InvariantCulture) == 0 ||
  2667. String.Compare(name, SUFIX_JOURNAL, true, CultureInfo.InvariantCulture) == 0)
  2668. {
  2669. //Need to get the machine Id to construct the format name.
  2670. if (machine.CompareTo(".") == 0)
  2671. machine = MessageQueue.ComputerName;
  2672. //Create a guid to get the right format.
  2673. Guid machineId = MessageQueue.GetMachineId(machine);
  2674. StringBuilder newFormatName = new StringBuilder();
  2675. //System format names:
  2676. //MACHINE=guid;DEADXACT
  2677. //MACHINE=guid;DEADLETTER
  2678. //MACHINE=guid;JOURNAL
  2679. newFormatName.Append("MACHINE=");
  2680. newFormatName.Append(machineId.ToString());
  2681. if (String.Compare(name, SUFIX_DEADXACT, true, CultureInfo.InvariantCulture) == 0)
  2682. newFormatName.Append(";DEADXACT");
  2683. else if (String.Compare(name, SUFIX_DEADLETTER, true, CultureInfo.InvariantCulture) == 0)
  2684. newFormatName.Append(";DEADLETTER");
  2685. else
  2686. newFormatName.Append(";JOURNAL");
  2687. return newFormatName.ToString();
  2688. }
  2689. else
  2690. {
  2691. string realPath = queuePath;
  2692. bool journal = false;
  2693. if (queuePath.ToUpper(CultureInfo.InvariantCulture).EndsWith(SUFIX_JOURNAL))
  2694. {
  2695. journal = true;
  2696. int lastIndex = realPath.LastIndexOf('\\');
  2697. realPath = realPath.Substring(0, lastIndex);
  2698. }
  2699. int result;
  2700. int status = 0;
  2701. StringBuilder newFormatName = new StringBuilder(NativeMethods.MAX_LABEL_LEN);
  2702. result = NativeMethods.MAX_LABEL_LEN;
  2703. status = SafeNativeMethods.MQPathNameToFormatName(realPath, newFormatName, ref result);
  2704. if (status != 0)
  2705. {
  2706. if (throwException)
  2707. throw new MessageQueueException(status);
  2708. else if (status == (int)MessageQueueErrorCode.IllegalQueuePathName)
  2709. throw new MessageQueueException(status);
  2710. return null;
  2711. }
  2712. if (journal)
  2713. newFormatName.Append(";JOURNAL");
  2714. return newFormatName.ToString();
  2715. }
  2716. }
  2717. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.ValidatePath"]/*' />
  2718. /// <internalonly/>
  2719. internal static bool ValidatePath(string path, bool checkQueueNameSize)
  2720. {
  2721. if (path == null || path.Length == 0)
  2722. return true;
  2723. String upperPath = path.ToUpper(CultureInfo.InvariantCulture);
  2724. if (upperPath.StartsWith(PREFIX_LABEL))
  2725. return true;
  2726. if (upperPath.StartsWith(PREFIX_FORMAT_NAME))
  2727. return true;
  2728. int number = 0;
  2729. int index = -1;
  2730. while (true)
  2731. {
  2732. int newIndex = upperPath.IndexOf('\\', index + 1);
  2733. if (newIndex == -1)
  2734. break;
  2735. else
  2736. index = newIndex;
  2737. ++number;
  2738. }
  2739. if (number == 1)
  2740. {
  2741. if (checkQueueNameSize)
  2742. {
  2743. long length = path.Length - (index + 1);
  2744. if (length > 255)
  2745. throw new ArgumentException(Res.GetString(Res.LongQueueName));
  2746. }
  2747. return true;
  2748. }
  2749. if (number == 2)
  2750. {
  2751. if (upperPath.EndsWith(SUFIX_JOURNAL))
  2752. return true;
  2753. index = upperPath.LastIndexOf(SUFIX_PRIVATE + "\\");
  2754. if (index != -1)
  2755. return true;
  2756. }
  2757. if (number == 3 && upperPath.EndsWith(SUFIX_JOURNAL))
  2758. {
  2759. index = upperPath.LastIndexOf(SUFIX_PRIVATE + "\\");
  2760. if (index != -1)
  2761. return true;
  2762. }
  2763. return false;
  2764. }
  2765. /// <internalonly/>
  2766. internal void SetAccessMode(QueueAccessMode accessMode)
  2767. {
  2768. //
  2769. // this method should only be called from a constructor.
  2770. // we dont support changing queue access mode after contruction time.
  2771. //
  2772. if (!ValidationUtility.ValidateQueueAccessMode(accessMode))
  2773. throw new InvalidEnumArgumentException("accessMode", (int)accessMode, typeof(QueueAccessMode));
  2774. this.accessMode = accessMode;
  2775. }
  2776. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.QueuePropertyFilter"]/*' />
  2777. /// <internalonly/>
  2778. private class QueuePropertyFilter
  2779. {
  2780. public bool Authenticate;
  2781. public bool BasePriority;
  2782. public bool CreateTime;
  2783. public bool EncryptionLevel;
  2784. public bool Id;
  2785. // disable csharp compiler warning #0414: field assigned unused value
  2786. #pragma warning disable 0414
  2787. public bool Transactional;
  2788. #pragma warning restore 0414
  2789. public bool Label;
  2790. public bool LastModifyTime;
  2791. public bool MaximumJournalSize;
  2792. public bool MaximumQueueSize;
  2793. public bool MulticastAddress;
  2794. // disable csharp compiler warning #0414: field assigned unused value
  2795. #pragma warning disable 0414
  2796. public bool Path;
  2797. #pragma warning restore 0414
  2798. public bool Category;
  2799. public bool UseJournalQueue;
  2800. public void ClearAll()
  2801. {
  2802. Authenticate = false;
  2803. BasePriority = false;
  2804. CreateTime = false;
  2805. EncryptionLevel = false;
  2806. Id = false;
  2807. Transactional = false;
  2808. Label = false;
  2809. LastModifyTime = false;
  2810. MaximumJournalSize = false;
  2811. MaximumQueueSize = false;
  2812. Path = false;
  2813. Category = false;
  2814. UseJournalQueue = false;
  2815. MulticastAddress = false;
  2816. }
  2817. }
  2818. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest"]/*' />
  2819. /// <devdoc>
  2820. /// This class is used in asynchronous operations,
  2821. /// it keeps the context under which the asynchronous
  2822. /// request was posted.
  2823. /// </devdoc>
  2824. /// <internalonly/>
  2825. private class AsynchronousRequest : IAsyncResult
  2826. {
  2827. private IOCompletionCallback onCompletionStatusChanged;
  2828. private SafeNativeMethods.ReceiveCallback onMessageReceived;
  2829. private AsyncCallback callback;
  2830. private ManualResetEvent resetEvent;
  2831. private object asyncState;
  2832. private MessageQueue owner;
  2833. private bool isCompleted = false;
  2834. private int status = 0;
  2835. private Message message;
  2836. private int action;
  2837. private uint timeout;
  2838. private CursorHandle cursorHandle;
  2839. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.AsynchronousRequest"]/*' />
  2840. /// <devdoc>
  2841. /// Creates a new asynchronous request that
  2842. /// represents a pending asynchronous operation.
  2843. /// </devdoc>
  2844. /// <internalonly/>
  2845. internal unsafe AsynchronousRequest(MessageQueue owner, uint timeout, CursorHandle cursorHandle, int action, bool useThreadPool, object asyncState, AsyncCallback callback)
  2846. {
  2847. this.owner = owner;
  2848. this.asyncState = asyncState;
  2849. this.callback = callback;
  2850. this.action = action;
  2851. this.timeout = timeout;
  2852. this.resetEvent = new ManualResetEvent(false);
  2853. this.cursorHandle = cursorHandle;
  2854. if (!useThreadPool)
  2855. this.onMessageReceived = new SafeNativeMethods.ReceiveCallback(this.OnMessageReceived);
  2856. else
  2857. this.onCompletionStatusChanged = new IOCompletionCallback(this.OnCompletionStatusChanged);
  2858. }
  2859. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.Action"]/*' />
  2860. /// <internalonly/>
  2861. internal int Action
  2862. {
  2863. get
  2864. {
  2865. return this.action;
  2866. }
  2867. }
  2868. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.AsyncState"]/*' />
  2869. /// <devdoc>
  2870. /// IAsyncResult implementation
  2871. /// </devdoc>
  2872. public object AsyncState
  2873. {
  2874. get
  2875. {
  2876. return this.asyncState;
  2877. }
  2878. }
  2879. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.AsyncWaitHandle"]/*' />
  2880. /// <devdoc>
  2881. /// IAsyncResult implementation
  2882. /// </devdoc>
  2883. public WaitHandle AsyncWaitHandle
  2884. {
  2885. get
  2886. {
  2887. return this.resetEvent;
  2888. }
  2889. }
  2890. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.CompletedSynchronously"]/*' />
  2891. /// <devdoc>
  2892. /// IAsyncResult implementation
  2893. /// </devdoc>
  2894. public bool CompletedSynchronously
  2895. {
  2896. get
  2897. {
  2898. return false;
  2899. }
  2900. }
  2901. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.IsCompleted"]/*' />
  2902. /// <devdoc>
  2903. /// IAsyncResult implementation
  2904. /// </devdoc>
  2905. /// <internalonly/>
  2906. public bool IsCompleted
  2907. {
  2908. get
  2909. {
  2910. return this.isCompleted;
  2911. }
  2912. }
  2913. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.BeginRead"]/*' />
  2914. /// <devdoc>
  2915. /// Does the actual asynchronous receive posting.
  2916. /// </devdoc>
  2917. /// <internalonly/>
  2918. internal unsafe void BeginRead()
  2919. {
  2920. NativeOverlapped* overlappedPointer = null;
  2921. if (this.onCompletionStatusChanged != null)
  2922. {
  2923. Overlapped overlapped = new Overlapped();
  2924. overlapped.AsyncResult = this;
  2925. overlappedPointer = overlapped.Pack(this.onCompletionStatusChanged, null);
  2926. }
  2927. int localStatus = 0;
  2928. this.message = new Message(owner.MessageReadPropertyFilter);
  2929. try
  2930. {
  2931. localStatus = this.owner.StaleSafeReceiveMessage(this.timeout, this.action, this.message.Lock(), overlappedPointer, this.onMessageReceived, this.cursorHandle, IntPtr.Zero);
  2932. while (MessageQueue.IsMemoryError(localStatus))
  2933. {
  2934. // Need to special-case retrying PeekNext after a buffer overflow
  2935. // by using PeekCurrent on retries since otherwise MSMQ will
  2936. // advance the cursor, skipping messages
  2937. if (this.action == NativeMethods.QUEUE_ACTION_PEEK_NEXT)
  2938. this.action = NativeMethods.QUEUE_ACTION_PEEK_CURRENT;
  2939. this.message.Unlock();
  2940. this.message.AdjustMemory();
  2941. localStatus = this.owner.StaleSafeReceiveMessage(this.timeout, this.action, this.message.Lock(), overlappedPointer, this.onMessageReceived, this.cursorHandle, IntPtr.Zero);
  2942. }
  2943. }
  2944. catch (Exception e)
  2945. {
  2946. // Here will would do all the cleanup that RaiseCompletionEvent does on failure path,
  2947. // but without raising completion event.
  2948. // This is to preserve pre-Whidbey Beta 2 behavior, when exception thrown from this method
  2949. // would prevent RaiseCompletionEvent from being called (and also leak resources)
  2950. this.message.Unlock();
  2951. if (overlappedPointer != null)
  2952. Overlapped.Free(overlappedPointer);
  2953. if (!this.owner.useThreadPool)
  2954. this.owner.OutstandingAsyncRequests.Remove(this);
  2955. throw e;
  2956. }
  2957. // NOTE: RaiseCompletionEvent is not in a finally block by design, for two reasons:
  2958. // 1) the contract of BeginRead is to throw exception and not to notify event handler.
  2959. // 2) we dont know what the value pf localStatus will be in case of exception
  2960. if (MessageQueue.IsFatalError(localStatus))
  2961. RaiseCompletionEvent(localStatus, overlappedPointer);
  2962. }
  2963. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.End"]/*' />
  2964. /// <devdoc>
  2965. /// Waits until the request has been completed.
  2966. /// </devdoc>
  2967. /// <internalonly/>
  2968. internal Message End()
  2969. {
  2970. this.resetEvent.WaitOne();
  2971. if (MessageQueue.IsFatalError(status))
  2972. throw new MessageQueueException(status);
  2973. if (this.owner.formatter != null)
  2974. this.message.Formatter = (IMessageFormatter)this.owner.formatter.Clone();
  2975. return this.message;
  2976. }
  2977. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.OnCompletionStatusChanged"]/*' />
  2978. /// <devdoc>
  2979. /// Thread pool IOCompletionPort bound callback.
  2980. /// </devdoc>
  2981. /// <internalonly/>
  2982. private unsafe void OnCompletionStatusChanged(uint errorCode, uint numBytes, NativeOverlapped* overlappedPointer)
  2983. {
  2984. int result = 0;
  2985. if (errorCode != 0)
  2986. {
  2987. // MSMQ does a hacky trick to return the operation
  2988. // result through the completion port.
  2989. // Microsoft Dec 2004. Bug 419155:
  2990. // NativeOverlapped.InternalLow returns IntPtr, which is 64 bits on a 64 bit platform.
  2991. // It contains MSMQ error code, which, when set to an error value, is outside of the int range
  2992. // Therefore, OverflowException is thrown in checked context.
  2993. // However, IntPtr (int) operator ALWAYS runs in checked context on 64 bit platforms.
  2994. // Therefore, we first cast to long to avoid OverflowException, and then cast to int
  2995. // in unchecked context
  2996. long msmqError = (long)overlappedPointer->InternalLow;
  2997. unchecked
  2998. {
  2999. result = (int)msmqError;
  3000. }
  3001. }
  3002. RaiseCompletionEvent(result, overlappedPointer);
  3003. }
  3004. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.OnMessageReceived"]/*' />
  3005. /// <devdoc>
  3006. /// MSMQ APC based callback.
  3007. /// </devdoc>
  3008. /// <internalonly/>
  3009. private unsafe void OnMessageReceived(int result, IntPtr handle, int timeout, int action, IntPtr propertiesPointer, NativeOverlapped* overlappedPointer, IntPtr cursorHandle)
  3010. {
  3011. RaiseCompletionEvent(result, overlappedPointer);
  3012. }
  3013. /// <include file='doc\MessageQueue.uex' path='docs/doc[@for="MessageQueue.AsynchronousRequest.RaiseCompletionEvent"]/*' />
  3014. /// <internalonly/>
  3015. // See comment explaining this SuppressMessage below
  3016. [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
  3017. private unsafe void RaiseCompletionEvent(int result, NativeOverlapped* overlappedPointer)
  3018. {
  3019. if (MessageQueue.IsMemoryError(result))
  3020. {
  3021. while (MessageQueue.IsMemoryError(result))
  3022. {
  3023. // Need to special-case retrying PeekNext after a buffer overflow
  3024. // by using PeekCurrent on retries since otherwise MSMQ will
  3025. // advance the cursor, skipping messages
  3026. if (this.action == NativeMethods.QUEUE_ACTION_PEEK_NEXT)
  3027. this.action = NativeMethods.QUEUE_ACTION_PEEK_CURRENT;
  3028. this.message.Unlock();
  3029. this.message.AdjustMemory();
  3030. try
  3031. {
  3032. // ReadHandle called from StaleSafeReceiveMessage can throw if the handle has been invalidated
  3033. // (for example, by closing it), and subsequent MQOpenQueue fails for some reason.
  3034. // Therefore catch exception (otherwise process will die) and propagate error
  3035. // Microsoft Jan 2006 (Whidbey bug 570055)
  3036. result = this.owner.StaleSafeReceiveMessage(this.timeout, this.action, this.message.Lock(), overlappedPointer, this.onMessageReceived, this.cursorHandle, IntPtr.Zero);
  3037. }
  3038. catch (MessageQueueException e)
  3039. {
  3040. result = (int)e.MessageQueueErrorCode;
  3041. break;
  3042. }
  3043. }
  3044. if (!MessageQueue.IsFatalError(result))
  3045. return;
  3046. }
  3047. this.message.Unlock();
  3048. if (this.owner.IsCashedInfoInvalidOnReceive(result))
  3049. {
  3050. this.owner.MQInfo.Close();
  3051. try
  3052. {
  3053. // For explanation of this try/catch, see comment above
  3054. result = this.owner.StaleSafeReceiveMessage(this.timeout, this.action, this.message.Lock(), overlappedPointer, this.onMessageReceived, this.cursorHandle, IntPtr.Zero);
  3055. }
  3056. catch (MessageQueueException e)
  3057. {
  3058. result = (int)e.MessageQueueErrorCode;
  3059. }
  3060. if (!MessageQueue.IsFatalError(result))
  3061. return;
  3062. }
  3063. this.status = result;
  3064. if (overlappedPointer != null)
  3065. Overlapped.Free(overlappedPointer);
  3066. this.isCompleted = true;
  3067. this.resetEvent.Set();
  3068. try
  3069. {
  3070. //
  3071. // 511878: The code below breaks the contract of ISynchronizeInvoke.
  3072. // We fixed it in 367076, but that fix resulted in a regression that is bug 511878.
  3073. // "Proper fix" for 511878 requires special-casing Form. That causes us to
  3074. // load System.Windows.Forms and System.Drawing,
  3075. // which were previously not loaded on this path.
  3076. // As only one customer complained about 367076, we decided to revert to
  3077. // Everett behavior
  3078. //
  3079. if (this.owner.SynchronizingObject != null &&
  3080. this.owner.SynchronizingObject.InvokeRequired)
  3081. {
  3082. this.owner.SynchronizingObject.BeginInvoke(this.callback, new object[] { this });
  3083. }
  3084. else
  3085. this.callback(this);
  3086. }
  3087. catch (Exception)
  3088. {
  3089. // Microsoft, Dec 2004: ----ing exceptions here is a serious bug.
  3090. // However, it would be a breaking change to remove this catch,
  3091. // therefore we decided to preserve the existing behavior
  3092. }
  3093. finally
  3094. {
  3095. if (!this.owner.useThreadPool)
  3096. {
  3097. Debug.Assert(this.owner.OutstandingAsyncRequests.Contains(this));
  3098. this.owner.OutstandingAsyncRequests.Remove(this);
  3099. }
  3100. }
  3101. }
  3102. }
  3103. private int StaleSafePurgeQueue()
  3104. {
  3105. int status = UnsafeNativeMethods.MQPurgeQueue(MQInfo.ReadHandle);
  3106. if (status == (int)MessageQueueErrorCode.StaleHandle || status == (int)MessageQueueErrorCode.QueueDeleted)
  3107. {
  3108. MQInfo.Close();
  3109. status = UnsafeNativeMethods.MQPurgeQueue(MQInfo.ReadHandle);
  3110. }
  3111. return status;
  3112. }
  3113. private int StaleSafeSendMessage(MessagePropertyVariants.MQPROPS properties, IntPtr transaction)
  3114. {
  3115. //
  3116. // TransactionType.Automatic uses current System.Transactions transaction, if one is available;
  3117. // otherwise, it passes Automatic to MSMQ to support COM+ transactions
  3118. // NOTE: Need careful qualification of class names,
  3119. // since ITransaction is defined by System.Messaging.Interop, System.Transactions and System.EnterpriseServices
  3120. //
  3121. if ((MessageQueueTransactionType)transaction == MessageQueueTransactionType.Automatic)
  3122. {
  3123. Transaction tx = Transaction.Current;
  3124. if (tx != null)
  3125. {
  3126. IDtcTransaction ntx =
  3127. TransactionInterop.GetDtcTransaction(tx);
  3128. return StaleSafeSendMessage(properties, (ITransaction)ntx);
  3129. }
  3130. }
  3131. int status = UnsafeNativeMethods.MQSendMessage(MQInfo.WriteHandle, properties, transaction);
  3132. if (status == (int)MessageQueueErrorCode.StaleHandle || status == (int)MessageQueueErrorCode.QueueDeleted)
  3133. {
  3134. MQInfo.Close();
  3135. status = UnsafeNativeMethods.MQSendMessage(MQInfo.WriteHandle, properties, transaction);
  3136. }
  3137. return status;
  3138. }
  3139. private int StaleSafeSendMessage(MessagePropertyVariants.MQPROPS properties, ITransaction transaction)
  3140. {
  3141. int status = UnsafeNativeMethods.MQSendMessage(MQInfo.WriteHandle, properties, transaction);
  3142. if (status == (int)MessageQueueErrorCode.StaleHandle || status == (int)MessageQueueErrorCode.QueueDeleted)
  3143. {
  3144. MQInfo.Close();
  3145. status = UnsafeNativeMethods.MQSendMessage(MQInfo.WriteHandle, properties, transaction);
  3146. }
  3147. return status;
  3148. }
  3149. internal unsafe int StaleSafeReceiveMessage(uint timeout, int action, MessagePropertyVariants.MQPROPS properties, NativeOverlapped* overlapped,
  3150. SafeNativeMethods.ReceiveCallback receiveCallback, CursorHandle cursorHandle, IntPtr transaction)
  3151. {
  3152. //
  3153. // TransactionType.Automatic uses current System.Transactions transaction, if one is available;
  3154. // otherwise, it passes Automatic to MSMQ to support COM+ transactions
  3155. // NOTE: Need careful qualification of class names,
  3156. // since ITransaction is defined by System.Messaging.Interop, System.Transactions and System.EnterpriseServices
  3157. //
  3158. if ((MessageQueueTransactionType)transaction == MessageQueueTransactionType.Automatic)
  3159. {
  3160. Transaction tx = Transaction.Current;
  3161. if (tx != null)
  3162. {
  3163. IDtcTransaction ntx =
  3164. TransactionInterop.GetDtcTransaction(tx);
  3165. return StaleSafeReceiveMessage(timeout, action, properties, overlapped, receiveCallback, cursorHandle, (ITransaction)ntx);
  3166. }
  3167. }
  3168. int status = UnsafeNativeMethods.MQReceiveMessage(MQInfo.ReadHandle, timeout, action, properties, overlapped, receiveCallback, cursorHandle, transaction);
  3169. if (IsCashedInfoInvalidOnReceive(status))
  3170. {
  3171. MQInfo.Close(); //invalidate cached ReadHandle, so it will be refreshed on next access
  3172. status = UnsafeNativeMethods.MQReceiveMessage(MQInfo.ReadHandle, timeout, action, properties, overlapped, receiveCallback, cursorHandle, transaction);
  3173. }
  3174. return status;
  3175. }
  3176. private unsafe int StaleSafeReceiveMessage(uint timeout, int action, MessagePropertyVariants.MQPROPS properties, NativeOverlapped* overlapped,
  3177. SafeNativeMethods.ReceiveCallback receiveCallback, CursorHandle cursorHandle, ITransaction transaction)
  3178. {
  3179. int status = UnsafeNativeMethods.MQReceiveMessage(MQInfo.ReadHandle, timeout, action, properties, overlapped, receiveCallback, cursorHandle, transaction);
  3180. if (IsCashedInfoInvalidOnReceive(status))
  3181. {
  3182. MQInfo.Close(); //invalidate cached ReadHandle, so it will be refreshed on next access
  3183. status = UnsafeNativeMethods.MQReceiveMessage(MQInfo.ReadHandle, timeout, action, properties, overlapped, receiveCallback, cursorHandle, transaction);
  3184. }
  3185. return status;
  3186. }
  3187. private unsafe int StaleSafeReceiveByLookupId(long lookupId, int action, MessagePropertyVariants.MQPROPS properties,
  3188. NativeOverlapped* overlapped, SafeNativeMethods.ReceiveCallback receiveCallback, IntPtr transaction)
  3189. {
  3190. if ((MessageQueueTransactionType)transaction == MessageQueueTransactionType.Automatic)
  3191. {
  3192. Transaction tx = Transaction.Current;
  3193. if (tx != null)
  3194. {
  3195. IDtcTransaction ntx =
  3196. TransactionInterop.GetDtcTransaction(tx);
  3197. return StaleSafeReceiveByLookupId(lookupId, action, properties, overlapped, receiveCallback, (ITransaction)ntx);
  3198. }
  3199. }
  3200. int status = UnsafeNativeMethods.MQReceiveMessageByLookupId(MQInfo.ReadHandle, lookupId, action, properties, overlapped, receiveCallback, transaction);
  3201. if (IsCashedInfoInvalidOnReceive(status))
  3202. {
  3203. MQInfo.Close(); //invalidate cached ReadHandle, so it will be refreshed on next access
  3204. status = UnsafeNativeMethods.MQReceiveMessageByLookupId(MQInfo.ReadHandle, lookupId, action, properties, overlapped, receiveCallback, transaction);
  3205. }
  3206. return status;
  3207. }
  3208. private unsafe int StaleSafeReceiveByLookupId(long lookupId, int action, MessagePropertyVariants.MQPROPS properties,
  3209. NativeOverlapped* overlapped, SafeNativeMethods.ReceiveCallback receiveCallback, ITransaction transaction)
  3210. {
  3211. int status = UnsafeNativeMethods.MQReceiveMessageByLookupId(MQInfo.ReadHandle, lookupId, action, properties, overlapped, receiveCallback, transaction);
  3212. if (IsCashedInfoInvalidOnReceive(status))
  3213. {
  3214. MQInfo.Close(); //invalidate cached ReadHandle, so it will be refreshed on next access
  3215. status = UnsafeNativeMethods.MQReceiveMessageByLookupId(MQInfo.ReadHandle, lookupId, action, properties, overlapped, receiveCallback, transaction);
  3216. }
  3217. return status;
  3218. }
  3219. private bool IsCashedInfoInvalidOnReceive(int receiveResult)
  3220. {
  3221. // returns true if return code of ReceiveMessage indicates
  3222. // that cached handle used for receive has become invalid
  3223. return (receiveResult == (int)MessageQueueErrorCode.StaleHandle || //both qm and ac restarted
  3224. receiveResult == (int)MessageQueueErrorCode.InvalidHandle || //get this if ac is not restarted
  3225. receiveResult == (int)MessageQueueErrorCode.InvalidParameter); // get this on w2k
  3226. }
  3227. internal class CacheTable<Key, Value>
  3228. {
  3229. private Dictionary<Key, CacheEntry<Value>> table;
  3230. private ReaderWriterLock rwLock;
  3231. // used for debugging
  3232. private string name;
  3233. // when the number of entries in the hashtable gets larger than capacity,
  3234. // the "stale" entries are removed and capacity is reset to twice the number
  3235. // of remaining entries
  3236. private int capacity;
  3237. private int originalCapacity;
  3238. // time, in seconds, after which an entry is considerred stale (if the reference
  3239. // count is zero)
  3240. private TimeSpan staleTime;
  3241. public CacheTable(string name, int capacity, TimeSpan staleTime)
  3242. {
  3243. this.originalCapacity = capacity;
  3244. this.capacity = capacity;
  3245. this.staleTime = staleTime;
  3246. this.name = name;
  3247. this.rwLock = new ReaderWriterLock();
  3248. this.table = new Dictionary<Key, CacheEntry<Value>>();
  3249. }
  3250. public Value Get(Key key)
  3251. {
  3252. Value val = default(Value); // This keyword might change with C# compiler
  3253. rwLock.AcquireReaderLock(-1);
  3254. try
  3255. {
  3256. if (table.ContainsKey(key))
  3257. {
  3258. CacheEntry<Value> entry = table[key];
  3259. if (entry != null)
  3260. {
  3261. entry.timeStamp = DateTime.UtcNow;
  3262. val = entry.contents;
  3263. }
  3264. }
  3265. }
  3266. finally
  3267. {
  3268. rwLock.ReleaseReaderLock();
  3269. }
  3270. return val;
  3271. }
  3272. public void Put(Key key, Value val)
  3273. {
  3274. rwLock.AcquireWriterLock(-1);
  3275. try
  3276. {
  3277. if (val == null /* not Value.default - bug in C# compiler? */)
  3278. {
  3279. table[key] = null;
  3280. }
  3281. else
  3282. {
  3283. CacheEntry<Value> entry = null;
  3284. if (table.ContainsKey(key))
  3285. entry = table[key]; //which could be null also
  3286. if (entry == null)
  3287. {
  3288. entry = new CacheEntry<Value>();
  3289. table[key] = entry;
  3290. if (table.Count >= capacity)
  3291. {
  3292. ClearStale(staleTime);
  3293. }
  3294. }
  3295. entry.timeStamp = DateTime.UtcNow;
  3296. entry.contents = val;
  3297. }
  3298. }
  3299. finally
  3300. {
  3301. rwLock.ReleaseWriterLock();
  3302. }
  3303. }
  3304. public void Remove(Key key)
  3305. {
  3306. rwLock.AcquireWriterLock(-1);
  3307. try
  3308. {
  3309. if (table.ContainsKey(key))
  3310. table.Remove(key);
  3311. }
  3312. finally
  3313. {
  3314. rwLock.ReleaseWriterLock();
  3315. }
  3316. }
  3317. public void ClearStale(TimeSpan staleAge)
  3318. {
  3319. DateTime now = DateTime.UtcNow;
  3320. Dictionary<Key, CacheEntry<Value>> newTable = new Dictionary<Key, CacheEntry<Value>>();
  3321. rwLock.AcquireReaderLock(-1);
  3322. try
  3323. {
  3324. foreach (KeyValuePair<Key, CacheEntry<Value>> kv in table)
  3325. {
  3326. CacheEntry<Value> iterEntry = kv.Value;
  3327. // see if this entry is stale (ticks are 100 nano-sec.)
  3328. if (now - iterEntry.timeStamp < staleAge)
  3329. {
  3330. newTable[kv.Key] = kv.Value;
  3331. }
  3332. }
  3333. }
  3334. finally
  3335. {
  3336. rwLock.ReleaseReaderLock();
  3337. }
  3338. rwLock.AcquireWriterLock(-1);
  3339. table = newTable;
  3340. capacity = 2 * table.Count;
  3341. if (capacity < originalCapacity) capacity = originalCapacity;
  3342. rwLock.ReleaseWriterLock();
  3343. }
  3344. private class CacheEntry<T>
  3345. {
  3346. public T contents;
  3347. public DateTime timeStamp;
  3348. }
  3349. }
  3350. internal class MQCacheableInfo
  3351. {
  3352. // Double-checked locking pattern requires volatile for read/write synchronization
  3353. private volatile MessageQueueHandle readHandle = MessageQueueHandle.InvalidHandle;
  3354. // Double-checked locking pattern requires volatile for read/write synchronization
  3355. private volatile MessageQueueHandle writeHandle = MessageQueueHandle.InvalidHandle;
  3356. private bool isTransactional;
  3357. // Double-checked locking pattern requires volatile for read/write synchronization
  3358. private volatile bool isTransactional_valid = false;
  3359. // Double-checked locking pattern requires volatile for read/write synchronization
  3360. private volatile bool boundToThreadPool;
  3361. private string formatName;
  3362. private int shareMode;
  3363. private QueueAccessModeHolder accessMode;
  3364. private int refCount;
  3365. private bool disposed;
  3366. private object syncRoot = new object();
  3367. public MQCacheableInfo(string formatName, QueueAccessMode accessMode, int shareMode)
  3368. {
  3369. this.formatName = formatName;
  3370. this.shareMode = shareMode;
  3371. // For each accessMode, corresponding QueueAccessModeHolder is a singleton.
  3372. // Call factory method to return existing holder for this access mode,
  3373. // or make a new one if noone used this access mode before.
  3374. //
  3375. this.accessMode = QueueAccessModeHolder.GetQueueAccessModeHolder(accessMode);
  3376. }
  3377. public bool CanRead
  3378. {
  3379. get
  3380. {
  3381. if (!accessMode.CanRead())
  3382. return false;
  3383. if (readHandle.IsInvalid)
  3384. {
  3385. if (this.disposed)
  3386. throw new ObjectDisposedException(GetType().Name);
  3387. lock (this.syncRoot)
  3388. {
  3389. if (readHandle.IsInvalid)
  3390. {
  3391. MessageQueueHandle result;
  3392. int status = UnsafeNativeMethods.MQOpenQueue(this.formatName, accessMode.GetReadAccessMode(), shareMode, out result);
  3393. if (MessageQueue.IsFatalError(status))
  3394. return false;
  3395. readHandle = result;
  3396. }
  3397. }
  3398. }
  3399. return true;
  3400. }
  3401. }
  3402. public bool CanWrite
  3403. {
  3404. get
  3405. {
  3406. if (!accessMode.CanWrite())
  3407. return false;
  3408. if (writeHandle.IsInvalid)
  3409. {
  3410. if (this.disposed)
  3411. throw new ObjectDisposedException(GetType().Name);
  3412. lock (this.syncRoot)
  3413. {
  3414. if (writeHandle.IsInvalid)
  3415. {
  3416. MessageQueueHandle result;
  3417. int status = UnsafeNativeMethods.MQOpenQueue(this.formatName, accessMode.GetWriteAccessMode(), 0, out result);
  3418. if (MessageQueue.IsFatalError(status))
  3419. return false;
  3420. writeHandle = result;
  3421. }
  3422. }
  3423. }
  3424. return true;
  3425. }
  3426. }
  3427. public int RefCount
  3428. {
  3429. get
  3430. {
  3431. return this.refCount;
  3432. }
  3433. }
  3434. public MessageQueueHandle ReadHandle
  3435. {
  3436. get
  3437. {
  3438. if (readHandle.IsInvalid)
  3439. {
  3440. if (this.disposed)
  3441. throw new ObjectDisposedException(GetType().Name);
  3442. lock (this.syncRoot)
  3443. {
  3444. if (readHandle.IsInvalid)
  3445. {
  3446. MessageQueueHandle result;
  3447. int status = UnsafeNativeMethods.MQOpenQueue(this.formatName, accessMode.GetReadAccessMode(), shareMode, out result);
  3448. if (MessageQueue.IsFatalError(status))
  3449. throw new MessageQueueException(status);
  3450. readHandle = result;
  3451. }
  3452. }
  3453. }
  3454. return readHandle;
  3455. }
  3456. }
  3457. public MessageQueueHandle WriteHandle
  3458. {
  3459. get
  3460. {
  3461. if (writeHandle.IsInvalid)
  3462. {
  3463. if (this.disposed)
  3464. throw new ObjectDisposedException(GetType().Name);
  3465. lock (this.syncRoot)
  3466. {
  3467. if (writeHandle.IsInvalid)
  3468. {
  3469. MessageQueueHandle result;
  3470. int status = UnsafeNativeMethods.MQOpenQueue(this.formatName, accessMode.GetWriteAccessMode(), 0, out result);
  3471. if (MessageQueue.IsFatalError(status))
  3472. throw new MessageQueueException(status);
  3473. writeHandle = result;
  3474. }
  3475. }
  3476. }
  3477. return writeHandle;
  3478. }
  3479. }
  3480. public bool Transactional
  3481. {
  3482. get
  3483. {
  3484. if (!isTransactional_valid)
  3485. {
  3486. lock (this.syncRoot)
  3487. {
  3488. if (!isTransactional_valid)
  3489. {
  3490. QueuePropertyVariants props = new QueuePropertyVariants();
  3491. props.SetUI1(NativeMethods.QUEUE_PROPID_TRANSACTION, (byte)0);
  3492. int status = UnsafeNativeMethods.MQGetQueueProperties(formatName, props.Lock());
  3493. props.Unlock();
  3494. if (MessageQueue.IsFatalError(status))
  3495. throw new MessageQueueException(status);
  3496. this.isTransactional = (props.GetUI1(NativeMethods.QUEUE_PROPID_TRANSACTION) != NativeMethods.QUEUE_TRANSACTIONAL_NONE);
  3497. isTransactional_valid = true;
  3498. }
  3499. }
  3500. }
  3501. return isTransactional;
  3502. }
  3503. }
  3504. public void AddRef()
  3505. {
  3506. lock (this)
  3507. {
  3508. ++refCount;
  3509. }
  3510. }
  3511. public void BindToThreadPool()
  3512. {
  3513. if (!this.boundToThreadPool)
  3514. {
  3515. lock (this)
  3516. {
  3517. if (!this.boundToThreadPool)
  3518. {
  3519. ThreadPool.BindHandle(ReadHandle);
  3520. this.boundToThreadPool = true;
  3521. }
  3522. }
  3523. }
  3524. }
  3525. public void CloseIfNotReferenced()
  3526. {
  3527. lock (this)
  3528. {
  3529. if (RefCount == 0)
  3530. Close();
  3531. }
  3532. }
  3533. public void Close()
  3534. {
  3535. this.boundToThreadPool = false;
  3536. if (!this.writeHandle.IsInvalid)
  3537. {
  3538. lock (this.syncRoot)
  3539. {
  3540. if (!this.writeHandle.IsInvalid)
  3541. {
  3542. this.writeHandle.Close();
  3543. }
  3544. }
  3545. }
  3546. if (!this.readHandle.IsInvalid)
  3547. {
  3548. lock (this.syncRoot)
  3549. {
  3550. if (!this.readHandle.IsInvalid)
  3551. {
  3552. this.readHandle.Close();
  3553. }
  3554. }
  3555. }
  3556. }
  3557. public void Dispose()
  3558. {
  3559. Dispose(true);
  3560. GC.SuppressFinalize(this);
  3561. }
  3562. protected virtual void Dispose(bool disposing)
  3563. {
  3564. if (disposing)
  3565. {
  3566. this.Close();
  3567. }
  3568. this.disposed = true;
  3569. }
  3570. public void Release()
  3571. {
  3572. lock (this)
  3573. {
  3574. --refCount;
  3575. }
  3576. }
  3577. }
  3578. internal class QueueInfoKeyHolder
  3579. {
  3580. private string formatName;
  3581. private QueueAccessMode accessMode;
  3582. public QueueInfoKeyHolder(string formatName, QueueAccessMode accessMode)
  3583. {
  3584. this.formatName = formatName.ToUpper(CultureInfo.InvariantCulture);
  3585. this.accessMode = accessMode;
  3586. }
  3587. public override int GetHashCode()
  3588. {
  3589. return formatName.GetHashCode() + (int)accessMode;
  3590. }
  3591. public override bool Equals(object obj)
  3592. {
  3593. if (obj == null || GetType() != obj.GetType()) return false;
  3594. QueueInfoKeyHolder qik = (QueueInfoKeyHolder)obj;
  3595. return this.Equals(qik);
  3596. }
  3597. public bool Equals(QueueInfoKeyHolder qik)
  3598. {
  3599. if (qik == null) return false;
  3600. // string.Equals performs case-sensitive and culture-insensitive comparison
  3601. // we address case sensitivity by normalizing format name in the constructor
  3602. return ((this.accessMode == qik.accessMode) && this.formatName.Equals(qik.formatName));
  3603. }
  3604. }
  3605. }
  3606. }