首页
社区
课程
招聘
[求助]MS Active Accessibility 接口技术编程尝试
发表于: 2015-4-19 20:44 6762

[求助]MS Active Accessibility 接口技术编程尝试

2015-4-19 20:44
6762
想做一个获取qq聊天内容的程序,在网上查资料,发现了一个博客,上面讲了很多,但是我把代码写好,编译完成,但是执行的时候就会崩溃,不知道那得问题,求大神指教,博客上有代码,网址如下:“http://www.vckbase.com/index.php/wv/651”
代码如下:
#include <iostream>
#include <windows.h>
#include <oleacc.h>
#include "atlbase.h"
#include <winable.h>
#include "comutil.h"
#pragma comment(lib,"comsupp.lib")
#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 接口指针。
                HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );
        LPFNACCESSIBLEOBJECTFROMWINDOW pfAccessibleObjectFromWindow =
                                (LPFNACCESSIBLEOBJECTFROMWINDOW)::GetProcAddress(hInst,_T("AccessibleObjectFromWindow"));
        if(S_OK == (hr = pfAccessibleObjectFromWindow(
                        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,&pDisp);
                        if(hr==S_OK)
                        printf("S_OK\n");
                        else if(hr==S_FALSE)
                                printf("S_FALSE\n");
                        else if(hr==E_INVALIDARG)
                                printf("E_INVALIDARG\n");
                        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
                        printf("*paccChild = pCAcc;\n");
                        VariantInit(&varChild);
                        varChild.vt = VT_I4;
                        varChild.lVal = CHILDID_SELF;
                       
                        *paccChild = pCAcc;
                }
                else
                {
                        //如果子不支持IAccessible 接口
                        printf("*paccChild = paccParent;\n");
                        *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");
        BSTR buf;
        printf("paccChild:%d\n",paccChild);
        paccChild->get_accName(*varChild,&buf);
        printf("%s\n",buf);
        szObjName=_com_util::ConvertBSTRToString(buf);
        SysFreeString(buf);
}
void GetObjectRole(IAccessible* paccChild, VARIANT* varChild, char szObjRole[], int s)
{
        printf("getrole\n");
        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");
        HWND hwnd;
        LPSTR buf;
        WindowFromAccessibleObject(paccChild,&hwnd);
        GetClassName(hwnd,buf,s);
        szObjClass=buf;
        printf("getclass end\n");
}
但是代码执行到for循环的第二次的时候在        hr = paccParent ->get_accChild(varChild,&pDisp);处就会崩溃,而且pDisp的值始终为0,不知道为什么,对了这个程序我就是用的网址里的源码,把他的代码补完整了,基本功能就是实现将运行窗口的编辑框内容变为注册表的名字,并打开注册表程序。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 75
活跃值: (164)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
求高手解达
2015-4-19 20:45
0
雪    币: 75
活跃值: (164)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
我发现之所以哪里帮亏是枚举到的索引是负值,IEnumVARIANT这个获取到了啊,但是,不知道为什么得到的索引好像都不能用
2015-4-22 22:01
0
游客
登录 | 注册 方可回帖
返回
//