MS Active Accessibility 接口技术问题

#include
#include
#include
#include "atlbase.h"
#include
#pragma comment(lib,"oleacc.lib")
BOOL FindChild (IAccessible* paccParent,
char* szName, char* szRole,
char* szClass,
IAccessible** paccChild,
VARIANT* pvarChild);
UINT GetObjectState(IAccessible* pacc,
VARIANT* pvarChild,
LPTSTR lpszState,
UINT cchState);
void GetObjectName(IAccessible* paccChild, VARIANT* varChild, char szObjName[], int s);
void GetObjectRole(IAccessible* paccChild, VARIANT* varChild, char szObjRole[], int s);
void GetObjectClass(IAccessible* paccChild,char szObjClass[], int s);
int main()
{

IAccessible* paccControl = NULL;//输入框的 IAccessible 接口
VARIANT     varControl;         //子ID。
HWND hWndMainWindow;
IAccessible *paccMainWindow = NULL;
HRESULT hr;
//得到标题为"运行"的窗口的句柄
if(NULL == (hWndMainWindow = FindWindow(NULL, "运行")))
{
    MessageBox(NULL, "没有发现窗口!", "错误", MB_OK);
}
else
{
    //通过窗口句柄得到窗口的 IAccessible 接口指针。
    if(S_OK == (hr = AccessibleObjectFromWindow(
        hWndMainWindow,
        OBJID_WINDOW,
        IID_IAccessible,
        (void**)&
        paccMainWindow)))
    {
        //……我们可以通过这个指针paccMainWindow进行操作。
        //paccMainWindow->Release();
        //在文本输入框输入"regedit"
        printf("paccMainWindow:%d\n",paccMainWindow);
        if(1 == FindChild (paccMainWindow, "打开(O):", 
            "可编辑文字", 
            "Edit", 
            &paccControl, 
            &varControl))
        {
            //在这里修改文本编辑框的值
            printf("xiu gai wenben nei rong\n");
            hr = paccControl->put_accValue(varControl,CComBSTR("regedit"));
            printf("xiu gai cheng gong\n");
            paccControl->Release();
            VariantClear(&varControl);
        }

        // 找到确定按钮,并执行默认动作。
        if(1 == FindChild (paccMainWindow, 
            "确定", 
            "按下按钮", 
            "Button", 
            &paccControl, 
            &varControl))
        {
            //这里执行按钮的默认动作,即"按下这个按钮"
            hr = paccControl->accDoDefaultAction(varControl);
            paccControl->Release();
            VariantClear(&varControl);
        }
    }
}
return 0;

}
BOOL FindChild (IAccessible* paccParent,
char* szName, char* szRole,
char* szClass,
IAccessible** paccChild,
VARIANT* pvarChild)
{
HRESULT hr;
long numChildren;
unsigned long numFetched;
VARIANT varChild;
int index;
IAccessible* pCAcc = NULL;
IEnumVARIANT* pEnum = NULL;
IDispatch* pDisp = NULL;
BOOL found = false;
char szObjName[256], szObjRole[256], szObjClass[256], szObjState[256];

//得到父亲支持的IEnumVARIANT接口
if(paccParent==NULL)
{
    printf("paccParent is NULL");
    return false;
}
printf("enter findall\n");
hr = paccParent->QueryInterface(IID_IEnumVARIANT,(void**)&pEnum);
if(pEnum)
    pEnum -> Reset();

//取得父亲拥有的可访问的子的数目
paccParent -> get_accChildCount(&numChildren); 
printf("numChildren:%d\n",numChildren);

//搜索并比较每一个子ID,找到名字、角色、类与输入相一致的。
for(index = 1; index <= numChildren && !found; index++)
{
    printf("%d\n",index);
    pCAcc = NULL;       
    // 如果支持IEnumVARIANT接口,得到下一个子ID
    //以及其对应的 IDispatch 接口
    printf("pEnum:%d\n",pEnum);
    if (pEnum)
    {
        VariantInit(&varChild);
        printf("varChild:%d\n",varChild);
        hr = pEnum -> Next(1, &varChild, &numFetched);
        if(hr==S_OK)
            printf("S_OK\n");
        printf("varChild:%d\n",varChild);
    }
    else
    {
        //如果一个父亲不支持IEnumVARIANT接口,子ID就是它的序号
        varChild.vt = VT_I4;
        varChild.lVal = index;
    }

    // 找到此子ID对应的 IDispatch 接口
    if (varChild.vt == VT_I4)
    {
        //通过子ID序号得到对应的 IDispatch 接口
        pDisp = NULL;
        printf("pDisp:%d\n",pDisp);
        hr = paccParent ->get_accChild(varChild,(IDispatch**)&pDisp);
        printf("pDisp:%d\n",pDisp);
    }
    else
        //如果父支持IEnumVARIANT接口可以直接得到子IDispatch 接口
        pDisp = varChild.pdispVal;

    // 通过 IDispatch 接口得到子的 IAccessible 接口 pCAcc
    if (pDisp)
    {
        printf("pCAcc:%d\n",pCAcc);
        hr = pDisp->QueryInterface(IID_IAccessible, (void**)&pCAcc);
        printf("pCAcc:%d\n",pCAcc);
        hr = pDisp->Release();
    }

    // Get information about the child
    if(pCAcc)
    {
        //如果子支持IAccessible 接口,那么子ID就是CHILDID_SELF
        VariantInit(&varChild);
        varChild.vt = VT_I4;
        varChild.lVal = CHILDID_SELF;

        *paccChild = pCAcc;
    }
    else
        //如果子不支持IAccessible 接口
        *paccChild = paccParent;

    //跳过了有不可访问状态的元素
    GetObjectState(*paccChild, 
        &varChild, 
        szObjState, 
        sizeof(szObjState));
    if(NULL != strstr(szObjState, "unavailable"))
    {
        if(pCAcc)
            pCAcc->Release();
        continue;
    }
    //通过get_accName得到Nam
    GetObjectName(*paccChild, &varChild, szObjName, sizeof(szObjName));
    //通过get_accRole得到Role
    GetObjectRole(*paccChild, &varChild, szObjRole, sizeof(szObjRole));
    //通过WindowFromAccessibleObject和GetClassName得到Class
    GetObjectClass(*paccChild, szObjClass, sizeof(szObjClass));
    //以上实现代码比较简单,大家自己看代码吧。
    //如果这些参数与输入相符或输入为NULL
    if ((NULL==szName || 
        0==strcmp(szName, szObjName))&& 
        (NULL==szRole || 
        0==strcmp(szRole, szObjRole)) && 
        (NULL==szClass || 
        0==strcmp(szClass, szObjClass)))
    {
        found = true;
        *pvarChild = varChild;
        break;
    }
    if(!found && pCAcc)
    {
        // 以这次得到的子接口为父递归调用
        printf("findall again");
        found = FindChild(pCAcc, 
            szName, 
            szRole, 
            szClass, 
            paccChild, 
            pvarChild);
        if(*paccChild != pCAcc)
            pCAcc->Release();
    }
}//End for
// Clean up
if(pEnum)
    pEnum -> Release();
printf("exit findall\n");
return found;

}

