Пример #1
0
 private void DrainQueue()
 {
     // It's possible items could be enqueued between when we check for the count
     // and dequeue but the event is set then and we'll come back into DrainQueue.
     // (note: don't use a for loop here because as the counter is incremented
     // Count is decremented and we'll only process half the queue)
     while (_q.Count > 0)
     {
         // pull an item off the queue, process, then clear it
         QueueItem item = (QueueItem)_q.Dequeue();
         if (!_quitting)
         {
             try
             {
                 item.Process();
             }
             catch (Exception e)
             {
                 if (Misc.IsCriticalException(e))
                 {
                     throw;
                 }
                 // Eat it.
                 // There's no place to let this exception percolate out
                 // to so we'll stop it here.
             }
         }
     }
 }
Пример #2
0
        // OnEventObjectDestroy - process an EventObjectDestroy WinEvent.
        private void OnEventObjectDestroy(int eventId, IntPtr hwnd, int idObject, int idChild, uint eventTime)
        {
            // Check if still alive. Ignore caret destroys - we're only interesed in 'real' objects here...
            if (idObject != UnsafeNativeMethods.OBJID_CARET && _accCurrent != null)
            {
                bool fDead = false;

                try
                {
                    int    dwState = _accCurrent.State;
                    IntPtr hwndCur = _accCurrent.Window;
                    if (hwndCur == IntPtr.Zero || !SafeNativeMethods.IsWindow(NativeMethods.HWND.Cast(hwndCur)))
                    {
                        fDead = true;
                    }
                }
                catch (Exception e)
                {
                    if (Misc.IsCriticalException(e))
                    {
                        throw;
                    }

                    fDead = true;
                }

                if (fDead)
                {
                    // It's dead...
                    HandleFocusChange(IntPtr.Zero, null, 0, 0, eventTime);
                }
            }
        }
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        #region Internal Methods

        // The method that gets called from CallbackQueue's thread.  Uses Post to invoke the callback on the proper thread.
        internal static void InvokeClientHandler(Delegate clientCallback, AutomationElement srcEl, AutomationEventArgs args)
        {
            try
            {
                if (args is AutomationPropertyChangedEventArgs)
                {
                    ((AutomationPropertyChangedEventHandler)clientCallback)(srcEl, (AutomationPropertyChangedEventArgs)args);
                }
                else if (args is StructureChangedEventArgs)
                {
                    ((StructureChangedEventHandler)clientCallback)(srcEl, (StructureChangedEventArgs)args);
                }
                else if (args is InternalAutomationFocusChangedEventArgs)
                {
                    AutomationFocusChangedEventArgs realArgs = ((InternalAutomationFocusChangedEventArgs)args)._args;

                    // For focus events, check that the event is actually more recent than the last one (see note at top of file).
                    // Since the timestamps can wrap around, subtract and measure the delta instead of just comparing them.
                    // Any events that appear to have taken place within the 5 seconds before the last event we got will be ignored.
                    // (Because of wraparound, certain before- and after- time spans share the same deltas; 5000ms before has the
                    // same value as MAXUINT-5000ms after. Since we're just trying to filter out very recent event race conditions,
                    // confine this test to a small window, just the most recent 5 seconds. That means you'd have to wait a *very*
                    // long time without any focus changes before getting a false positive here.)
                    uint eventTime = ((InternalAutomationFocusChangedEventArgs)args)._eventTime;
                    if (_lastFocusEventTime != 0)
                    {
                        uint delta = _lastFocusEventTime - eventTime;
                        // Exclude events that happend before the last one, but do allow any that happened "at the same time",
                        // (delta==0) since they likely actually happened after, but within the resolution of the event timer.
                        if (delta < 5000 && delta != 0)
                        {
                            return;
                        }
                    }
                    _lastFocusEventTime = eventTime;
                    ((AutomationFocusChangedEventHandler)clientCallback)(srcEl, realArgs);
                }
                else
                {
                    ((AutomationEventHandler)clientCallback)(srcEl, args);
                }
            }
            catch (Exception e)
            {
                if (Misc.IsCriticalException(e))
                {
                    throw;
                }

                // Since we can't predict what exceptions an outside client might throw intentionally ignore all
            }
        }
