// 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); } }
// protected override bool ReleaseHandle() { return(Misc.CloseHandle(handle)); }
// 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. // try { return(factoryCallback(hwnd, idChild, idObject)); } catch (Exception e) { if (Misc.IsCriticalException(e)) { throw; } return(null); } }