Skip to content

Commit 1da1b88

Browse files
authored
Replace boxing ArrayLists in UIAutomationClientSideProviders (hWnd proxies) (#9388)
* add system.collections ref to use generic collections * modify PropertyToWinEvent from boxing arraylist to generic, return ReadOnlySpan (wont build) * modify call-chain to use ReadOnlySpan<EvtPropertyId> instead of an array * replace listview array allocs with ReadOnlySpan<EvtIdProperty> * replace listbox array allocs with ReadOnlySpan<EvtIdProperty> * bring parity and pass array/span length props everywhere for better code quality * return ReadOnlySpan<EvtIdProperty> in ComboBox instead of arrays * remove passing down the index downstream as ROS<EvtIdProperty> has Length already * fix mistake introduced in 63107ac8 (return ROS in ComboBox commit) * remove output count parameters and use span (for span<t>.empty where needed) * fix up some comments * replace boxing array list on EventCreateParams with generic, make the struct internal * Fix post-merge issues
1 parent d71c3ce commit 1da1b88

File tree

13 files changed

+123
-167
lines changed

13 files changed

+123
-167
lines changed

src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/ProxyHwnd.cs

Lines changed: 41 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
// AdviseEventAdded
1616
// AdviseEventRemoved
1717

18-
using System;
19-
using System.Windows;
20-
using System.Windows.Automation;
2118
using System.Windows.Automation.Provider;
22-
using System.Collections;
19+
using System.Runtime.InteropServices;
20+
using System.Collections.Generic;
21+
using System.Windows.Automation;
22+
using System.Windows;
2323
using MS.Win32;
24+
using System;
2425

2526
namespace MS.Internal.AutomationProxies
2627
{
@@ -60,32 +61,31 @@ internal ProxyHwnd (IntPtr hwnd, ProxyFragment parent, int item)
6061

6162
// Advises proxy that an event has been added.
6263
// Maps the Automation Events into WinEvents and add those to the list of WinEvents notification hooks
63-
internal virtual void AdviseEventAdded (AutomationEvent eventId, AutomationProperty [] aidProps)
64+
internal virtual void AdviseEventAdded(AutomationEvent eventId, AutomationProperty[] aidProps)
6465
{
6566
// No RawElementBase creation callback, exit from here
6667
if (_createOnEvent == null)
6768
{
6869
return;
6970
}
7071

71-
int cEvents = 0;
72-
WinEventTracker.EvtIdProperty [] aEvents;
72+
ReadOnlySpan<WinEventTracker.EvtIdProperty> aEvents;
7373

7474
// Gets an Array of WinEvents to trap on a per window handle basis
7575
if (eventId == AutomationElement.AutomationPropertyChangedEvent)
7676
{
77-
aEvents = PropertyToWinEvent (aidProps, out cEvents);
77+
aEvents = PropertyToWinEvent(aidProps);
7878
}
7979
else
8080
{
81-
aEvents = EventToWinEvent (eventId, out cEvents);
81+
aEvents = EventToWinEvent(eventId);
8282
}
8383

8484
// If we have WinEvents to trap, add those to the list of WinEvent
8585
// notification list
86-
if (cEvents > 0)
86+
if (aEvents.Length > 0)
8787
{
88-
WinEventTracker.AddToNotificationList (_hwnd, _createOnEvent, aEvents, cEvents);
88+
WinEventTracker.AddToNotificationList(_hwnd, _createOnEvent, aEvents);
8989
}
9090
}
9191

@@ -98,24 +98,23 @@ internal virtual void AdviseEventRemoved(AutomationEvent eventId, AutomationProp
9898
return;
9999
}
100100

101-
int cEvents;
102-
WinEventTracker.EvtIdProperty [] aEvents;
101+
ReadOnlySpan<WinEventTracker.EvtIdProperty> aEvents;
103102

104103
// Gets an Array of WinEvents to trap on a per window handle basis
105104
if (eventId == AutomationElement.AutomationPropertyChangedEvent)
106105
{
107-
aEvents = PropertyToWinEvent (aidProps, out cEvents);
106+
aEvents = PropertyToWinEvent(aidProps);
108107
}
109108
else
110109
{
111-
aEvents = EventToWinEvent (eventId, out cEvents);
110+
aEvents = EventToWinEvent(eventId);
112111
}
113112

114113
// If we have WinEvents to remove, remive those to the list of WinEvent
115114
// notification list
116-
if (cEvents > 0)
115+
if (aEvents.Length > 0)
117116
{
118-
WinEventTracker.RemoveToNotificationList (_hwnd, aEvents, null, cEvents);
117+
WinEventTracker.RemoveToNotificationList(_hwnd, aEvents, null);
119118
}
120119
}
121120

@@ -395,30 +394,30 @@ protected virtual int [] PropertyToWinEvent (AutomationProperty idProp)
395394
return null;
396395
}
397396

