プロバイダー用 IAccessibleEx の実装

このセクションでは、IAccessibleEx インターフェイスを実装して、Microsoft Active Accessibility サーバーに Microsoft UI オートメーション プロバイダー機能を追加する方法について説明します。

IAccessibleEx を実装する前に、次の要件を考慮してください。

  • ベースライン Microsoft Active Accessibility のユーザー補助の高いオブジェクト階層をクリーンする必要があります。 IAccessibleEx は、既存のユーザー補助の高いオブジェクト階層の問題を修正できません。 オブジェクト モデル構造に関する問題は、IAccessibleEx を実装する前に、Microsoft Active Accessibility の実装で修正する必要があります。
  • IAccessibleEx の実装は、Microsoft Active Accessibility 仕様とUI オートメーション仕様の両方に準拠している必要があります。 ツールは、両方の仕様でコンプライアンスを検証するために使用できます。 詳細については、「アクセシビリティのテスト」および「UI オートメーション検証 (UIA 検証) テスト オートメーション ツール」を参照してください。

IAccessibleEx の実装には、次の主な手順が必要です。

  • このオブジェクトまたは別のオブジェクトで IAccessibleEx インターフェイスを検出できるように、ユーザー補助の高いオブジェクトに IServiceProvider を実装します。
  • アクセス可能なオブジェクトに IAccessibleEx を実装します。
  • Microsoft Active Accessibility で親オブジェクト (リスト アイテムなど) の IAccessible インターフェイスで表される、Microsoft Active Accessibility の子項目に対してユーザー補助の高いオブジェクトを作成します。 これらのオブジェクトに IAccessibleEx を実装します。
  • ユーザー補助の高いすべてのオブジェクトに IRawElementProviderSimple を実装します。
  • ユーザー補助の高いオブジェクトに適切なコントロール パターン インターフェイスを実装します。

IServiceProvider インターフェイスの実装

コントロールの IAccessibleEx の実装は別のオブジェクトに存在する可能性があるため、クライアント アプリケーションはこのインターフェイスを取得するために QueryInterface に依存することはできません。 代わりに、クライアントは IServiceProvider::QueryService を呼び出す必要があります。 このメソッドの実装例では、IAccessibleEx が別のオブジェクトに実装されていないことを前提としています。そのため、メソッドは単にQueryInterface を呼び出します。

           
HRESULT CListboxAccessibleObject::QueryService(REFGUID guidService, REFIID riid, LPVOID *ppvObject)
{
    if (ppvObject == NULL)
    {
        return E_INVALIDARG;
    }
    *ppvObject = NULL;
    if (guidService == __uuidof(IAccessibleEx))
    {
        return QueryInterface(riid, ppvObject);
    }
    else 
    {
        return E_NOINTERFACE;
    }
};      

IAccessibleEx インターフェイスの実装

Microsoft Active Accessibility では、UI 要素は常に IAccessible インターフェイスと子 ID によって識別されます。 IAccessible の単一インスタンスは、複数の UI 要素を表すことができます。

IAccessibleEx インスタンスは単一の UI 要素のみを表しているため、各 IAccessible と子 ID のペアを単一の IAccessibleEx インスタンスにマップする必要があります。 IAccessibleEx には、このマッピングを処理する次の 2 つのメソッドが含まれています。

  • GetObjectForChild— 指定された子の IAccessibleEx インターフェイスを取得します。 このメソッドは、IAccessibleEx 実装で指定された子 ID が認識されない場合、指定された子の IAccessibleEx がない場合、または子要素を表す場合に NULL を返します。
  • GetIAccessiblePairIAccessibleEx 要素の IAccessible インターフェイスと子 ID を取得します。 子 ID を使用しない IAccessible 実装の場合、このメソッドでは対応する IAccessible オブジェクトと CHILDID_Standard Edition LF を取得します。

