.NET version
.NET 10 (10.0.11 runtime, SDK 10.0.303). Still present in main (checked at 75072a6) and in release/10.0 (f8eab87).
Did it work in .NET Framework?
Yes
Did it work in any of the earlier releases of .NET Core or .NET 5+?
Yes. It works in .NET 8 and .NET 9 (verified with 9.0.19).
Issue description
Control.AccessibilityNotifyClients(AccessibleEvents, int, int) is the method every control uses to raise MSAA WinEvents (NotifyWinEvent). Its guard lost the negation between .NET 9 and .NET 10:
// .NET 8
if (IsHandleCreated && AccessibleObject.CanNotifyClients)
// .NET 9
if (IsHandleCreated && !LocalAppContextSwitches.NoClientNotifications)
// .NET 10 and main
if (IsHandleCreated && AppContextSwitches.NoClientNotifications)
The negation was dropped in #12840 ("More OLE related refactoring", 620b123), which renamed LocalAppContextSwitches to AppContextSwitches across 81 files. That PR touched seven lines that use this switch; in the other six the rename kept the expression as it was (four !AppContextSwitches.NoClientNotifications, two without negation that had none before). Only this one lost its !, so it looks like a slip in a mechanical rename rather than a decision; the PR description does not mention accessibility and there are no review comments.
NoClientNotifications means "do not notify accessibility clients" and is false by default, so since .NET 10 NotifyWinEvent is only called when the application has asked for no notifications, that is, never by default. Every other use of the switch in the code base is negated (AccessibleObject.cs, Control.ControlAccessibleObject.cs, MessageBox.cs).
The result is that assistive technologies that rely on MSAA WinEvents stop receiving everything raised through this method: SystemMenuPopupStart/SystemMenuPopupEnd of a ContextMenuStrip, SystemMenuStart/SystemMenuEnd of a MenuStrip, the Focus event of ToolStrip items, and the state, selection, value and name change events raised by the controls.
I am a blind developer and I found this while investigating why JAWS and NVDA behave differently with a WinForms app after moving it to .NET 10. What a JAWS 2026 user gets today when opening a ContextMenuStrip with Shift+F10: "Menu" and nothing else; the arrow keys read nothing for a while, and only after going round the menu a few times do they start reading the items. The menu bar is affected too: the first Alt+F is silent. With the one-character fix applied to a local build of release/10.0, JAWS says "Context menu, Open" on opening and the arrows read every item from the first time; Alt+F says "New, 1 of 3". NVDA is not affected because it uses UIA for these windows.
Measurements: the WinEvents seen from another process on .NET Framework 4.8, .NET 9, .NET 10 and .NET 10 with the fix
I listened to the WinEvents of the repro app below from another process (SetWinEventHook, out of context) while opening a context menu with Shift+F10 and pressing Down twice. For every event I called AccessibleObjectFromEvent.
.NET Framework 4.8 raises the same events (MENUPOPUPSTART idObject=-4 name="DropDown" role=MENUPOPUP, then FOCUS idObject=-4 idChild=1 name="Open" role=MENUITEM...), so .NET 10 is the first version in which they are missing.
.NET 9.0.19, stock — real MSAA events, resolvable:
MENUPOPUPSTART idObject=-4 idChild=0 name="" role=MENUPOPUP
FOCUS idObject=-4 idChild=1 name="Open" role=MENUITEM
FOCUS idObject=-4 idChild=2 name="Edit" role=MENUITEM
.NET 10.0.11, stock — none of them. The only WinEvents left are the ones Windows bridges from the UIA events, which carry a positive idObject and cannot be resolved (AccessibleObjectFromEvent returns E_FAIL):
FOCUS idObject=1 idChild=0 (AccessibleObjectFromEvent hr=0x80004005)
FOCUS idObject=2 idChild=0 (AccessibleObjectFromEvent hr=0x80004005)
.NET 10 with the fix — back to the .NET 9 behaviour:
MENUPOPUPSTART idObject=-4 idChild=0 role=MENUPOPUP
FOCUS idObject=-4 idChild=1 name="Open" role=MENUITEM
FOCUS idObject=-4 idChild=2 name="Edit" role=MENUITEM
The existing unit tests of AccessibilityNotifyClients only check that the call does not throw, which is why the regression went unnoticed.
Steps to reproduce
-
Create a WinForms app targeting net10.0-windows with this in the form:
Button button = new() { Text = "Button with a ContextMenuStrip", AutoSize = true };
ContextMenuStrip menu = new();
menu.Items.Add("&Open");
menu.Items.Add("&Edit");
button.ContextMenuStrip = menu;
Controls.Add(button);
-
From another process, install a WinEvent hook for the app (or use Accessible Event Watcher / AccEvent from the Windows SDK, in WinEvents mode).
-
Focus the button, press Shift+F10, then Down.
-
No EVENT_SYSTEM_MENUPOPUPSTART and no EVENT_OBJECT_FOCUS with idObject = OBJID_CLIENT arrive. The same app targeting net9.0-windows raises them.
I have a fix with unit tests ready and will open a pull request.
.NET version
.NET 10 (10.0.11 runtime, SDK 10.0.303). Still present in
main(checked at 75072a6) and inrelease/10.0(f8eab87).Did it work in .NET Framework?
Yes
Did it work in any of the earlier releases of .NET Core or .NET 5+?
Yes. It works in .NET 8 and .NET 9 (verified with 9.0.19).
Issue description
Control.AccessibilityNotifyClients(AccessibleEvents, int, int)is the method every control uses to raise MSAA WinEvents (NotifyWinEvent). Its guard lost the negation between .NET 9 and .NET 10:The negation was dropped in #12840 ("More OLE related refactoring", 620b123), which renamed
LocalAppContextSwitchestoAppContextSwitchesacross 81 files. That PR touched seven lines that use this switch; in the other six the rename kept the expression as it was (four!AppContextSwitches.NoClientNotifications, two without negation that had none before). Only this one lost its!, so it looks like a slip in a mechanical rename rather than a decision; the PR description does not mention accessibility and there are no review comments.NoClientNotificationsmeans "do not notify accessibility clients" and isfalseby default, so since .NET 10NotifyWinEventis only called when the application has asked for no notifications, that is, never by default. Every other use of the switch in the code base is negated (AccessibleObject.cs,Control.ControlAccessibleObject.cs,MessageBox.cs).The result is that assistive technologies that rely on MSAA WinEvents stop receiving everything raised through this method:
SystemMenuPopupStart/SystemMenuPopupEndof aContextMenuStrip,SystemMenuStart/SystemMenuEndof aMenuStrip, theFocusevent ofToolStripitems, and the state, selection, value and name change events raised by the controls.I am a blind developer and I found this while investigating why JAWS and NVDA behave differently with a WinForms app after moving it to .NET 10. What a JAWS 2026 user gets today when opening a
ContextMenuStripwith Shift+F10: "Menu" and nothing else; the arrow keys read nothing for a while, and only after going round the menu a few times do they start reading the items. The menu bar is affected too: the first Alt+F is silent. With the one-character fix applied to a local build ofrelease/10.0, JAWS says "Context menu, Open" on opening and the arrows read every item from the first time; Alt+F says "New, 1 of 3". NVDA is not affected because it uses UIA for these windows.Measurements: the WinEvents seen from another process on .NET Framework 4.8, .NET 9, .NET 10 and .NET 10 with the fix
I listened to the WinEvents of the repro app below from another process (
SetWinEventHook, out of context) while opening a context menu with Shift+F10 and pressing Down twice. For every event I calledAccessibleObjectFromEvent..NET Framework 4.8 raises the same events (
MENUPOPUPSTART idObject=-4 name="DropDown" role=MENUPOPUP, thenFOCUS idObject=-4 idChild=1 name="Open" role=MENUITEM...), so .NET 10 is the first version in which they are missing..NET 9.0.19, stock — real MSAA events, resolvable:
.NET 10.0.11, stock — none of them. The only WinEvents left are the ones Windows bridges from the UIA events, which carry a positive
idObjectand cannot be resolved (AccessibleObjectFromEventreturnsE_FAIL):.NET 10 with the fix — back to the .NET 9 behaviour:
The existing unit tests of
AccessibilityNotifyClientsonly check that the call does not throw, which is why the regression went unnoticed.Steps to reproduce
Create a WinForms app targeting
net10.0-windowswith this in the form:From another process, install a WinEvent hook for the app (or use Accessible Event Watcher / AccEvent from the Windows SDK, in WinEvents mode).
Focus the button, press Shift+F10, then Down.
No
EVENT_SYSTEM_MENUPOPUPSTARTand noEVENT_OBJECT_FOCUSwithidObject = OBJID_CLIENTarrive. The same app targetingnet9.0-windowsraises them.I have a fix with unit tests ready and will open a pull request.