// UI元素的状态也表示成整型形式。因为一个状态可以有多个值,
//例如可选的、可做焦点的,该整数是反映这些值的位的或操作结果。
//将这些或数转换成相应的用逗号分割的状态字符串。
UINT GetObjectState(IAccessible* pacc,
VARIANT* pvarChild,
LPTSTR lpszState,
UINT cchState)
{
HRESULT hr;
VARIANT varRetVal;

*lpszState = 0;

VariantInit(&varRetVal);

hr = pacc->get_accState(*pvarChild, &varRetVal);

if (!SUCCEEDED(hr))
    return(0);

DWORD dwStateBit;
int cChars = 0;
if (varRetVal.vt == VT_I4)
{
    // 根据返回的状态值生成以逗号连接的字符串。
    for (dwStateBit = STATE_SYSTEM_UNAVAILABLE; 
           dwStateBit < STATE_SYSTEM_ALERT_HIGH; 
           dwStateBit <<= 1)
    {
        if (varRetVal.lVal & dwStateBit)
        {
            cChars += GetStateText(dwStateBit, 
                                   lpszState + cChars, 
                                   cchState - cChars);
            *(lpszState + cChars++) = ',';
        }
    }
    if(cChars > 1)
        *(lpszState + cChars - 1) = '\0';
}
else if (varRetVal.vt == VT_BSTR)
{
    WideCharToMultiByte(CP_ACP, 
                        0, 
                        varRetVal.bstrVal, 
                        -1, 
                        lpszState,
                        cchState, 
                        NULL, 
                        NULL);
}

VariantClear(&varRetVal);

return(lstrlen(lpszState));

}
void GetObjectName(IAccessible* paccChild, VARIANT* varChild, char szObjName[], int s)
{
printf("getname\n");
if(paccChild==NULL)
{
printf("IAccessible is NULL");
return;
}
CComBSTR buf;
paccChild->get_accName(*varChild,&buf);
unsigned int i,len;
len=buf.Length();
memset(szObjName,0,s);
for(i=0;i *(szObjName+i)=*(buf.m_str+i);
}
void GetObjectRole(IAccessible* paccChild, VARIANT* varChild, char szObjRole[], int s)
{
printf("getrole\n");
if(paccChild==NULL)
{
printf("IAccessible is NULL");
return;
}
VARIANT buf;
paccChild->get_accRole(*varChild,&buf);
buf.vt=VT_I2;
szObjRole=(char*)buf.bstrVal;
}
void GetObjectClass(IAccessible* paccChild,char szObjClass[], int s)
{
printf("getclass\n");
if(paccChild==NULL)
{
printf("IAccessible is NULL\n");
return;
}
HWND hwnd;
LPSTR buf;
WindowFromAccessibleObject(paccChild,&hwnd);
GetClassName(hwnd,buf,s);
szObjClass=buf;
printf("getclass end\n");
}
我第二次for循环一直运行出错,pDisp的值一直为0

3个回答

使用pDisp之前判断一下指针是否为空,为空就不要调用。同时输出一下返回的错误码信息来分析具体原因。

!程序运行到第二次for循环的 paccParent ->get_accChild(varChild,&pDisp);就会出现这个](https://img-ask.csdn.net/upload/201504/22/1429668328_835708.png)

我发现问题好像是IEnumVARIANT得到的值都是负值,应该是枚举到的不对,但是应该怎么写啊

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问