プロバイダーの IAccessibleEx の実装
このセクションでは、IAccessibleEx インターフェイスを実装して、Microsoft ACTIVE Accessibility サーバーに Microsoft UI オートメーション プロバイダー機能を追加する方法について説明します。
IAccessibleEx実装する前に、次の要件を考慮してください。
- ベースライン Microsoft Active Accessibility のアクセシビリティ対応オブジェクト階層はクリーンである必要があります。 IAccessibleEx は、既存のアクセシビリティ対応オブジェクト階層の問題を修正できません。 オブジェクトモデル構造に関する問題は、Microsoft Active Accessibility の実装を修正してから、IAccessibleExを実装する必要があります。
- IAccessibleEx 実装は、Microsoft Active Accessibility 仕様と UI オートメーション仕様の両方に準拠している必要があります。 ツールは、両方の仕様でコンプライアンスを検証するために使用できます。 詳細については、「アクセシビリティのテスト」および「UI オートメーションの検証 (UIA 検証) テスト オートメーション フレームワーク」を参照してください。
IAccessibleEx を実装するには、次の主要な手順が必要です。
- アクセス可能なオブジェクト IServiceProvider を実装して、IAccessibleEx インターフェイスをこのオブジェクトまたは別のオブジェクトで見つけることができます。
- アクセス可能なオブジェクト 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 の 1 つのインスタンスは、複数の UI 要素を表すことができます。
各 IAccessibleEx インスタンスは 1 つの UI 要素のみを表しているため、各 IAccessible と子 ID のペアは、1 つの IAccessibleEx インスタンスにマップする必要があります。 IAccessibleEx には、このマッピングを処理するための 2 つのメソッドが含まれています。
- GetObjectForChild—指定された子の IAccessibleEx インターフェイスを取得します。 このメソッドは、IAccessibleEx 実装が指定した子 ID を認識しない場合、指定した子に対して IAccessibleEx を持っていない場合、または子要素を表す場合、NULL を返します。
- GetIAccessiblePair— IAccessibleEx 要素の IAccessible インターフェイスと子 ID を取得します。 子 ID を使用しない IAccessible 実装 場合、このメソッドは IAccessible オブジェクトとCHILDID_SELFに対応する を取得します。
次の例は、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で公開されます。