winforms icon indicating copy to clipboard operation
winforms copied to clipboard

System.Windows.Automation.InvokePattern.Invoke blocks on a menu item.

Open lovettchris opened this issue 1 year ago • 19 comments

.NET version

7.0.403

Did it work in .NET Framework?

Yes

Did it work in any of the earlier releases of .NET Core or .NET 5+?

Don't know, it works in .NET Framework 4.6.2, but not in latest version of .NET Framework 4.8

Issue description

Run the unit test in the following solution. Notice that the unit test hangs on line 80 of UnitTest1.cs which is the InvokePattern.Invoke call on the FIle/Open... menu item. This makes it impossible to test any menu item using System.Automation?

Steps to reproduce

  1. on Windows 11 22H2 build 22621.2361
  2. Load this solution into VS 2022
  3. Run Test/Debug all tests
  4. wait for windows open file dialog to appear
  5. Notice it never disappears
  6. hit break in the debugger and you will see it is blocked on line 80 of UnitTest1.cs.

WinFormsApp1.zip

lovettchris avatar Nov 07 '23 23:11 lovettchris

@Olina-Zhang can your team please test this to confirm?

elachlan avatar Nov 07 '23 23:11 elachlan

@elachlan we can repro this issue on .NET 6.0, 7.0, 8.0 and 9.0. Repro

Amy-Li03 avatar Nov 08 '23 06:11 Amy-Li03

[like] Chris Lovett reacted to your message:

lovettchris avatar Nov 09 '23 00:11 lovettchris

I and @Amy-Li03 discussed this issue, and we think this is not a a11y issue.

Epica3055 avatar Nov 14 '23 06:11 Epica3055

@Epica3055 let's discuss in the next meeting.

merriemcgaw avatar Nov 14 '23 19:11 merriemcgaw

@Amy-Li03 - Could you please verify if this issue reproduces on 4.7.2 and 4.8.1 and if it depends on any AccessibilityImprovements.Level?

Tanya-Solyanik avatar Nov 15 '23 01:11 Tanya-Solyanik

Attached is a .NET Framework 4.7.2 version of the above test app and the test passes (the invoke does not block) WindowsFormsApp1.zip

If you then change the project properties to target .NET Framework 4.8, the test fails as per my original bug report.

lovettchris avatar Nov 15 '23 03:11 lovettchris

@Tanya-Solyanik , this issue reproduces on .NET Framework 4.8 & 4.8.1 and it doesn't repro on 4.7.2 and its previous versions. Also it doesn't depend on AccessibilityImprovements.Level, add following quirk to app.config file, issue still repro.

<runtime>
	  <AppContextSwitchOverrides value="Switch.UseLegacyAccessibilityFeatures=false;Switch.UseLegacyAccessibilityFeatures.2=false;Switch.UseLegacyAccessibilityFeatures.3=false;Switch.UseLegacyAccessibilityFeatures.4=false;Switch.UseLegacyAccessibilityFeatures.5=false" />
</runtime>

Amy-Li03 avatar Nov 15 '23 06:11 Amy-Li03

.netFramwork4.7 project: The function RawInvokePattern_Invoke(hobj) return 0

UIAutomationClientsideProviders.dll!MS.Internal.AutomationProxies.Accessible.DoDefaultAction() Line 527	C#
UIAutomationClientsideProviders.dll!MS.Internal.AutomationProxies.MsaaNativeProvider.CallDoDefaultAction() Line 820	C#
UIAutomationClientsideProviders.dll!MS.Internal.AutomationProxies.MsaaNativeProvider.System.Windows.Automation.Provider.IInvokeProvider.Invoke() Line 515	C#
[Native to Managed Transition]	
[Managed to Native Transition]	
 UIAutomationClient.dll!MS.Internal.Automation.UiaCoreApi.InvokePattern_Invoke(MS.Internal.Automation.SafePatternHandle hobj) Line 659	C#

netFramwork4.8.1 project: The function RawInvokePattern_Invoke(hobj) return -2146233083

