托管 UI 自动化无窗口 ActiveX 控件

了解如何创建能够托管实现 Microsoft UI 自动化的无窗口 Microsoft ActiveX 控件的控件容器。 通过使用此处所述的步骤,可以确保控制容器中托管的任何UI 自动化无窗口控件都可以通过辅助技术 (AT) 客户端应用程序进行访问。

需要了解的事项

技术

先决条件

  • C/C++
  • Microsoft Win32 和组件对象模型 (COM) 编程
  • 无窗口 ActiveX 控件
  • UI 自动化提供程序

Instructions

步骤 1:代表无窗口控件提供 IRawElementProviderSimple 接口。

每当系统需要 IRawElementProviderSimple 指针作为无窗口控件的根时,系统会查询控件容器。 为了检索指针,容器调用无窗口控件的 IServiceProvider::QueryService 方法的实现。

如果控件容器具有UI 自动化实现,它可以返回指向系统的无窗口控件的 IRawElementProviderSimple 指针。

如果控件容器具有 Microsoft Active Accessibility 实现,请调用 UiaIAccessibleFromProvider 函数以获取表示控件的 IAccessible 接口指针,然后将 IAccessible 接口指针返回到系统。

步骤 2:实现 IRawElementProviderWindowlessSite 接口。

控件容器实现 IRawElementProviderWindowlessSite 接口,使基于UI 自动化的无窗口控件能够传达其辅助功能信息。

  1. 实现 IRawElementProviderWindowlessSite::GetRuntimeIdPrefix

    无窗口控件片段必须为自身创建唯一的运行时 ID。 为了创建其运行时 ID,无窗口控件片段通过调用控件站点的 GetRuntimeIdPrefix 方法检索前缀值,然后将相对于无窗口控件中所有其他片段唯一的整数值追加到前缀。

    无窗口控件的控制站点应通过形成包含常量 UiaAppendRuntimeIdSAFEARRAY,后跟站点唯一的整数值来实现 GetRuntimeIdPrefix 方法。

    此示例演示如何返回无窗口控件的运行时 ID 前缀。

    IFACEMETHODIMP CProviderWindowlessSite::GetRuntimeIdPrefix(   
         SAFEARRAY **ppsaPrefix)   
    {   
        if (ppsaPrefix == NULL) 
        {
            return E_INVALIDARG;
        }
    
        // m_siteIndex is the index of the windowless control's
        // site. It is defined by the control container.
        int rId[] = { UiaAppendRuntimeId, m_siteIndex };
        SAFEARRAY *psa = SafeArrayCreateVector(VT_I4, 0, 2);  
        if (psa == NULL)
        {
            return E_OUTOFMEMORY;
        }
    
        for (LONG i = 0; i < 2; i++)
        {
            SafeArrayPutElement(psa, &i, (void*)&(rId[i]));
        }
    
        *ppsaPrefix = psa;  
        return S_OK;  
    }  
    
  2. 实现 IRawElementProviderWindowlessSite::GetAdjacentFragment 方法。

    实现UI 自动化的控件必须返回指向控件的父片段提供程序的指针。

    若要返回片段的父级,实现 IRawElementProviderFragment 接口的对象必须能够实现 Navigate 方法。 对于无窗口控件,实现 Navigate 是困难的,因为控件可能无法确定它在父对象的可访问树中的位置。 IRawElementProviderWindowlessSite::GetAdjacentFragment 方法使无窗口控件能够查询其站点中的相邻片段,然后将该片段返回到调用 Navigate 的客户端。

    此示例演示控件容器如何检索无窗口控件的父片段。

    IFACEMETHODIMP CProviderWindowlessSite::GetAdjacentFragment(
            enum NavigateDirection direction, IRawElementProviderFragment **ppFragment)   
    {
        if (ppFragment == NULL)
        {
            return E_INVALIDARG;
        }
    
        *ppFragment = NULL;
        HRESULT hr = S_OK;
    
        switch (direction)
        {
            case NavigateDirection_Parent:
                {  
                    IRawElementProviderSimple *pSimple = NULL;
    
                    // Call an application-defined function to retrieve the
                    // parent provider interface.
                    hr = GetParentProvider(&pSimple);  
                    if (SUCCEEDED(hr))  
                    {  
                        // Get the parent's IRawElementProviderFragment interface.
                        hr = pSimple->QueryInterface(IID_PPV_ARGS(ppFragment));  
                        pSimple->Release();  
                    } 
                }  
                break;  
    
            case NavigateDirection_FirstChild:
            case NavigateDirection_LastChild:
                hr = E_INVALIDARG;
                break;
    
            // Ignore NavigateDirection_NextSibling and NavigateDirection_PreviousSibling
            // because there are no adjacent fragments.
            default:  
                break;  
        }  
    
        return hr;  
    }   
    

步骤 3:可选:实现 IRawElementProviderHostingAccessibles 接口。

如果控件容器具有UI 自动化提供程序实现,该实现是辅助功能树的根,其中包含支持 Microsoft Active Accessibility 的无窗口 ActiveX 控件,则实现 IRawElementProviderHostingAccessibles 接口。 IRawElementProviderHostingAccessibles 接口有一个方法 GetEmbeddedAccessibles,该方法检索控件容器托管的所有基于 Active Accessibility 的无窗口 ActiveX 控件的 IAccessible 接口指针。

如何托管 MSAA 无窗口 ActiveX 控件

无窗口 ActiveX 控件辅助功能