Ejemplo n.º 1
0
        //copy this change it
        public List <ThreadMessage> GetAllByOwnerAndParentId(int ownerId, int ownerTypeId, int parentId)
        {
            List <ThreadMessage> allMessages = null;

            Action <SqlParameterCollection> inputParamDelegate = delegate(SqlParameterCollection paramCollection)
            {
                paramCollection.AddWithValue("@OwnerId", ownerId);
                paramCollection.AddWithValue("@OwnerTypeId", ownerTypeId);
                paramCollection.AddWithValue("@ParentId", parentId);
            };

            Action <IDataReader, short> singleRecMapper = delegate(IDataReader reader, short set)
            {
                ThreadMessage comment = MessageMapper(reader);

                if (allMessages == null)
                {
                    allMessages = new List <ThreadMessage>();
                }

                allMessages.Add(comment);
            };

            _dataProvider.ExecuteCmd("dbo.Comments_GetAllByOwnerIdOwnerTypeIdParentId", inputParamDelegate, singleRecMapper);

            return(allMessages);
        }
Ejemplo n.º 2
0
        /************************************************************************************/
        /// <summary>
        ///
        /// </summary>
        /// <param name="NewEvent"></param>
        public bool PostMessage(ThreadMessage NewEvent)
        {
            if (null == NewEvent)
            {
                return(false);
            }

            lock (m_Lock)
            {
                // First thing is check if the thread is even in a position to take messages.
                if (!m_bAcceptNewMessages)
                {
                    return(false);
                }

                NewEvent.m_PostLocalTime = DateTime.Now;
                m_MessageQueue.Enqueue(NewEvent);

                // Only set the event when transitioning from 0 to 1 total item(s).
                // This spares us a kernel call.
                if (m_MessageQueue.Count == 1)
                {
                    m_QueueFilledEvent.Set();
                }
            }
            return(true);
        }