UIAutomationClient.dll!MS.Internal.Automation.UiaCoreApi.CheckError(int hr) Line 1017	C#
UIAutomationClient.dll!MS.Internal.Automation.UiaCoreApi.InvokePattern_Invoke(MS.Internal.Automation.SafePatternHandle hobj) Line 660	C#
UIAutomationClient.dll!System.Windows.Automation.InvokePattern.Invoke() Line 28	C#
TestProject1.dll!TestProject1.UnitTest1.Invoke(System.Windows.Automation.AutomationElement e) Line 99	C#
TestProject1.dll!TestProject1.UnitTest1.InvokeMenuItem(System.Windows.Automation.AutomationElement window, string menuItemName) Line 91	C#
TestProject1.dll!TestProject1.UnitTest1.TestMethod1() Line 35	C#

LeafShi1 avatar Apr 03 '24 04:04 LeafShi1

@LeafShi1 - does 4.8.1 sample block as well?

Tanya-Solyanik avatar Apr 06 '24 02:04 Tanya-Solyanik

@LeafShi1 - does 4.8.1 sample block as well?

Yes

LeafShi1 avatar Apr 08 '24 01:04 LeafShi1

@LeafShi1 - what other controls does this reproduce for?

Tanya-Solyanik avatar Apr 08 '24 04:04 Tanya-Solyanik

@LeafShi1 - what other controls does this reproduce for?

  • I tried this in a button, it work well. WindowsFormsApp9.zip
  • Adding a ComboBox to the MenuStrip, execute Invoke on the ComboBox, it also work well.
  • Changing the fd.ShowDialog(this) to MessageBox.Show("....."), of the WinFormsApp1.zip project, then run the unit test, the Invoke is also blocked.

So this problem only reproduces in MenuStrip, and the invoke event of menuItem needs to pop up a new windows page.

LeafShi1 avatar Apr 08 '24 07:04 LeafShi1

@LeafShi1 - do we have any unit tests that call the Invoke method on controls? If not, could you please add some?

Tanya-Solyanik avatar Apr 09 '24 22:04 Tanya-Solyanik

@LeafShi1 - do we have any unit tests that call the Invoke method on controls? If not, could you please add some?

Many controls contain an IsPatternSupported test but the Invoke method on the control is not tested? Do we need to complete all of them? Such as https://github.com/dotnet/winforms/blob/9313f05e84328c3176eb7d80497c9505cd8aaebf/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/AccessibleObjects/HScrollBar.ScrollBarFirstLineButtonAccessibleObjectTests.cs#L128-L135

LeafShi1 avatar Apr 10 '24 16:04 LeafShi1

Start with the MenuItems mentioned in this bug and buttons, we'll see if we need to add more later.

Tanya-Solyanik avatar Apr 10 '24 17:04 Tanya-Solyanik

Start with the MenuItems mentioned in this bug and buttons, we'll see if we need to add more later.

Try to add following test, the System.Windows.Forms.AccessibleObject.Invoke blocks on Button and MenuItem. But System.Windows.Automation.InvokePattern.Invoke only blocks on MenuItem.

    {
        int callCount = 0;
        using Button button = new()
        {
            AccessibleRole = AccessibleRole.Default
        };

        button.CreateControl();
        ButtonAccessibleObject buttonAccessibleObject = new(button);

        button.Click += (sender, e) =>
        {
            MessageBox.Show("TestDialog");
            callCount++;
        };

        buttonAccessibleObject.Invoke();
        Assert.Equal(1, callCount);

        foreach (Form form in Application.OpenForms)
        {
            if (form.Text == "TestDialog")
            {
                form.Close();
                break;
            }
        }
    }

image

LeafShi1 avatar Apr 15 '24 07:04 LeafShi1

This is interesting, my test application was blocking on a button. I was doing a cross process access though. I have a driver application and a test application, and the driver is invoking buttons in the test app.

Let's test only for menuitems for now. Going forward we can start replacing code that send clicks to buttons(or other controls) with AccessibleObject.Invoke in tests that excersize control functionality.

Tanya-Solyanik avatar Apr 16 '24 21:04 Tanya-Solyanik

Well after waiting for almost a year I've given up waiting. I ended up implementing my own custom automation layer for my menu items so that I could invoke them asynchronously. This gets my unit tests back up and running finally. See this commit: https://github.com/microsoft/XmlNotepad/commit/484713b6bd527a27644109994c139f3dd007deb3 And specifically the HiddenMenuItems control that provides new custom AutomationObjects for my menu items with a feature that can invoke some of them asynchronously (specifically the ones that pop up a modal file open or save dialog).

clovett avatar Sep 21 '24 12:09 clovett