プロバイダー用 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 を返します。
- GetIAccessiblePair— IAccessibleEx 要素の 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 を使用して公開されます。