次の例は、カスタム リスト ビューの項目に対する GetObjectForChild メソッドと GetIAccessiblePair メソッドの実装を示しています。 このメソッドを使用すると、UI オートメーションは IAccessible と子 ID のペアを対応する IAccessibleEx インスタンスにマップできます。

           
HRESULT CListboxAccessibleObject::GetObjectForChild(
    long idChild, IAccessibleEx **ppRetVal)
{ 
    VARIANT vChild;
    vChild.vt = VT_I4;
    vChild.lVal = idChild;
    HRESULT hr = ValidateChildId(vChild);
    if (FAILED(hr))
    {
        return E_INVALIDARG;
    }
    // List item accessible objects are stored as an array of
    // pointers; for the purpose of this example it is assumed that 
    // the list contents will not change. Accessible objects are
    // created only when needed.
    if (itemProviders[idChild - 1] == NULL)
    {
        // Create an object that supports UI Automation and
        // IAccessibleEx for the item.
        itemProviders[idChild - 1] = 
          new CListItemAccessibleObject(idChild, 
          g_pListboxControl);
        if (itemProviders[idChild - 1] == NULL)
        {
            return E_OUTOFMEMORY;
        }
    }
    IAccessibleEx* pAccEx = static_cast<IAccessibleEx*>
      (itemProviders[idChild - 1]);
    if (pAccEx != NULL)
    {
      pAccEx->AddRef();
    }
    *ppRetVal = pAccEx;
    return S_OK; 
}

HRESULT CListItemAccessibleObject::GetIAccessiblePair(
    IAccessible **ppAcc, long *pidChild)
{ 
    if (ppAcc == NULL || pidChild == NULL)
    {
        return E_INVALIDARG;   
    }

                CListboxAccessibleObject* pParent = 
        m_control->GetAccessibleObject();

    HRESULT hr = pParent->QueryInterface( 
        __uuidof(IAccessible), (void**)ppAcc);
    if (FAILED(hr))
    {
        *pidChild = 0;
        return E_NOINTERFACE;
    }
    *pidChild = m_childID; 
    return S_OK; 
}
}

ユーザー補助の高いオブジェクトの実装で子 ID を使用しない場合でも、次のコード スニペットに示すようにメソッドを実装できます。

           

    // This sample implements IAccessibleEx on the same object; it could use a tear-off
    // or inner object instead.
    class MyAccessibleImpl: public IAccessible,
                        public IAccessibleEx,
                        public IRawElementProviderSimple
    {
    public:
    ...
   HRESULT STDMETHODCALLTYPE GetObjectForChild( long idChild, IAccessibleEx **ppRetVal )
    {
        // This implementation does not support child IDs.
        *ppRetVal = NULL;
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE GetIAccessiblePair( IAccessible ** ppAcc, long * pidChild )
    {
        // This implementation assumes that IAccessibleEx is implemented on same object as
        // IAccessible.
        *ppAcc = static_cast<IAccessible *>(this);
        (*ppAcc)->AddRef();
        *pidChild = CHILDID_SELF;
        return S_OK;
    }

IRawElementProviderSimple インターフェイスを実装する

サーバーで IRawElementProviderSimple を使用して、UI オートメーション プロパティとコントロール パターンに関する情報を公開します。 IRawElementProviderSimple には、次のメソッドが含まれています。

  • GetPatternProvider— このメソッドは、コントロール パターン インターフェイスを公開するために使用されます。 これは、指定したコントロール パターンをサポートするオブジェクトを返すか、コントロール パターンがサポートされていない場合は NULL を返します。
  • GetPropertyValue— このメソッドは、UI オートメーション プロパティ値を公開するために使用されます。
  • HostRawElementProvider— このメソッドは、IAccessibleEx の実装には使用されません。
  • ProviderOptions— このメソッドは、IAccessibleEx の実装には使用されません。

IAccessibleEx サーバーは、IRawElementProviderSimple::GetPatternProvider を実装することによってコントロール パターンを公開します。 このメソッドは、コントロール パターンを指定する整数パラメーターを受け取ります。 パターンがサポートされていない場合は、サーバーは NULL を返します。 コントロール パターン インターフェイスがサポートされている場合は、サーバーは IUnknown を返し、クライアントは QueryInterface を呼び出して適切なコントロール パターンを取得します。

IAccessibleEx サーバーでは、IRawElementProviderSimple::GetPropertyValue を実装し、プロパティをパラメーターとして識別する整数 PROPERTYID を指定することで、UI オートメーションプロパティ (LabeledBy、IsRequiredForForm など) をサポートできます。 この手法は、コントロール パターン インターフェイスに含まれていない UI オートメーションプロパティにのみ適用されます。 コントロール パターン インターフェイスに関連付けられているプロパティは、コントロール パターン インターフェイス メソッド経由で公開されます。 たとえば、SelectionItem コントロール パターンの IsSelected プロパティは、ISelectionItemProvider::get_IsSelected を使用して公開されます。