Skip to content

Commit 2fb59e7

Browse files
committed
Resolve native Start from live XAML AutomationId
1 parent ea4c4e9 commit 2fb59e7

1 file changed

Lines changed: 85 additions & 1 deletion

File tree

‎Src/StartMenu/StartMenuDLL/Win11StartButton.cpp‎

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@
1313
#include "ResourceHelper.h"
1414

1515
#include <Windows.UI.Xaml.h>
16+
#include <Windows.UI.Xaml.Automation.h>
1617
#include <xamlom.h>
1718
#include <ocidl.h>
19+
#include <roapi.h>
20+
#include <winstring.h>
1821
#include <unordered_map>
22+
23+
#pragma comment(lib, "runtimeobject.lib")
1924
#include <vector>
2025

2126
static const GUID CLSID_OpenShellStartButtonTap =
@@ -156,6 +161,8 @@ class CWin11StartButtonTap: public IObjectWithSite, public IVisualTreeServiceCal
156161
m_Visual->UnadviseVisualTreeChange(static_cast<IVisualTreeServiceCallback*>(this));
157162
m_Advised = false;
158163
}
164+
m_AutomationProperties.Release();
165+
m_Diagnostics.Release();
159166
m_Visual.Release();
160167
m_Site.Release();
161168

@@ -203,9 +210,14 @@ class CWin11StartButtonTap: public IObjectWithSite, public IVisualTreeServiceCal
203210
return hr;
204211
}
205212

213+
HRESULT diagnosticsHr = site->QueryInterface(__uuidof(IXamlDiagnostics), (void**)&m_Diagnostics);
214+
LogToFile(STARTUP_LOG, L"Win11StartButton: XamlDiagnostics 0x%08X", diagnosticsHr);
215+
206216
if (!CreateDispatchWindow())
207217
{
208218
DWORD error = GetLastError();
219+
m_AutomationProperties.Release();
220+
m_Diagnostics.Release();
209221
m_Visual.Release();
210222
m_Site.Release();
211223
BalanceInjectionReference();
@@ -238,6 +250,8 @@ class CWin11StartButtonTap: public IObjectWithSite, public IVisualTreeServiceCal
238250
SetWindowLongPtr(dispatch, GWLP_USERDATA, 0);
239251
DestroyWindow(dispatch);
240252
}
253+
m_AutomationProperties.Release();
254+
m_Diagnostics.Release();
241255
m_Visual.Release();
242256
m_Site.Release();
243257
BalanceInjectionReference();
@@ -385,6 +399,8 @@ class CWin11StartButtonTap: public IObjectWithSite, public IVisualTreeServiceCal
385399
m_Advised = false;
386400
}
387401

402+
m_AutomationProperties.Release();
403+
m_Diagnostics.Release();
388404
m_Visual.Release();
389405
m_Site.Release();
390406

@@ -519,19 +535,85 @@ class CWin11StartButtonTap: public IObjectWithSite, public IVisualTreeServiceCal
519535
return primary;
520536
}
521537

538+
HRESULT EnsureAutomationProperties( void )
539+
{
540+
if (m_AutomationProperties)
541+
return S_OK;
542+
543+
static const wchar_t classNameText[] = L"Windows.UI.Xaml.Automation.AutomationProperties";
544+
HSTRING className = NULL;
545+
HRESULT hr = WindowsCreateString(classNameText, (UINT32)_countof(classNameText) - 1, &className);
546+
if (FAILED(hr))
547+
return hr;
548+
549+
hr = RoGetActivationFactory(className,
550+
__uuidof(ABI::Windows::UI::Xaml::Automation::IAutomationPropertiesStatics),
551+
(void**)&m_AutomationProperties);
552+
WindowsDeleteString(className);
553+
return hr;
554+
}
555+
556+
HRESULT ResolveAutomationIdDirect( InstanceHandle handle, CString *automationId )
557+
{
558+
automationId->Empty();
559+
if (!m_Diagnostics)
560+
return E_NOINTERFACE;
561+
562+
CComPtr<IInspectable> inspectable;
563+
HRESULT hr = m_Diagnostics->GetIInspectableFromHandle(handle, &inspectable);
564+
if (FAILED(hr) || !inspectable)
565+
return FAILED(hr) ? hr : E_FAIL;
566+
567+
CComPtr<ABI::Windows::UI::Xaml::IDependencyObject> dependencyObject;
568+
hr = inspectable->QueryInterface(
569+
__uuidof(ABI::Windows::UI::Xaml::IDependencyObject),
570+
(void**)&dependencyObject);
571+
if (FAILED(hr) || !dependencyObject)
572+
return FAILED(hr) ? hr : E_NOINTERFACE;
573+
574+
hr = EnsureAutomationProperties();
575+
if (FAILED(hr) || !m_AutomationProperties)
576+
return FAILED(hr) ? hr : E_NOINTERFACE;
577+
578+
HSTRING value = NULL;
579+
hr = m_AutomationProperties->GetAutomationId(dependencyObject, &value);
580+
if (SUCCEEDED(hr) && value)
581+
{
582+
UINT32 length = 0;
583+
const wchar_t *text = WindowsGetStringRawBuffer(value, &length);
584+
if (text && length)
585+
automationId->SetString(text, (int)length);
586+
}
587+
if (value)
588+
WindowsDeleteString(value);
589+
return hr;
590+
}
591+
522592
HRESULT ResolveStartControl( InstanceHandle handle, const StartElement &element, bool *isStartControl )
523593
{
524594
*isStartControl = false;
525595
if (!IsStartControlCandidate(element))
526596
return S_OK;
527597

528-
// Older taskbar implementations may expose a distinct x:Name.
529598
if (element.name.CompareNoCase(L"StartButton") == 0)
530599
{
531600
*isStartControl = true;
532601
return S_OK;
533602
}
534603

604+
CString directId;
605+
HRESULT directHr = ResolveAutomationIdDirect(handle, &directId);
606+
if (SUCCEEDED(directHr))
607+
{
608+
*isStartControl = directId.CompareNoCase(L"StartButton") == 0;
609+
LogToFile(STARTUP_LOG, L"Win11StartButton: direct AutomationId '%s' start=%d",
610+
(LPCWSTR)directId, *isStartControl ? 1 : 0);
611+
return S_OK;
612+
}
613+
614+
LogToFile(STARTUP_LOG, L"Win11StartButton: direct AutomationId failed 0x%08X; using property-chain fallback",
615+
directHr);
616+
535617
unsigned int sourceCount = 0;
536618
unsigned int valueCount = 0;
537619
PropertyChainSource *sources = NULL;
@@ -779,6 +861,8 @@ class CWin11StartButtonTap: public IObjectWithSite, public IVisualTreeServiceCal
779861
CRITICAL_SECTION m_Lock;
780862
CComPtr<IUnknown> m_Site;
781863
CComPtr<IVisualTreeService> m_Visual;
864+
CComPtr<IXamlDiagnostics> m_Diagnostics;
865+
CComPtr<ABI::Windows::UI::Xaml::Automation::IAutomationPropertiesStatics> m_AutomationProperties;
782866
InstanceHandle m_PrimaryStart;
783867
unsigned int m_NextDiscoveryOrder;
784868
bool m_InjectionReferenceBalanced;

0 commit comments

Comments
 (0)