使用IAccessible访问Mozilla的ISimpleDOMNode

时间:2010-07-10 01:40:11

标签: c++ firefox mozilla iaccessible

我有以下代码:

IAccessible *pAccessible = NULL;
IServiceProvider *pServProv = NULL; 
AccessibleObjectFromWindow((HWND)0x0025093A, OBJID_CLIENT, IID_IAccessible, (void**)&pAccessible);

HRESULT hr = pAccessible->QueryInterface(IID_IServiceProvider, (void**)&pServProv);
if (SUCCEEDED(hr) && (pServProv != NULL))
{
    const GUID unused;
    ISimpleDOMDocument *pAccDoc = NULL;

    hr = pServProv->QueryService(unused, IID_ISimpleDOMDocument, (void**)&pAccDoc);

    if (SUCCEEDED(hr) && (pAccDoc != NULL))
    {
        // Success
    }
    else
    {
        // Failure
    }
}

上面的硬编码HWND是MozillaContentWindowClass的一个实例。

我可以得到QueryService - AccessibleObjectFromWindow和QueryInterface都成功并返回非NULL对象;但是,QueryService返回“无效参数”。我已经看到其他建议,其中一个没有使用QueryService - 只是用IID_ISimpleDom *调用QueryInterface - 但这些调用返回'No Service'错误。

我也看到过导航到Document对象的建议,并从那里获得对节点的引用 - 但我不太清楚如何实现它(我是IAccessibility的新手)。

我很欣赏任何见解。

1 个答案:

答案 0 :(得分:1)

Mozilla

提供的Magic GUID
if (pAccChild)
{
    CComQIPtr<IServiceProvider> provider = pAccChild;
    if( provider ){
       const GUID refguid = {0x0c539790, 0x12e4, 0x11cf, 0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};

      CComPtr<ISimpleDOMNode> node;
      provider->QueryService(refguid, IID_ISimpleDOMNode, (void**)&node);
      CComQIPtr<ISimpleDOMDocument> ffdocument = node;
      if (node) {
        ffdocument->get_URL(&DOM_string);
        if (DOM_string != 0) { 
            addressbar = (const wchar_t *)_bstr_t(DOM_string, FALSE); 
        }
      }

现在,在AccessibleObjectFromWindow和获取提供者之间,您可能需要移动可访问的层次结构,这可能有点混乱。

请查看此Code Project - XMSAALib以获取建议。

以下是一些涵盖各种问题的树木行走示例。从原来修改使用ATL智能指针和一些错误修复(或引入;))

//-----------------------------------------------------------------------------
bool CXMSAALib::EnumAccessible(IAccessible *pIAccParent, IAccessibleEnumProc& lpEnumAccessibleProc )
{
    _ASSERTE(pIAccParent);

    // 2 ways to go through the children
    // * some parents will support the Enum(erator) interface where child ids may not be a contiguous sequence, and children may be returned as id or IAccessible directly
    // * others support the accChild function only where the count and ids should be contiguous.

    CComQIPtr<IEnumVARIANT> pEnum = pIAccParent;
    if( pEnum )
        pEnum->Reset();

    // get child count
    long nChildren = 0;
    if( FAILED( pIAccParent->get_accChildCount(&nChildren) ) )
        nChildren = 0;
    //TRACE(_T("nChildren=%d\n"), nChildren);

    bool bContinue = true;
    // skip 0 (self)
    for (long index = 1; (index <= nChildren) && bContinue; index++)
    {
        HRESULT hr =0;
        VARIANT varChildRef;
        VariantInit(&varChildRef);
        if (pEnum)
        {
            unsigned long nFetched = 0;
            hr = pEnum->Next(1, &varChildRef, &nFetched);
            //children may be returned as lVal id or IAccessible directly
            if (!SUCCEEDED(hr) || !nFetched )
            {
                bContinue = false;
                break;
            }
        }
        else
        {
            varChildRef.vt = VT_I4;
            varChildRef.lVal = index;
        }

        // IAccessible doesn't always allow indirect access to children that are also of type IAccessible
        // change the focus to the child element if we can
        VARIANT varChild;
        VariantInit(&varChild);
        CComPtr<IAccessible> pIAccChild;
        FocusOnChild( pIAccParent, varChildRef, pIAccChild, varChild );

        bContinue = lpEnumAccessibleProc(pIAccChild, varChild);

        if ( bContinue 
            && pIAccChild 
            && CHILDID_SELF == varChild.lVal )
        {

            bContinue = EnumAccessible(pIAccChild, lpEnumAccessibleProc);

        }

        VariantClear(&varChild);
    }

    return bContinue;
}

//-----------------------------------------------------------------------------
bool CXMSAALib::EnumAccessible(HWND hwnd, IAccessibleEnumProc& lpEnumAccessibleProc) 
{
    if (::IsWindow(hwnd))
    {
        CComPtr<IAccessible> pIAccParent;

        HRESULT hr = AccessibleObjectFromWindow(hwnd, OBJID_CLIENT, IID_IAccessible, (void**)&pIAccParent);
        if (SUCCEEDED(hr) && pIAccParent)
        {
            VARIANT varChild;
            VariantInit(&varChild);
            varChild.vt = VT_I4;
            varChild.lVal = CHILDID_SELF;
            if( lpEnumAccessibleProc(pIAccParent, varChild) ) {
                EnumAccessible(pIAccParent, lpEnumAccessibleProc, nLevel+1);
            }

            VariantClear(&varChild);
            return true;
        }
    }
    return false;
}

//-----------------------------------------------------------------------------
void CXMSAALib::FocusOnChild( IAccessible * pIAccParent, VARIANT &varChildRef, CComPtr<IAccessible> &pIAccChild, VARIANT &varChild ) 
{
    // get IDispatch interface for the child
    CComPtr<IDispatch> pDisp;
    if (varChildRef.vt == VT_I4)
    {
        pIAccParent->get_accChild(varChildRef, &pDisp);
    }
    else if (varChildRef.vt == VT_DISPATCH)
    {
        pDisp = varChildRef.pdispVal;
    }

    // get IAccessible interface for the child
    CComQIPtr<IAccessible> pCAcc(pDisp);

    if (pCAcc && pCAcc != pIAccParent )
    {
        VariantInit(&varChild);
        varChild.vt = VT_I4;
        varChild.lVal = CHILDID_SELF;
        pIAccChild = pCAcc;
    }
    else
    {
        pIAccChild = pIAccParent;
        varChild = varChildRef;
    }
}