Пример #4
0
 private bool IsCriticalMSAAException(Exception e)
 {
     // Some OLEACC proxies produce out-of-memory for non-critical reasons:
     // notably, the treeview proxy will raise this if the target HWND no longer exists,
     // GetWindowThreadProcessID fails and it therefore won't be able to allocate shared
     // memory in the target process, so it incorrectly assumes OOM.
     // Some Native impls (media player) return E_POINTER, which COM Interop translates
     // into NullRefException; need to ignore those too.
     // should ignore those
     return(!(e is OutOfMemoryException) &&
            !(e is NullReferenceException) &&
            Misc.IsCriticalException(e));
 }
Пример #5
0
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------

        #region Private Methods

        // queue winevents so that the get processed in the order we receive them. If we just
        // dispatch them as we get them, we'll end up getting some _while_ we are processing others,
        // and end up completing those events out of order, making the event order appear backwards.
        // This code checks whether we are currently processing an event, and if so, queues it so that
        // we process it when we're done with the current event.
        private void WinEventReentrancyFilter(int winEventHook, int eventId, IntPtr hwnd, int idObject, int idChild, int eventThread, uint eventTime)
        {
            if (_fBusy)
            {
                _qEvents.Enqueue(new WinEvent(eventId, hwnd, idObject, idChild, eventTime));
            }
            else
            {
                _fBusy = true;
                try
                {
                    PreWinEventProc(eventId, hwnd, idObject, idChild, eventTime); // deliver this event
                }
                catch (Exception e)
                {
                    if (Misc.IsCriticalException(e))
                    {
                        throw;
                    }

                    // ignore exceptions for now since we've no way to let clients add exception handlers
                }

                while (_qEvents.Count > 0)
                {
                    WinEvent e = (WinEvent)_qEvents.Dequeue(); // process queued events
                    try
                    {
                        PreWinEventProc(e._eventId, e._hwnd, e._idObject, e._idChild, e._eventTime);
                    }
                    catch (Exception ex)
                    {
                        if (Misc.IsCriticalException(ex))
                        {
                            throw;
                        }

                        // ignore exceptions for now since we've no way to let clients add exception handlers
                    }
                }
                _fBusy = false;
            }
        }
Пример #6
0
        // Given an entry from one of the hash-tables or lists, check if it matches the image/classname, and if so, call the
        // factory method to create the proxy.
        // (Because full classname matching is done via hash-table lookup, this only needs to do string comparisons
        // for partial classname matches.)
        static private IRawElementProviderSimple GetProxyFromEntry(ProxyScoping findType, object entry, ref string imageName, NativeMethods.HWND hwnd, int idChild, int idObject, string classNameForPartialMatch)
        {
            // First, determine if the entry matches, and if so, extract the factory callback...
            ClientSideProviderFactoryCallback factoryCallback = null;

            // The entry may be a ClientSideProviderFactoryCallback or ClientSideProviderDescription...
            if (findType == ProxyScoping.ImageOnlyHandlers || findType == ProxyScoping.FallbackHandlers)
            {
                // Handle the fallback and image cases specially. The array for these is an array
                // of ClientSideProviderFactoryCallbacks, not ClientSideProviderDescription.
                factoryCallback = (ClientSideProviderFactoryCallback)entry;
            }
            else
            {
                // Other cases use ClientSideProviderDescription...
                ClientSideProviderDescription pi = (ClientSideProviderDescription)entry;

                // Get the image name if necessary...
#pragma warning suppress 6507 // Null and Empty string mean different things here.
                if (imageName == null && pi.ImageName != null)
                {
                    imageName = GetImageName(hwnd);
                }

                if (pi.ImageName == null || pi.ImageName == imageName)
                {
                    // Check if we have a match for this entry...
                    switch (findType)
                    {
                    case ProxyScoping.ExactMatchApparentClassName:
                        factoryCallback = pi.ClientSideProviderFactoryCallback;
                        break;

                    case ProxyScoping.ExactMatchRealClassName:
                        if ((pi.Flags & ClientSideProviderMatchIndicator.DisallowBaseClassNameMatch) == 0)
                        {
                            factoryCallback = pi.ClientSideProviderFactoryCallback;
                        }
                        break;

                    case ProxyScoping.PartialMatchApparentClassName:
                        if (classNameForPartialMatch.IndexOf(pi.ClassName, StringComparison.Ordinal) >= 0)
                        {
                            factoryCallback = pi.ClientSideProviderFactoryCallback;
                        }
                        break;

                    case ProxyScoping.PartialMatchRealClassName:
                        if (classNameForPartialMatch.IndexOf(pi.ClassName, StringComparison.Ordinal) >= 0 &&
                            ((pi.Flags & ClientSideProviderMatchIndicator.DisallowBaseClassNameMatch) == 0))
                        {
                            factoryCallback = pi.ClientSideProviderFactoryCallback;
                        }
                        break;

                    default:
                        Debug.Assert(false, "unexpected switch() case:");
                        break;
                    }
                }
            }

            // Second part: did we get a match? If so, use the factory callback to obtain an instance...
            if (factoryCallback == null)
            {
                return(null);
            }

            // if we get an exception creating a proxy just don't create the proxy and let the UIAutomation default proxy be used
            // This will still allow the tree to be navigated  and some properties to be made availible.
            // Catching all exceptions here doesn't follow .NET guidelines, but is it ok in this scenario?
            try
            {
                return(factoryCallback(hwnd, idChild, idObject));
            }
            catch (Exception e)
            {
                if (Misc.IsCriticalException(e))
                {
                    throw;
                }

                return(null);
            }
        }
