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