Ejemplo n.º 3
0
        private async Task DeleteMessageInThread(ModMailThread thread, ThreadMessage message, bool deleteMessage = true)
        {
            var bot   = Global.Bot;
            var guild = bot.GetGuild(Global.ServerID);
            var user  = guild.GetUser(thread.UserId);

            if (user == null)
            {
                throw new Exception("User was not found. Probably left the guild.");
            }
            var        channelObj    = guild.GetTextChannel(thread.ChannelId);
            IDMChannel userDmChannel = await user.GetOrCreateDMChannelAsync();

            IMessage rawChannelMessage = await channelObj.GetMessageAsync(message.ChannelMessageId);

            if (deleteMessage)
            {
                await rawChannelMessage.DeleteAsync();
            }

            IMessage rawDmMessage = await userDmChannel.GetMessageAsync(message.UserMessageId);

            await rawDmMessage.DeleteAsync();

            using (var db = new Database()){
                db.ThreadMessages.Remove(message);
                db.SaveChanges();
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="tm"></param>
        /// <returns></returns>
        public static DomingoBlError AddToThread(ThreadMessage tm)
        {
            try
            {
                using (TravelogyDevEntities1 context = new TravelogyDevEntities1())
                {
                    // update the MostRecentPostDate of the parent thread
                    var thread = context.Threads.Find(tm.ThreadId);
                    thread.MostRecentPostDate = DateTime.Now;

                    // add the message
                    context.ThreadMessages.Add(tm);

                    // commit
                    context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                return(new DomingoBlError()
                {
                    ErrorCode = 100, ErrorMessage = ex.Message
                });
            }

            return(new DomingoBlError()
            {
                ErrorCode = 0, ErrorMessage = ""
            });
        }
Ejemplo n.º 5
0
        public ActionResult ReplyToThread(int threadId, string replyMessage, int tripId, int aDmin = 0)
        {
            if (!string.IsNullOrEmpty(replyMessage))
            {
                var threadMessage = new ThreadMessage()
                {
                    AspnetUserId = User.Identity.GetUserId(),
                    ThreadId     = threadId,
                    Body         = replyMessage,
                    CreatedDate  = DateTime.Now,
                    TravellerId  = 990,
                    IsAdmin      = aDmin > 0 ? true : false
                };

                var _blError = ThreadManager.AddToThread(threadMessage);
            }

            if (aDmin > 0)
            {
                return(RedirectToAction("Message", "Admin", new { @id = threadId }));
            }


            if (tripId != 0)
            {
                return(RedirectToAction("EditTrip", new { @tripId = tripId }));
            }

            return(RedirectToAction("MessageCenter"));
        }
Ejemplo n.º 6
0
        public ThreadMessage Get(int id)
        {
            //get targetmessage
            //fill list
            //by parent
            ThreadMessage        targetMessage           = null;
            List <ThreadMessage> allMessages             = null;
            Dictionary <int, List <ThreadMessage> > dict = null;
            //kepp a list of children by parent Id
            //except those with parents of null have key 0

            Action <SqlParameterCollection> inputParamDelegate = delegate(SqlParameterCollection paramCollection)
            {
                paramCollection.AddWithValue("@Id", id);
                //strings have to match the stored proc parameter names
            };

            Action <IDataReader, short> singleRecMapper = delegate(IDataReader reader, short set)
            {
                ThreadMessage comment  = MessageMapper(reader);
                int           parentId = comment.ParentId.HasValue ? comment.ParentId.Value : 0;

                if (comment.Id == id)
                {
                    targetMessage = comment;
                }
                if (allMessages == null)
                {
                    allMessages = new List <ThreadMessage>();
                }
                if (dict == null)
                {
                    dict = new Dictionary <int, List <ThreadMessage> >();
                }
                allMessages.Add(comment);

                if (!dict.ContainsKey(parentId))
                {
                    dict.Add(parentId, new List <ThreadMessage>());
                }
                dict[parentId].Add(comment);
            };

            _dataProvider.ExecuteCmd("dbo.Comments_SelectById", inputParamDelegate, singleRecMapper);

            if (allMessages != null)
            {
                foreach (ThreadMessage currentMessage in allMessages)
                {
                    if (dict.ContainsKey(currentMessage.Id))
                    {
                        currentMessage.Replies = dict[currentMessage.Id];
                    }
                }
            }

            return(targetMessage);
        }
Ejemplo n.º 7
0
        /************************************************************************************/
        /// <summary>
        /// Waits for a message to be handled by the thread before returning.
        /// </summary>
        /// <remarks>
        /// Can be called from any thread, but requires the receiving thread to call
        /// ThreadMessage.SignalReply() upon completion of processing.
        /// If called on the same thread as the destination,
        /// then it requires OnMessage() to be implemented.
        /// </remarks>
        /// <param name="NewMessage"></param>
        public bool CallMessage(ThreadMessage NewMessage, TimeSpan?WaitSpan)
        {
            /// TODO: Make sure this thread is even active, otherwise this call will crash.

            MessageThread CallerThread = CurrentThread;

            /// If we're calling from within the same thread...
            if (null != CallerThread && CallerThread.ID == ID)
            {
                OnMessage(NewMessage);
            }

            /// If we're calling from another thread...
            else
            {
                EventWaitHandle TempWaitHandle = null;

                if (null == CallerThread)
                {
                    TempWaitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);                     // The GC will need to destroy this.
                }
                else
                {
                    TempWaitHandle = CallerThread.m_CallMessageCompletedEvent;
                }

                NewMessage.WaitHandle = TempWaitHandle;

                TempWaitHandle.Reset();
                PostMessage(NewMessage);

                /// Wait for the destination thread to reply to the message.
                if (WaitSpan == null)
                {
#if DEBUG
                    /// This is EXTREMELY valuable in helping to find deadlocks.
                    /// NOTE: It might happen inadvertently during debug breakpoints. Ignore it during these times.
                    Debug.Assert(TempWaitHandle.WaitOne(30000, false), "CallMessage reply not received within 30 seconds from thread:\n\n" + Name);
#else
                    TempWaitHandle.WaitOne();
#endif
                }
                else
                {
                    if (!TempWaitHandle.WaitOne(WaitSpan.Value, false))
                    {
                        return(false);
                    }
                }

                if (NewMessage.m_bAbortedCall)
                {
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 8
0
        public List <ThreadMessage> GetAllByOwnerInfo(int ownerId, int ownerTypeId)
        {
            List <ThreadMessage>     allMessages = null;
            List <Author>            allAuthors  = null;
            Dictionary <int, Author> dict        = null;

            Action <SqlParameterCollection> inputParamDelegate = delegate(SqlParameterCollection paramCollection)
            {
                paramCollection.AddWithValue("@OwnerId", ownerId);
                paramCollection.AddWithValue("@OwnerTypeId", ownerTypeId);
            };

            Action <IDataReader, short> singleRecMapper = delegate(IDataReader reader, short set)
            {
                if (set == 0)
                {
                    Author author        = new Author();
                    int    startingIndex = 0;
                    author.Id        = reader.GetSafeInt32(startingIndex++);
                    author.FirstName = reader.GetSafeString(startingIndex++);
                    author.LastName  = reader.GetSafeString(startingIndex++);

                    if (allAuthors == null)
                    {
                        allAuthors = new List <Author>();
                    }

                    allAuthors.Add(author);
                    if (dict == null)
                    {
                        dict = new Dictionary <int, Author>();
                    }
                    dict[author.Id] = author;
                }

                if (set == 1)
                {
                    ThreadMessage comment = MessageMapper(reader);

                    if (allMessages == null)
                    {
                        allMessages = new List <ThreadMessage>();
                    }

                    allMessages.Add(comment);

                    if (dict.ContainsKey(comment.UserId))
                    {
                        comment.AuthorInfo = dict[comment.UserId];
                    }
                }
            };

            _dataProvider.ExecuteCmd("dbo.Comments_GetAllByOwnerIdOwnerTypeId_V2", inputParamDelegate, singleRecMapper);

            return(allMessages);
        }
Ejemplo n.º 9
0
 /************************************************************************************/
 /// <summary>
 /// This is the "proper" way to empty the message queue because it lets other threads who used
 /// CallMessage() know that they just got f****d. Leaving them in the dark isn't as fun when
 /// you're trashing your own process, ya know?
 /// </summary>
 protected void ClearMessageQueue()
 {
     lock (m_Lock)
     {
         while (m_MessageQueue.Count > 0)
         {
             ThreadMessage NextMessage = m_MessageQueue.Dequeue();
             NextMessage.SignalAbort();
         }
     }
 }
Ejemplo n.º 10
0
        /************************************************************************************/
        /// <summary>
        /// This is just a helper function.  Derived classes may or may not use this at their whim.
        /// The default Run() implementation calls this automatically.
        /// </summary>
        /// <returns>false if bExitIfEmptyQueue is true and a quit message was encountered.</returns>
        protected bool DoMessageLoop(bool bExitIfEmptyQueue)
        {
            while (true)
            {
                if (bExitIfEmptyQueue && QueuedMessageCount == 0)
                {
                    return(true);
                }

                ThreadMessage NextMessage = GetMessage(true);
                if (NextMessage != null)
                {
                    try
                    {
                        OnMessage(NextMessage);
                    }
                    finally
                    {
                        /// Signal the message in case the handler forgets.
                        /// NOTE: Don't do this anymore.
                        /// Some derived threads get into the practice of caching and reordering messages for later processing.
                        //NextMessage.SignalReply();
                    }

                    if (NextMessage is QuitMessage)
                    {
                        if (bExitIfEmptyQueue)
                        {
                            return(false);
                        }
                        else
                        {
                            break;
                        }
                    }
                    else if (NextMessage is PingMessage)
                    {
                        NextMessage.SignalReply();
                    }
                }

                /// Call the idle handler if the queue is empty OR if starvation is occuring.
                if (QueuedMessageCount == 0 || (DateTime.Now - m_LastOnIdleLocalCallTime) > MaxIdleStarvationTimeSpan)
                {
                    m_LastOnIdleLocalCallTime = DateTime.Now;
                    OnIdle();
                }
            }

            return(true);
        }
Ejemplo n.º 11
0
        // ReSharper disable once InconsistentNaming
        public void ShouldReturnMessagesInFIFOOrder()
        {
            BlockingQueue <ThreadMessage> x = new BlockingQueue <ThreadMessage>();

            ThreadMessage msg1 = new ThreadMessage(1);
            ThreadMessage msg2 = new ThreadMessage(2);
            ThreadMessage msg3 = new ThreadMessage(3);

            x.Enqueue(msg1);
            x.Enqueue(msg2);
            x.Enqueue(msg3);
            Assert.AreEqual(x.Dequeue().Cmd, msg1.Cmd);
            Assert.AreEqual(x.Dequeue().Cmd, msg2.Cmd);
            Assert.AreEqual(x.Dequeue().Cmd, msg3.Cmd);
        }
Ejemplo n.º 12
0
        private void AddModMailMessage(ulong channelId, RestUserMessage channelMessageId, IUserMessage userMessage, ulong userId, bool anonymous = false)
        {
            var msg = new ThreadMessage();

            msg.ChannelId        = channelId;
            msg.ChannelMessageId = channelMessageId.Id;
            msg.UserMessageId    = userMessage != null ? userMessage.Id : 0;
            msg.UserId           = userId;
            msg.Anonymous        = anonymous;
            using (var db = new Database())
            {
                db.ThreadMessages.Add(msg);
                db.SaveChanges();
            }
        }
Ejemplo n.º 13
0
        public async Task PostMessageToServer(ThreadMessage message)
        {
            var group = _connectionGroupCache.FindGroup(Context.ConnectionId);

            await Clients.Group(group.GroupName).ReceiveMessageFromServer(message);

            var(isExist, messageChannel) = _messageChannelStoreReaderForPolling.GetMessageChannel(group.ThreadId);

            if (isExist)
            {
                messageChannel.AddMessage(message);
            }

            await _commentAccessor.InsertCommentAsync(message.Message, group.ThreadId, DateTime.UtcNow);
        }
Ejemplo n.º 14
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="tm"></param>
        /// <param name="title"></param>
        /// <param name="tripId"></param>
        /// <returns></returns>
        public static DomingoBlError CreateThreadforTrip(ThreadMessage tm, string title, int tripId)
        {
            try
            {
                using (TravelogyDevEntities1 context = new TravelogyDevEntities1())
                {
                    // create the Thread
                    var _thread = new Thread()
                    {
                        AuthorUserId       = tm.TravellerId,
                        CreatedDate        = DateTime.Now,
                        MostRecentPostDate = DateTime.Now,
                        Title        = title,
                        Tags         = "message",
                        AspnetUserId = tm.AspnetUserId
                    };

                    // save it to the DB
                    context.Threads.Add(_thread);
                    context.SaveChanges();

                    // add the message with the ID
                    context.ThreadMessages.Add(tm);
                    tm.ThreadId = _thread.Id;

                    var trip = context.Trips.FirstOrDefault(p => p.Id == tripId);
                    if (trip != null)
                    {
                        trip.ThreadId = _thread.Id;
                    }

                    // commit
                    context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                return(new DomingoBlError()
                {
                    ErrorCode = 100, ErrorMessage = ex.Message
                });
            }

            return(new DomingoBlError()
            {
                ErrorCode = 0, ErrorMessage = ""
            });
        }
Ejemplo n.º 15
0
        public async Task <ActionResult <ThreadMessage> > UpdateThread(ThreadMessage message)
        {
            (var thread, _) = await this.ExecuteAsync(() => _service.ReadThread(message.ThreadId));

            if (thread is null)
            {
                return(BadRequest($"Thread {message.ThreadId} is deleted"));
            }

            return(await this.ExecuteAsync(async() =>
            {
                await _service.UpdateThread(thread, message.MessageContext);

                return await _service.ReadThreadMessage(message.ThreadId);
            }).AsResultAsync());
        }
        public HttpResponseMessage Get(int id)
        {
            ThreadMessage comment = _commentsService.Get(id);

            ItemResponse <ThreadMessage> response = new ItemResponse <ThreadMessage>();

            response.Item = comment;

            if (response.Item == null)
            {
                response.IsSuccessful = false;
                return(Request.CreateResponse(HttpStatusCode.NotFound, response));
            }

            return(Request.CreateResponse(HttpStatusCode.OK, response));
        }
Ejemplo n.º 17
0
        //TODO: メンションの処理を入れる。
        internal async Task <Guid> CreateThread(ThreadMessage message, string userId)
        {
            var threadId = Guid.NewGuid();

            var thread = new Models.Thread()
            {
                Id = threadId,
                ApplicationUserId = userId,
                PostId            = message.PostId,
                Text = message.MessageContext
            };

            _context.Add(thread);
            await _context.SaveChangesAsync();

            return(threadId);
        }
Ejemplo n.º 18
0
        public void ShouldEnqueAndDequeTheSameMessage()
        {
            BlockingQueue <ThreadMessage> x = new BlockingQueue <ThreadMessage>();
            // ReSharper disable once UseObjectOrCollectionInitializer
            ThreadMessage msg1 = new ThreadMessage(1);

            msg1.Add("Test1", "Some String Value");
            msg1.Add("TEST2", 1);
            msg1.Add("Test3", true);
            x.Enqueue(msg1);
            ThreadMessage msg2 = x.Dequeue();

            Assert.AreEqual(msg1.Cmd, msg2.Cmd);
            Assert.AreEqual(msg1.GetString("Test1"), msg2.GetString("Test1"));
            Assert.AreEqual(msg1.GetInt("Test2"), msg2.GetInt("TEST2"));
            Assert.AreEqual(msg1.GetBool("Test3"), msg2.GetBool("Test3"));
        }
Ejemplo n.º 19
0
        /************************************************************************************/
        protected override void OnMessage(ThreadMessage NewMessage)
        {
            base.OnMessage(NewMessage);

            if (NewMessage is NewProfileMessage)
            {
                NewProfileMessage ThisMessage = (NewMessage as NewProfileMessage);
                m_CurrentProfile = ThisMessage.m_NewProfileCopy;
            }

            else if (NewMessage is EmailMessage)
            {
                EmailMessage ThisMessage = (NewMessage as EmailMessage);
                m_CurrentProfile.SendEMail(ThisMessage.m_astrToAddresses, ThisMessage.m_strSubject, ThisMessage.m_strBody);
            }

            return;
        }
Ejemplo n.º 20
0
        private static ThreadMessage MessageMapper(IDataReader reader)
        {
            ThreadMessage comment       = new ThreadMessage();
            int           startingIndex = 0;

            comment.Id           = reader.GetSafeInt32(startingIndex++);
            comment.Title        = reader.GetSafeString(startingIndex++);
            comment.Comment      = reader.GetSafeString(startingIndex++);
            comment.ParentId     = reader.GetSafeInt32(startingIndex++);
            comment.OwnerId      = reader.GetSafeInt32(startingIndex++);
            comment.OwnerTypeId  = reader.GetSafeInt32(startingIndex++);
            comment.UserId       = reader.GetSafeInt32(startingIndex++);
            comment.DateAdded    = reader.GetSafeDateTime(startingIndex++);
            comment.DateModified = reader.GetSafeDateTime(startingIndex++);



            return(comment);
        }
Ejemplo n.º 21
0
            void ProcessInterThreadMessage(ThreadMessage msg)
            {
                switch (msg.Type)
                {
                case MessageType.AddActor:
                    // Only comes from Scheduler, nothing to answer
                    m_ActorStates.Add(msg.ActorState);
                    msg.ActorState.NbExecutions = 0;
                    msg.ActorState.NbCycles     = 0;
                    break;

                case MessageType.RemoveActor:
                    // Only comes from Scheduler, no need to signal the source
                    // as it will be fetched when Add is called again in Scheduler
                    m_ActorStates.Remove(msg.ActorState);
                    msg.Source.SendRemoveActorResponse(this, msg.ActorState);
                    break;

                case MessageType.StealActor:
                    FindAndSendStolenActor(msg);
                    break;

                case MessageType.StealActorResponse:
                    m_HasPendingStealingRequest = false;
                    if (msg.ActorState != null)
                    {
                        m_ActorStates.Add(msg.ActorState);
                        msg.ActorState.ExecutionGroup = this;
                        msg.ActorState.IsReady        = true;
                        msg.ActorState.NbExecutions   = 0;
                        msg.ActorState.NbCycles       = 0;
                    }
                    break;

                case MessageType.RemoveActorResponse:
                    // Should never happen, only FakeExecutionGroup will receive it and it's running in
                    // cooperative mode without ticking being called
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
Ejemplo n.º 22
0
        public async Task <ActionResult <ThreadMessage> > PostThread(ThreadMessage message)
        {
            var user = await _userService.ReadUser(message.UserEmail);

            if (user is null)
            {
                return(BadRequest("This user is deleted"));
            }

            return(await this.ExecuteAsync(async() =>
            {
                var threadId = await _service.CreateThread(message, user.Id);

                var thread = await _service.ReadThreadMessage(threadId);
                await _postService.SendMention(message.MessageContext, thread.RoomId);

                await _postService.SendMessage(SignalRMehod.SendThreadMessage, thread);
                return thread;
            }).AsResultAsync());
        }
Ejemplo n.º 23
0
            void FindAndSendStolenActor(ThreadMessage msg)
            {
                if (m_NbCyclesSinceLastSendStolenActor < k_SampleSize || m_ActorStates.Count < 2)
                {
                    msg.Source.SendStealActorResponse(this, null);
                    return;
                }

                ActorState bestMatch      = null;
                var        smallestRatio  = float.MaxValue;
                var        bestMatchIndex = 0;

                for (var i = 0; i < m_ActorStates.Count; ++i)
                {
                    var actor = m_ActorStates[i];

                    // Not enough data to know if this actor is heavy or lightweight
                    if (actor.NbCycles < k_SampleSize * 2)
                    {
                        continue;
                    }

                    var ratio = actor.NbExecutions / (float)actor.NbCycles;
                    if (ratio < smallestRatio)
                    {
                        bestMatch      = actor;
                        bestMatchIndex = i;
                        smallestRatio  = ratio;
                    }
                }

                if (bestMatch == null)
                {
                    msg.Source.SendStealActorResponse(this, null);
                    return;
                }

                m_NbCyclesSinceLastSendStolenActor = 0;
                m_ActorStates.RemoveAt(bestMatchIndex);
                msg.Source.SendStealActorResponse(this, bestMatch);
            }
Ejemplo n.º 24
0
        public ActionResult CreateThread(MessageViewModel _model)
        {
            var _message = new ThreadMessage()
            {
                TravellerId  = 999,
                Body         = _model.Body,
                CreatedDate  = DateTime.Now,
                AspnetUserId = User.Identity.GetUserId()
            };

            var _blError = new DomingoBlError();

            if (_model.TripId == 0)
            {
                _blError = ThreadManager.CreateThread(_message, _model.Subject);
            }
            else
            {
                _blError = ThreadManager.CreateThreadforTrip(_message, _model.Subject, _model.TripId);
            }

            if (_blError.ErrorCode == 0)
            {
                if (_model.TripId == 0)
                {
                    return(RedirectToAction("MessageCenter"));
                }

                else
                {
                    return(RedirectToAction("EditTrip", new { @tripId = _model.TripId }));
                }
            }

            return(RedirectToAction("MessageCenter"));
        }
Ejemplo n.º 25
0
 /************************************************************************************/
 public bool CallMessage(ThreadMessage NewMessage)
 {
     return(CallMessage(NewMessage, null));
 }
Ejemplo n.º 26
0
        void launchWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ThreadMessage message = e.UserState as ThreadMessage;

            this.engine.WriteStatusLogMessage(message.Message);
        }
Ejemplo n.º 27
0
        public async Task ChangeThreadMessage(ThreadMessage threadMessage, HttpClient httpClient)
        {
            await httpClient.PutAsJsonAsync("Thread", threadMessage);

            ChangeMessage();
        }
Ejemplo n.º 28
0
 /************************************************************************************/
 /// <summary>
 /// This is a companion callback to DoMessageLoop().
 /// </summary>
 /// <param name="NewMessage"></param>
 protected virtual void OnMessage(ThreadMessage NewMessage)
 {
     return;
 }
Ejemplo n.º 29
0
        /************************************************************************************/
        /// <summary>
        /// Retrieves a message from the queue.
        /// </summary>
        /// <remarks>
        /// This function will throw an exception if called from outside the context of the owner thread.
        /// </remarks>
        /// <param name="bWaitForMessageIfEmpty"></param>
        /// <returns>Returns NULL if no message was in the queue.</returns>
        protected ThreadMessage GetMessage(bool bWaitForMessageIfEmpty)
        {
            int iWaitObjectIndex = -1;

            if (bWaitForMessageIfEmpty)
            {
                iWaitObjectIndex = WaitHandle.WaitAny(m_aWaitHandles);                 // TODO: Should we figure a way to abort this?
            }
            else
            {
                iWaitObjectIndex = WaitHandle.WaitAny(m_aWaitHandles, 0, false);
            }

            WaitHandle ThisSignalledHandle = null;

            if (iWaitObjectIndex != WaitHandle.WaitTimeout)
            {
                ThisSignalledHandle = m_aWaitHandles[iWaitObjectIndex];
            }

            /// If a wait was signalled and it wasn't the standard queue filled event, return it.
            /// The recipient has an obligation to clear the signal or unregister the handle,
            /// otherwise the next call to GetMessage will return the same handle.
            if (ThisSignalledHandle != null && ThisSignalledHandle.SafeWaitHandle != m_QueueFilledEvent.SafeWaitHandle)
            {
                return(new WaitHandleSignalledMessage(ThisSignalledHandle));
            }

            ThreadMessage NewIncomingMessage = null;

            lock (m_Lock)
            {
                // Dummy check.
                if (m_Thread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)
                {
                    throw new Exception("TekMessageThread.GetMessage can only be called from the context of the owner thread.");
                }

                /// Check for any legit messages.
                if (m_MessageQueue.Count > 0)
                {
                    NewIncomingMessage = m_MessageQueue.Dequeue();
                }

                /// Check our timer list and generate a pseudo-message.
                /// Timers have lowest priority just like Win32 because if the messages build
                /// up and if the message handler takes time to process (such as connection timeout),
                /// then the backlog of messages will drown out any other processing.
                else if (m_PulsedTimers.Count > 0)
                {
                    int iTimerID = m_PulsedTimers[0];
                    m_PulsedTimers.Remove(iTimerID);

                    TimerDesc ThisTimerDesc = m_Timers[iTimerID];
                    NewIncomingMessage = new TimerMessage(iTimerID, ThisTimerDesc.m_Context, ThisTimerDesc.m_Timer.Interval);
                }

                /// Now that there is NOTHING to retrieve, make the event block again.
                if (QueuedMessageCount == 0)
                {
                    m_QueueFilledEvent.Reset();
                }
            }

            return(NewIncomingMessage);
        }