398-
// Builds a list of Win32 WinEvents to process a UIAutomation Event.
399-
protected virtual WinEventTracker.EvtIdProperty [] EventToWinEvent (AutomationEvent idEvent, out int cEvent)
397+
/// <summary> Builds a list of Win32 WinEvents to process a UIAutomation Event. </summary>
398+
/// <param name="idEvent"> An UIAutomation event. </param>
399+
/// <returns> Returns an array of Events to Set. </returns>
400+
protected virtual ReadOnlySpan<WinEventTracker.EvtIdProperty> EventToWinEvent(AutomationEvent idEvent)
400401
{
401402
// Fill this variable with a WinEvent id if found
402-
int idWinEvent = 0;
403+
int idWinEvent;
403404

404405
if (idEvent == SelectionItemPattern.ElementSelectedEvent)
405406
{
406-
cEvent = 2;
407407
return new WinEventTracker.EvtIdProperty[2]
408408
{
409-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectSelection, idEvent),
410-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectStateChange, idEvent)
409+
new(NativeMethods.EventObjectSelection, idEvent),
410+
new(NativeMethods.EventObjectStateChange, idEvent)
411411
};
412412
}
413413
else if (idEvent == SelectionItemPattern.ElementAddedToSelectionEvent)
414414
{
415415
// For some control, the Event Selection is sent instead of SelectionAdd
416416
// Trap both.
417-
cEvent = 2;
418417
return new WinEventTracker.EvtIdProperty [2]
419418
{
420-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectSelectionAdd, idEvent),
421-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectSelection, idEvent)
419+
new(NativeMethods.EventObjectSelectionAdd, idEvent),
420+
new(NativeMethods.EventObjectSelection, idEvent)
422421
};
423422
}
424423
else if (idEvent == SelectionItemPattern.ElementRemovedFromSelectionEvent)
@@ -431,40 +430,35 @@ protected virtual WinEventTracker.EvtIdProperty [] EventToWinEvent (AutomationEv
431430
}
432431
else if (idEvent == InvokePattern.InvokedEvent)
433432
{
434-
cEvent = 4;
435433
return new WinEventTracker.EvtIdProperty[4] {
436-
new WinEventTracker.EvtIdProperty (NativeMethods.EventSystemCaptureEnd, idEvent), // For SysHeaders
437-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectStateChange, idEvent),
438-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectValueChange, idEvent), // For WindowsScrollBarBits
439-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectInvoke, idEvent)
434+
new(NativeMethods.EventSystemCaptureEnd, idEvent), // For SysHeaders
435+
new(NativeMethods.EventObjectStateChange, idEvent),
436+
new(NativeMethods.EventObjectValueChange, idEvent), // For WindowsScrollBarBits
437+
new(NativeMethods.EventObjectInvoke, idEvent)
440438
};
441439
}
442440
else if (idEvent == AutomationElement.StructureChangedEvent)
443441
{
444-
cEvent = 3;
445442
return new WinEventTracker.EvtIdProperty[3] {
446-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectCreate, idEvent),
447-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectDestroy, idEvent),
448-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectReorder, idEvent)
443+
new(NativeMethods.EventObjectCreate, idEvent),
444+
new(NativeMethods.EventObjectDestroy, idEvent),
445+
new(NativeMethods.EventObjectReorder, idEvent)
449446
};
450447
}
451448
else if (idEvent == TextPattern.TextSelectionChangedEvent)
452449
{
453-
cEvent = 2;
454450
return new WinEventTracker.EvtIdProperty[2] {
455-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectLocationChange, idEvent),
456-
new WinEventTracker.EvtIdProperty (NativeMethods.EventObjectTextSelectionChanged, idEvent)
451+
new(NativeMethods.EventObjectLocationChange, idEvent),
452+
new(NativeMethods.EventObjectTextSelectionChanged, idEvent)
457453
};
458454
}
459455
else
460456
{
461-
cEvent = 0;
462-
return null;
457+
return ReadOnlySpan<WinEventTracker.EvtIdProperty>.Empty;
463458
}
464459

465460
// found one and only one
466-
cEvent = 1;
467-
return new WinEventTracker.EvtIdProperty [1] { new WinEventTracker.EvtIdProperty (idWinEvent, idEvent) };
461+
return new WinEventTracker.EvtIdProperty [1] { new(idWinEvent, idEvent) };
468462
}
469463

470464
// Check if a point is within the client Rect of a window
@@ -512,29 +506,22 @@ static protected string GetLabelAccessKey(IntPtr hwnd)
512506

513507
// Builds a list of Win32 WinEvents to process changes in properties changes values.
514508
// Returns an array of Events to Set. The number of valid entries in this array is pass back in cEvents
515-
private WinEventTracker.EvtIdProperty [] PropertyToWinEvent (AutomationProperty [] aProps, out int cEvent)
509+
private ReadOnlySpan<WinEventTracker.EvtIdProperty> PropertyToWinEvent(AutomationProperty[] aProps)
516510
{
517-
ArrayList alEvents = new ArrayList (16);
511+
List<WinEventTracker.EvtIdProperty> automationEvents = new(16);
518512

519513
foreach (AutomationProperty idProp in aProps)
520514
{
521-
int [] evtId = PropertyToWinEvent (idProp);
515+
int[] evtId = PropertyToWinEvent(idProp);
522516

523517
for (int i = 0; evtId != null && i < evtId.Length; i++)
524518
{
525-
alEvents.Add (new WinEventTracker.EvtIdProperty (evtId [i], idProp));
519+
automationEvents.Add(new WinEventTracker.EvtIdProperty(evtId[i], idProp));
526520
}
527521

528522
}
529523

530-
WinEventTracker.EvtIdProperty [] aEvtIdProperties = new WinEventTracker.EvtIdProperty [alEvents.Count];
531-
532-
cEvent = alEvents.Count;
533-
for (int i = 0; i < cEvent; i++)
534-
{
535-
aEvtIdProperties [i] = (WinEventTracker.EvtIdProperty) alEvents [i];
536-
}
537-
return aEvtIdProperties;
524+
return CollectionsMarshal.AsSpan(automationEvents);
538525
}
539526

540527
#endregion

0 commit comments

Comments
 (0)