Пример #7
0
        // We need to treat MSAA's FOCUS winevents differently depending on the OBJID -
        // OBJID_CLIENT gets routed to the proxies; _MENU and _SYSMENU get speical treatment.
        private AutomationElement GetFocusedElementFromWinEvent(IntPtr hwnd, int idObject, int idChild)
        {
            try
            {
                IRawElementProviderSimple provider = null;
                // These are the only object types that oleacc proxies allow to take focus.
                // (Native IAccessibles can send focus for other custom OBJID valus, but those are no use
                // to us.)
                // Try and get providers for them ourself - if we don't get anything, then
                // defer to core to get the element for the HWND itself.
                if (idObject == UnsafeNativeMethods.OBJID_CLIENT)
                {
                    // regular focus - pass it off to a proxy...
                    provider = ProxyManager.ProxyProviderFromHwnd(NativeMethods.HWND.Cast(hwnd), idChild, UnsafeNativeMethods.OBJID_CLIENT);
                }
                else if (idObject == UnsafeNativeMethods.OBJID_MENU)
                {
                    // menubar focus - see if there's a menubar pseudo-proxy registered...
                    ClientSideProviderFactoryCallback factory = ProxyManager.NonClientMenuBarProxyFactory;
                    if (factory != null)
                    {
                        provider = factory(hwnd, idChild, idObject);
                    }
                }
                else if (idObject == UnsafeNativeMethods.OBJID_SYSMENU)
                {
                    // system menu box focus - see if there's a sysmenu pseudo-proxy registered...
                    ClientSideProviderFactoryCallback factory = ProxyManager.NonClientSysMenuProxyFactory;
                    if (factory != null)
                    {
                        provider = factory(hwnd, idChild, idObject);
                    }
                }
                else if (idObject <= 0)
                {
                    return(null);
                }
                else
                {
                    // This covers OBJID_CLIENT and custom OBJID cases.
                    // Pass it to the proxy manager: most proxies will just handle OBJID_CLIENT,
                    // but the MSAA proxy can potentally handle other OBJID values.
                    provider = ProxyManager.ProxyProviderFromHwnd(NativeMethods.HWND.Cast(hwnd), idChild, idObject);
                }

                if (provider != null)
                {
                    // Ask the fragment root if any of its children really have the focus
                    IRawElementProviderFragmentRoot fragment = provider as IRawElementProviderFragmentRoot;
                    if (fragment != null)
                    {
                        // if we get back something that is different than what we started with and its not null
                        // use that instead.  This is here to get the subset link in the listview but could be usefull
                        // for listview subitems as well.
                        IRawElementProviderSimple realFocus = fragment.GetFocus();
                        if (realFocus != null && !Object.ReferenceEquals(realFocus, provider))
                        {
                            provider = realFocus;
                        }
                    }

                    SafeNodeHandle hnode = UiaCoreApi.UiaNodeFromProvider(provider);
                    return(AutomationElement.Wrap(hnode));
                }
                else
                {
                    // Didn't find a proxy to handle this hwnd - pass off to core...
                    return(AutomationElement.FromHandle(hwnd));
                }
            }
            catch (Exception e)
            {
                if (Misc.IsCriticalException(e))
                {
                    throw;
                }

                return(null);
            }
        }