如何使用UI 自动化使无窗口 ActiveX 控件易于访问
介绍如何使用 Microsoft UI 自动化 API 来确保辅助技术 (AT) 客户端应用程序可以访问无窗口 Microsoft ActiveX 控件。
需要了解的事项
技术
先决条件
- C/C++
- Microsoft Win32 和组件对象模型 (COM) 编程
- 无窗口 ActiveX 控件
- UI 自动化提供程序
Instructions
步骤 1:实现UI 自动化提供程序接口。
若要使应用程序可访问,必须为无窗口 ActiveX 控件实现UI 自动化提供程序接口,包括 IRawElementProviderSimple、IRawElementProviderFragment、IRawElementProviderFragmentRoot 和 IRawElementProviderAdviseEvents。 应像实现基于窗口的控件一样实现这些接口,但以下步骤中所述除外。 有关实现 UIA 提供程序接口的详细信息,请参阅 UI 自动化 提供程序程序员指南。
步骤 2:实现 IServiceProvider 接口。
当客户端需要有关无窗口控件的辅助功能信息时,控件容器会调用控件的 IServiceProvider::QueryService 方法来检索控件的 IRawElementProviderSimple 接口指针。
以下示例演示如何实现 QueryService 方法。
STDMETHODIMP CMyAccessibleUIAControl::QueryService(REFGUID guidService,
REFIID riid, void **ppvObject)
{
if (ppvObject == NULL)
{
return E_INVALIDARG;
}
*ppvObject = NULL;
HRESULT hr = E_FAIL;
if (guidService == __uuidof(IRawElementProviderSimple))
{
hr = QueryInterface(riid, ppvObject);
}
return hr;
}
步骤 3:实现 IRawElementProviderFragment::Navigate 方法。
当调用无窗口控件的 IRawElementProviderFragment::Navigate 方法导航到无窗口控件的根提供程序的父级或同级时, Navigate 方法应委托给控件容器的 IRawElementProviderWindowlessSite::GetAdjacentFragment 方法。
以下示例演示如何实现 Navigate 方法。
STDMETHODIMP CMyAccessibleUIAControl::Navigate(NavigateDirection direction,
IRawElementProviderFragment **ppRetVal)
{
if (ppRetVal == NULL)
{
return E_INVALIDARG;
}
*ppRetVal = NULL;
HRESULT hr = E_FAIL;
IRawElementProviderWindowlessSite *pWindowlessSite = NULL;
if (direction == NavigateDirection_Parent)
{
// Query the control container's windowless site
// for the parent.
if (SUCCEEDED(m_pClientSite->QueryInterface(
IID_PPV_ARGS(&pWindowlessSite))))
{
hr = pWindowlessSite->GetAdjacentFragment(direction, ppRetVal);
}
}
else if (direction == NavigateDirection_FirstChild)
{
// GetFragmentForChild is an application-defined function that
// retrieves the first or last child fragment.
hr = GetFragmentForChild(FIRST, ppRetVal);
}
else if (direction == NavigateDirection_LastChild)
{
hr = GetFragmentForChild(LAST, ppRetVal);
}
SafeRelease(&pWindowlessSite);
return S_OK;
}
步骤 4:实现 IRawElementProviderFragment::GetRuntimeId 方法。
当无窗口控件收到对其 IRawElementProviderFragment::GetRuntimeId 方法的调用时,该控件必须执行以下操作:
- 通过调用控件站点的 IRawElementProviderWindowlessSite::GetRuntimeIdPrefix 方法检索运行时 ID 前缀。
- 通过将整数追加到运行时 ID 前缀,为控件创建唯一的运行时 ID。
- 将运行时 ID 返回给调用方。
以下示例演示如何实现 GetRuntimeId 方法。
STDMETHODIMP CMyAccessibleUIAControl::GetRuntimeId(SAFEARRAY **ppRetVal)
{
if (ppRetVal == NULL)
{
return E_INVALIDARG;
}
*ppRetVal = NULL;
HRESULT hr = E_FAIL;
IRawElementProviderWindowlessSite *pWindowlessSite = NULL;
if (SUCCEEDED(m_pClientSite->QueryInterface(IID_PPV_ARGS(&pWindowlessSite))))
{
// Create a safe array to hold runtime ID.
SAFEARRAY *psa = SafeArrayCreateVector(VT_I4, 1, 3);
if (psa == NULL)
{
hr = E_OUTOFMEMORY;
}
// Retrieve the runtime ID prefix from the control container. The prefix
// consists of UiaAppendRuntimeId followed by the windowless site ID.
if (SUCCEEDED(hr))
{
hr = pWindowlessSite->GetRuntimeIdPrefix(&psa);
}
if (SUCCEEDED(hr))
{
// Append this fragment's ID to the retrieved runtime ID prefix.
long i = 2;
hr = SafeArrayPutElement(psa, &i, (void*)&m_Id);
}
if (SUCCEEDED(hr))
{
*ppRetVal = psa;
}
}
SafeRelease(&pWindowlessSite);
return hr;
}
相关主题