diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt index a86ec47001..daf3fda3cc 100644 --- a/.github/actions/spelling/expect/expect.txt +++ b/.github/actions/spelling/expect/expect.txt @@ -1772,6 +1772,7 @@ uldash uldb ULONGLONG ulwave +Unaccess Unadvise unattend UNCPRIORITY diff --git a/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp b/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp index 605753bc30..9967c5ac2b 100644 --- a/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp +++ b/src/cascadia/TerminalControl/InteractivityAutomationPeer.cpp @@ -49,7 +49,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation void InteractivityAutomationPeer::ParentProvider(AutomationPeer parentProvider) { - _parentProvider = parentProvider; + // LOAD-BEARING: use _parentProvider->ProviderFromPeer(_parentProvider) instead of this->ProviderFromPeer(*this). + // Since we split the automation peer into TermControlAutomationPeer and InteractivityAutomationPeer, + // using "this" returns null. This can cause issues with some UIA Client scenarios like any navigation in Narrator. + _parentProvider = parentProvider ? parentProvider.as().ProviderFromPeer(parentProvider) : nullptr; } // Method Description: @@ -181,15 +184,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation XamlAutomation::ITextRangeProvider InteractivityAutomationPeer::_CreateXamlUiaTextRange(UIA::ITextRangeProvider* returnVal) const { - // LOAD-BEARING: use _parentProvider->ProviderFromPeer(_parentProvider) instead of this->ProviderFromPeer(*this). - // Since we split the automation peer into TermControlAutomationPeer and InteractivityAutomationPeer, - // using "this" returns null. This can cause issues with some UIA Client scenarios like any navigation in Narrator. - const auto parent{ _parentProvider.get() }; - if (!parent) + if (!_parentProvider) { return nullptr; } - const auto xutr = winrt::make_self(returnVal, parent.as().ProviderFromPeer(parent)); + const auto xutr = winrt::make_self(returnVal, _parentProvider); return xutr.as(); }; @@ -201,22 +200,24 @@ namespace winrt::Microsoft::Terminal::Control::implementation // - com_array of Xaml Wrapped UiaTextRange (ITextRangeProviders) com_array InteractivityAutomationPeer::WrapArrayOfTextRangeProviders(SAFEARRAY* textRanges) { + if (!_parentProvider) + { + return {}; + } + // transfer ownership of UiaTextRanges to this new vector auto providers = SafeArrayToOwningVector<::Microsoft::Terminal::TermControlUiaTextRange>(textRanges); - auto count = gsl::narrow(providers.size()); + const auto len = gsl::narrow(providers.size()); + com_array result{ len }; - std::vector vec; - vec.reserve(count); - for (auto i = 0; i < count; i++) + for (uint32_t i = 0; i < len; ++i) { if (auto xutr = _CreateXamlUiaTextRange(providers[i].detach())) { - vec.emplace_back(std::move(xutr)); + result[i] = std::move(xutr); } } - com_array result{ vec }; - return result; } } diff --git a/src/cascadia/TerminalControl/InteractivityAutomationPeer.h b/src/cascadia/TerminalControl/InteractivityAutomationPeer.h index 4f5b4a79c6..d69d19d16e 100644 --- a/src/cascadia/TerminalControl/InteractivityAutomationPeer.h +++ b/src/cascadia/TerminalControl/InteractivityAutomationPeer.h @@ -80,7 +80,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation ::Microsoft::WRL::ComPtr<::Microsoft::Terminal::TermControlUiaProvider> _uiaProvider; winrt::Microsoft::Terminal::Control::implementation::ControlInteractivity* _interactivity; - weak_ref _parentProvider; + winrt::Windows::UI::Xaml::Automation::Provider::IRawElementProviderSimple _parentProvider{ nullptr }; til::rect _controlBounds{}; til::rect _controlPadding{}; diff --git a/src/cascadia/TerminalControl/InteractivityAutomationPeer.idl b/src/cascadia/TerminalControl/InteractivityAutomationPeer.idl index 9eb79a6329..e99a79c5ad 100644 --- a/src/cascadia/TerminalControl/InteractivityAutomationPeer.idl +++ b/src/cascadia/TerminalControl/InteractivityAutomationPeer.idl @@ -3,7 +3,7 @@ namespace Microsoft.Terminal.Control { [default_interface] runtimeclass InteractivityAutomationPeer : - Windows.UI.Xaml.Automation.Peers.AutomationPeer, + Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer, Windows.UI.Xaml.Automation.Provider.ITextProvider { diff --git a/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp b/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp index aaf6cfaf58..bf49dd2e85 100644 --- a/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp +++ b/src/cascadia/TerminalControl/TermControlAutomationPeer.cpp @@ -121,6 +121,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation // GH#13978: If the TermControl has already been removed from the UI tree, XAML might run into weird bugs. // This will prevent the `dispatcher.RunAsync` calls below from raising UIA events on the main thread. _termControl = {}; + + // Solve the circular reference between us and the content automation peer. + _contentAutomationPeer.ParentProvider(nullptr); } // Method Description: diff --git a/src/cascadia/inc/cppwinrt_utils.h b/src/cascadia/inc/cppwinrt_utils.h index 5bdd5f2d36..7377b5848f 100644 --- a/src/cascadia/inc/cppwinrt_utils.h +++ b/src/cascadia/inc/cppwinrt_utils.h @@ -324,9 +324,11 @@ std::vector> SafeArrayToOwningVector(SAFEARRAY* safeArray) std::vector> result{ gsl::narrow(count) }; for (int i = 0; i < count; i++) { - result[i].attach(pVals[i]); + result[i] = pVals[i]; } + THROW_IF_FAILED(SafeArrayUnaccessData(safeArray)); + THROW_IF_FAILED(SafeArrayDestroy(safeArray)); return result; } diff --git a/src/types/ScreenInfoUiaProviderBase.cpp b/src/types/ScreenInfoUiaProviderBase.cpp index 3a3b473a65..852605a8fa 100644 --- a/src/types/ScreenInfoUiaProviderBase.cpp +++ b/src/types/ScreenInfoUiaProviderBase.cpp @@ -234,7 +234,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetSelection(_Outptr_result_maybenull_ UiaTracing::TextProvider::GetSelection(*this, *range.Get()); LONG currentIndex = 0; - hr = SafeArrayPutElement(*ppRetVal, ¤tIndex, range.Detach()); + hr = SafeArrayPutElement(*ppRetVal, ¤tIndex, range.Get()); if (FAILED(hr)) { SafeArrayDestroy(*ppRetVal); @@ -278,7 +278,7 @@ IFACEMETHODIMP ScreenInfoUiaProviderBase::GetVisibleRanges(_Outptr_result_mayben UiaTracing::TextProvider::GetVisibleRanges(*this, *range.Get()); LONG currentIndex = 0; - hr = SafeArrayPutElement(*ppRetVal, ¤tIndex, range.Detach()); + hr = SafeArrayPutElement(*ppRetVal, ¤tIndex, range.Get()); if (FAILED(hr)) { SafeArrayDestroy(*ppRetVal);