// fire the element seleceted event if there is a client listening for it. private void MaybeFireSelectionItemEvent(AutomationEvent eventId, Hashtable eventTable, IntPtr hwnd, int idObject, int idChild) { // if the 2-nd level table contains an entry for this property if (eventTable.ContainsKey(eventId)) { // create a provider associated with this event and check whether the provider supports the selection item pattern. MsaaNativeProvider provider = (MsaaNativeProvider)MsaaNativeProvider.Create(hwnd, idChild, idObject); if (provider != null && provider.IsPatternSupported(SelectionItemPattern.Pattern)) { // fire the event AutomationEventArgs eventArgs = new AutomationEventArgs(eventId); //Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Firing {0} for {1}", eventId, hwnd), "NativeMsaaProxy"); AutomationInteropProvider.RaiseAutomationEvent(eventId, provider, eventArgs); } } }
// fire the property change event if there is a client listening for it. // pattern is the pattern that the property belongs to. the provider is tested to ensure it supports that pattern. private void MaybeFirePropertyChangeEvent(AutomationPattern pattern, AutomationProperty property, Hashtable eventTable, IntPtr hwnd, int idObject, int idChild, bool clientToo) { // if the 2-nd level table contains an entry for this property and the root element should be included (or not) if (eventTable.ContainsKey(property) && (clientToo || !IsClientObject(idObject, idChild))) { // create a provider associated with this event and check whether it supports the pattern, if specified. MsaaNativeProvider provider = (MsaaNativeProvider)MsaaNativeProvider.Create(hwnd, idChild, idObject); if (provider != null && (pattern == null || provider.IsPatternSupported(pattern))) { // get the new property value from the provider. object newValue = ((IRawElementProviderSimple)provider).GetPropertyValue(property.Id); // fire the event AutomationPropertyChangedEventArgs eventArgs = new AutomationPropertyChangedEventArgs(property, null, newValue); //Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Firing {0} change event for {1}", property, hwnd), "NativeMsaaProxy"); AutomationInteropProvider.RaiseAutomationPropertyChangedEvent(provider, eventArgs); } } }
// fire the structure change event if there is a client listening for it. private void MaybeFireStructureChangeEvent(int eventId, Hashtable eventTable, IntPtr hwnd, int idObject, int idChild) { // if the 2-nd level table contains an entry for this event and element is not the root // (the host hwnd provider takes care of structure changed events for the root.) if (eventTable.ContainsKey(AutomationElement.StructureChangedEvent) && !IsClientObject(idObject, idChild)) { // Note: src element for ChildRemoved cases needs to be the parent, but the runtime id is the child! // the type of structure changed event that we will fire depends on which event we are receiving. // the type then determines the src element -- either the parent or the child -- and the runtime id // -- either the parent or the child -- for the event arguments. IRawElementProviderFragment srcElement; int[] runtimeId = null; StructureChangeType type = StructureChangeType.ChildAdded; // Actual value is assigned below; any value will do here, to init the var switch (eventId) { case NativeMethods.EVENT_OBJECT_CREATE: case NativeMethods.EVENT_OBJECT_SHOW: // src element is child. runtime id is child. srcElement = (IRawElementProviderFragment)MsaaNativeProvider.Create(hwnd, idChild, idObject); if (srcElement != null) { runtimeId = srcElement.GetRuntimeId(); type = StructureChangeType.ChildAdded; } break; //case NativeMethods.EVENT_OBJECT_DESTROY: // src element is parent. runtime id is child. // There is nothing we can do in this case. Since the object is destroyed we can't instantiate // it in order to get its runtime ID. Even if it had a non-zero child id such that we could // instantiate its parent we still couldn't determine the runtime ID of the child that was destroyed. // There's also no guarantee that an EVENT_OBJECT_DESTROY will have a corresponding EVENT_OBJECT_CREATE // and even if it did it might use a different object id so we can't cache the information either. // (Trident for example uses a cyclic counter to generate object ids so the object id can vary for // the same object from one event to the next!) case NativeMethods.EVENT_OBJECT_HIDE: // src element is parent. runtime id is child. srcElement = (IRawElementProviderFragment)MsaaNativeProvider.Create(hwnd, idChild, idObject); if (srcElement != null) { runtimeId = srcElement.GetRuntimeId(); srcElement = (IRawElementProviderFragment)srcElement.Navigate(NavigateDirection.Parent); type = StructureChangeType.ChildRemoved; } break; default: Debug.Assert(eventId == NativeMethods.EVENT_OBJECT_REORDER); // src element is parent. runtime id is parent. srcElement = (IRawElementProviderFragment)MsaaNativeProvider.Create(hwnd, idChild, idObject); if (srcElement != null) { runtimeId = srcElement.GetRuntimeId(); type = StructureChangeType.ChildrenReordered; } break; } if (srcElement != null) { // fire the event StructureChangedEventArgs eventArgs = new StructureChangedEventArgs(type, runtimeId); //Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Firing structure change event for {0}", hwnd), "NativeMsaaProxy"); AutomationInteropProvider.RaiseStructureChangedEvent(srcElement, eventArgs); } } }