IAccessibleオブジェクトの列挙

解決


熊谷隆史  2008-08-21 02:53:22  No: 140246

こんにちは。
ExcelのユーザーフォームのIAccessibleオブジェクトを
再帰呼び出しに依って、列挙させようとしているのですが。

AccExplorer32.exeで順番を確認して
子IDを指定して、accChildメソッドを呼び出したところ、
エラーになります。
何かカン違いしてるのでしょうか?

Private Const NAVDIR_NEXT = 5&
Private Const NAVDIR_FIRSTCHILD = 7&
Private Const CHILDID_SELF = 0&

Private Sub UserForm_Initialize()

    Dim acc As IAccessible
    Set acc = Me
    Set acc = acc.accParent
    Set acc = acc.accChild(4&) ←ここで実行時エラー
    
End Sub

---
実行時エラー '5':

プロシージャの呼び出し、または引数が不正です。
---


魔界の仮面弁士  2008-08-21 05:29:18  No: 140247

> Set acc = acc.accChild(4&) ←ここで実行時エラー

この 4 という ChildID は、どのようにして得たものですか?

また、accChild 以外の方法(accNavigate メソッド や AccessibleChildren API)で辿ることはできますか?

=================================

Set acc = Me
Set acc = acc.accParent

count = acc.accChildCount
If count > 0 Then
    ReDim list(count - 1) As Variant
    Call AccessibleChildren(acc, 0&, ByVal count, list(0), count)
    If IsObject( list(n) ) Then

        Set acc = list( n )  'このようにしてアクセスできるか?

    End If
End If


熊谷隆史  2008-08-22 20:23:58  No: 140248

魔界の仮面弁士さん、こんにちは。
ご回答ありがとうございます。

> この 4 という ChildID は、どのようにして得たものですか?
Accessible Explorerを見ながら1,2,,,と数えていたのですが
それがマズかったのかも。

> また、accChild 以外の方法(accNavigate メソッド や AccessibleChildren API)で辿ることはできますか?
accNavigateだと、

Private Const CHILDID_SELF = 0&
Private Const NAVDIR_FIRSTCHILD = 7&
Private Sub CommandButton1_Click()

    Dim Vnt As Variant
    Dim acc As IAccessible
    Set acc = Me
    Set acc = acc.accParent
    Vnt = acc.accNavigate(NAVDIR_FIRSTCHILD, CHILDID_SELF) ←ここで実行時エラー

End Sub

---
実行時エラー '438':

オブジェクトは、このプロパティまたはメソッドをサポートしていません。
---
になります。

>         Set acc = list( n )  'このようにしてアクセスできるか?
ばっちりでした。

理由は分かりませんが、accNavigate・accChildではアクセス出来ない
オブジェクトがある様に感じます。
AccessibleChildrenがオールマイティなので構いませんが。
取り合えず、列挙出来てるのではないかと思うので(多分)
もう少し、見やすく出力できるように改善して行きたいと思います。
ありがとうございました。

---
Option Explicit
Private Declare Function AccessibleChildren Lib "oleacc" ( _
        ByVal paccContainer As IAccessible, _
        ByVal iChildStart As Long, _
        ByVal cChildren As Long, _
        rgvarChildren As Any, _
        pcObtained As Long) As Long
Private Const CHILDID_SELF = 0&
Private Const S_OK = 0&

Private Sub CommandButton1_Click()
    Dim acc As IAccessible
    Set acc = Me
    hog acc.accParent
    Unload Me
End Sub

' 子孫オブジェクトを列挙
Private Sub hog(ByVal acc As IAccessible)

    Dim i As Long
    Dim count As Long
    
    count = acc.accChildCount
    If count > 0 Then
        ReDim List(count - 1) As Variant
        If AccessibleChildren(acc, 0, count, List(0), count) = S_OK Then
            If IsObject(List(i)) Then
                For i = LBound(List) To UBound(List)
                    With List(i)
                        On Error Resume Next
                        Debug.Print "ChildCount: " & .accChildCount
                        Debug.Print "Value: " & .accValue(CHILDID_SELF)
                        Debug.Print "Name: " & .accName(CHILDID_SELF)
                        Debug.Print "Description: " & .accDescription(CHILDID_SELF) & vbCrLf
                        On Error GoTo 0
                    End With
                    hog List(i) '再帰
                Next
            End If
        End If
    End If
End Sub


魔界の仮面弁士  2008-08-23 03:27:11  No: 140249

MSAA に関する資料は、本当に少ないですよね。SDK の "VB Sample" の項にあるのは、
"Advanced Visual Basic 6.0, Second Edition" の紹介文だけだし…。

> Accessible Explorerを見ながら1,2,,,と数えていたのですが
たしかに 1 からの連番で振られる事が多いですが、連番であるとは限りません。
(そもそも、指定すべき Child ID 自体が無い場合もありますが)

SDK の『単純要素』の説明には、以下のように書かれています。

》 IAccessible オブジェクトを共有している要素を区別するために、
》 サーバーは各単純要素に、一意の正の子 ID を割り当てます。
》 この割り当ては、インターフェイスのインスタンスごとに行われるので、
》 ID はその範囲内では一意である必要があります。
》 ID には 1 からの通し番号を割り当てている実装が多く見受けられます。

> 理由は分かりませんが、accNavigate・
論理的ナビゲーションの場合、非表示項目はスキップされる可能性が高いです。
(SDK では、EnumChildWindows API を併用する方法が提示されています)

> accChildではアクセス出来ないオブジェクトがある様に感じます。
Child ID が間違っているならば、E_INVALIDARG になりますね。

SDK によると、子が単純要素である場合は、失敗すると書かれていますので、
この場合はおそらく、エラーになるか Nothing を返すかのいずれかなのでしょう。

》 child ID を使って IAccessible::get_accChild を呼び出して、
》 IDispatch インターフェイス ポインタがあるかどうか調べます。 
(中略)
》 get_accChild への呼び出しが失敗すれば、単純要素です。

> AccessibleChildrenがオールマイティなので構いませんが。
親子関係になっていない場合(空間的/論理的なナビゲーションでしか
アクセスできない項目)に対しては無効かも?


熊谷隆史  2008-08-27 00:22:23  No: 140250

魔界の仮面弁士さん、ご回答ありがとうございます。

> Child ID が間違っているならば、E_INVALIDARG になりますね。
HRESULT型の戻り値をVBAで得る方法は大変そうなので
C++で確認してみましたが、ご推察頂きましたとおり、
E_INVALIDARG(0x80070057)が返ってきました。

Child IDを得てみると連番になってはいるのですが
-1 〜 -7 となっていて、
accChildで子オブジェクトを取得出来るので
単純要素では無い様でした。

> SDK の『単純要素』の説明には、以下のように書かれています。
日本語版のSDKの存在を今更ながら知りました。
http://www.microsoft.com/japan/msdn/accessibility/msaa/

> > 理由は分かりませんが、accNavigate・
> 論理的ナビゲーションの場合、非表示項目はスキップされる可能性が高いです。
> (SDK では、EnumChildWindows API を併用する方法が提示されています)

> > AccessibleChildrenがオールマイティなので構いませんが。
> 親子関係になっていない場合(空間的/論理的なナビゲーションでしか
> アクセスできない項目)に対しては無効かも?

いろいろと考慮しなくてはいけないのですね。
勉強になります。

疑問が残っている箇所をご配慮頂いて、
解決後にも関わらず、書き込みを頂きまして、
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加