/////////////////////////////////////////////////////////////////////////////////////////////////
        //
        // BuildListOfHyperlinksFromWindow()
        //
        // Signals the background thread that the list of hyperlinks needs to be refreshed.
        //
        // Run on the main UI thread.
        //
        /////////////////////////////////////////////////////////////////////////////////////////////////
        public void BuildListOfHyperlinksFromWindow(bool fUseCache, bool fSearchLinkChildren)
        {
            // Let the background thread know it must generate the list of hyperlinks.
            SampleMsgData msgData = new SampleMsgData();

            msgData.msgType = SampleMsgType.msgBuildList;
            AddMsgToQueue(msgData);
        }
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 // Uninitialize()
 //
 // Close the background thread down.
 //
 // Runs on the main UI thread.
 //
 /////////////////////////////////////////////////////////////////////////////////////////////////
 public void Uninitialize()
 {
     // Tell the background thread to close down.
     if (_threadBackground != null)
     {
         SampleMsgData msgData = new SampleMsgData();
         msgData.msgType = SampleMsgType.msgCloseDown;
         AddMsgToQueue(msgData);
     }
 }
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 // InvokeLink()
 //
 // Signals the background thread that a hyperlink needs to be invoked.
 //
 // Run on the main UI thread.
 //
 /////////////////////////////////////////////////////////////////////////////////////////////////
 public void InvokeLink(int idxLink, bool fUseCache)
 {
     // It's ok to access the listview directly here, as we're running on the main UI thread.
     if ((idxLink >= 0) && (idxLink < _listViewLinks.Items.Count))
     {
         IUIAutomationElement element = (IUIAutomationElement)_listViewLinks.Items[idxLink].Tag;
         if (element != null)
         {
             // Let the background thread know it must invoke the hyperlink.
             SampleMsgData msgData = new SampleMsgData();
             msgData.msgType   = SampleMsgType.msgInvokeLink;
             msgData.element   = element;
             msgData.fUseCache = fUseCache;
             AddMsgToQueue(msgData);
         }
     }
 }
        /////////////////////////////////////////////////////////////////////////////////////////////////
        //
        // AddMsgToQueue()
        //
        // Update a list of messages waiting to be processed by the background thread.
        //
        // Run on the main UI thread.
        //
        /////////////////////////////////////////////////////////////////////////////////////////////////
        private void AddMsgToQueue(SampleMsgData msgData)
        {
            // Request the lock, and block until it is obtained.
            Monitor.Enter(_msgQueue);
            try
            {
                // When the lock is obtained, add an element.
                _msgQueue.Enqueue(msgData);
            }
            finally
            {
                // Ensure that the lock is released.
                Monitor.Exit(_msgQueue);
            }

            // Let the background thread know there's some action to be taken.
            _autoEventMsg.Set();
        }