// // // // // $Revision: 1965 $ // using System; using System.Collections.Generic; using System.Runtime.Remoting.Messaging; using System.Threading; namespace CustomSinks { class AsyncMessageResponseSink: IMessageSink { IMessage msgResponse; EventWaitHandle responseReceived = new EventWaitHandle(false, EventResetMode.ManualReset, "Waiting for response"); EventWaitHandle messageLoop; static List messageLoopsSTA = new List(); static object storeOneEventLock = new object(); static object invokeEventOnceLock = new object(); static EventForwarderEventArgs storedEvent; static EventWaitHandle recheckEventStatus = new EventWaitHandle(false, EventResetMode.AutoReset, "Waiting for remoting event to be handled"); static AsyncMessageResponseSink() { // We may want to invoke some events ourseves EventForwarder.EventReceived += new EventForwarderEventHandler(OnEventReceived); // From now on, OnEventReceived can be called at ANY time; even more times at once! } public AsyncMessageResponseSink() { if (Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA) { messageLoop = new EventWaitHandle(false, EventResetMode.AutoReset, "Waiting for message loop to be pumped"); lock (messageLoopsSTA) { messageLoopsSTA.Add(messageLoop); } } } public IMessage WaitForResponse() { // We are going to invoke events only if we are running on ApartmentState.STA if (Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA) { responseReceived.WaitOne(); } else { // Message loop: while (true) { Thread.Sleep(100); //WaitHandle.WaitAny(new WaitHandle[] {messageLoop, responseReceived}); //responseReceived.WaitOne(100, false); if (msgResponse != null) break; System.Windows.Forms.Application.DoEvents(); InvokeStoredEvent(); }; // We have got the response now lock (messageLoopsSTA) { messageLoopsSTA.Remove(messageLoop); } // We might be the last message loop - this would release the event recheckEventStatus.Set(); } return msgResponse; } // This function can be called at any time any number of times void InvokeStoredEvent() { lock (invokeEventOnceLock) { if (storedEvent != null) { storedEvent.InvokeEvent(); recheckEventStatus.Set(); } } } // This function can be called at any time any number of times static void OnEventReceived(object sender, EventForwarderEventArgs args) { lock (storeOneEventLock) // Store just one event at a time { while ((messageLoopsSTA.Count > 0) && // While there is someone who can invoke us (args.WasInvoked == false)) // and while the event was not invoked yet { // Store event storedEvent = args; // Pump all STA message loops lock (messageLoopsSTA) { foreach (EventWaitHandle loop in messageLoopsSTA) { loop.Set(); } } // Wait until we are told to check conditions again recheckEventStatus.WaitOne(); } } } IMessage IMessageSink.SyncProcessMessage(IMessage msg) { if (System.Threading.Thread.CurrentThread.Name == null) { System.Threading.Thread.CurrentThread.Name = "Response thread"; } Console.WriteLine("Remoting response: " + msg.Properties["__MethodName"]); msgResponse = msg; responseReceived.Set(); return msgResponse; } IMessageCtrl IMessageSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink) { return null; // Should not be called } IMessageSink IMessageSink.NextSink { get { return null; // Should not be called } } } }