首页
社区
课程
招聘
[求助]MSAA IAccessible接口枚举信息不全
发表于: 2016-12-16 19:08 7654

[求助]MSAA IAccessible接口枚举信息不全

2016-12-16 19:08
7654
背景: 针对某券商客户端(招商证券/中信证券通达信版本均可测试)做一个自动交易的辅助程序,对按钮,列表各种控件进行自动化控制操作,主要通过MSAA api来完成. 现在碰到了一个问题,请教下各位.

问题: 利用IAccessible接口遍历窗口,遍历的数据不全,和用工具AccCheckUI/AccExplorer32/AccViewer遍历的数据比起来,不一样有缺少,遍历的代码网上抄来的,改了下,自己调试了好久没找到原因,请大家帮忙找找原因

如图所示,"买入","卖出"都是窗口"MainViewBar",自定义类MHPToolBar下子元素,用工具AccViewer可以找到"买入"的层次关系,但自己的遍历代码无法找到role是"工具栏"的对象,找到的role=菜单栏,数据都不对了. 主要代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
        //查找自定义类MHPToolBar窗口句柄
  HWND hwnd = ::FindWindow(_T("TdxW_MainFrame_Class"), NULL);
  if (hwnd)
  {
    OFindWnd oWnd(hwnd, _T("MHPToolBar"), _T("MainViewBar"));
    hwnd = oWnd.m_hWnd;
  }
  if (!::IsWindow(hwnd))
    return FALSE;
 
  //枚举并查找"买入"控件
  IAccessible *pIAcc = NULL;
  HRESULT hr = AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible, (void**)&pIAcc);
  if (SUCCEEDED(hr) && pIAcc)
  {
    VARIANT varChild;
    VariantInit(&varChild);
    IAccessible *pIAccChild = NULL;
    g_sSubPrefix = "";
    if (CXMSAALib::FindAccessible(pIAcc, _T("买入"), _T("按下按钮"), _T("MHPToolBar"), &pIAccChild, &varChild))
    {
      //find
      DEBUGTRACE("find");
    }
    else
    {
      //not find
      DEBUGTRACE("not find");
    }
  }
 
 
BOOL CXMSAALib::FindAccessible(IAccessible* accParent,
  LPTSTR szName,
  LPTSTR szRole,
  LPTSTR szClass,
  IAccessible** paccChild,
  VARIANT* pvarChild)
{
  BOOL found = false;
  TCHAR szObjName[MAX_PATH], szObjRole[MAX_PATH], szObjClass[MAX_PATH], szObjState[MAX_PATH];
  IAccessible* pCAcc = NULL;
 
  VARIANT* vt_output = NULL;
  if (accParent == NULL)
    return FALSE;
 
  long lChildCount = 0;
  HRESULT hr = accParent->get_accChildCount(&lChildCount);
  if (FAILED(hr) || (lChildCount == 0))
    return FALSE;
  DEBUGTRACE("%s obj=0x%p, numChildren=%d", g_sSubPrefix.c_str(), accParent, lChildCount);
 
  vt_output = new VARIANT[lChildCount];
  for (int i = 0; i < lChildCount; i++)
    VariantInit(&vt_output[i]);
 
  long lNewChildCount = 0;
  hr = AccessibleChildren(accParent, 0, lChildCount, vt_output, &lNewChildCount);
  if (FAILED(hr))
    goto exit;
 
  for (int j = 0; j < lNewChildCount && !found; j++)
  {
    VARIANT varChild;
    VariantInit(&varChild);
    IDispatch* disp = NULL;
    pCAcc = NULL;
    //If the vt member of an array element is VT_DISPATCH, 
    //then the pdispVal member for that element is the address of the child object's IDispatch interface.
    if (vt_output[j].vt == VT_DISPATCH)
    {
      disp = vt_output[j].pdispVal;
    }
    //If the vt member of an array element is VT_I4, then the lVal member for that element is the child ID.
    else if (vt_output[j].vt == VT_I4)
    {
      hr = accParent->get_accChild(vt_output[j], &disp);
      //If a child is an element, get_accChild returns S_FALSE, and the parent will provide information for that child. 
      if (!SUCCEEDED(hr) || !disp)
      {
        //element deal
        varChild.vt = VT_I4;
        varChild.lVal = vt_output[j].lVal;
        *paccChild = accParent;
      }
    }
    else //未发现有进入
    {
      continue;
    }
 
    if (disp)
    {
      hr = disp->QueryInterface(IID_IAccessible, (void**)&pCAcc);
      if (FAILED(hr))
        continue;
      varChild.vt = VT_I4;
      varChild.lVal = CHILDID_SELF;
      *paccChild = pCAcc;
    }
 
    // Skip invisible and unavailable objects and their children
    GetObjectStateString(*paccChild, &varChild, szObjState, MAX_PATH);
//     if (NULL != _tcsstr(szObjState, _T("unavailable")))
//     {
//         if (pCAcc)
//           pCAcc->Release();
//         continue;
//     }
    UINT nState = 0;
    GetObjectState(*paccChild, &varChild, nState);
    // check if object is available
    if ((nState & STATE_SYSTEM_UNAVAILABLE /*STATE_SYSTEM_INVISIBLE*/ /*| STATE_SYSTEM_OFFSCREEN*/))
    {
       SAFE_RELEASE(pCAcc);
       continue;
    }
    GetObjectName(*paccChild, &varChild, szObjName, MAX_PATH);
    GetObjectRoleString(*paccChild, &varChild, szObjRole, MAX_PATH);
    //GetObjectClass(*paccChild, szObjClass, sizeof(szObjClass));
    memset(szObjClass, 0, sizeof(szObjClass));
    HWND hwndChild = 0;
    WindowFromAccessibleObject(*paccChild, &hwndChild);
    if (hwndChild)
      GetClassName(hwndChild, szObjClass, MAX_PATH);
 
    if ((!szName || !_tcscmp(szName, szObjName)) && (!szRole || !_tcscmp(szRole, szObjRole)) && (!szClass || !_tcscmp(szClass, szObjClass)))
    {
      found = true;
      *pvarChild = varChild;
      break;
    }
 
    if (pCAcc)
      DEBUGTRACE("%s name=%s, role=%s, class=%s, state=%s obj=0x%p,idx=0x%p", g_sSubPrefix.c_str(), szObjName, szObjRole, szObjClass, szObjState, pCAcc, varChild.lVal);
    else
      DEBUGTRACE("%s name=%s, role=%s, class=%s, state=%s elem,idx=0x%p", g_sSubPrefix.c_str(), szObjName, szObjRole, szObjClass, szObjState, varChild.lVal);
     
    if (!found && pCAcc)
    {
      string sParentPrefix = g_sSubPrefix;
      g_sSubPrefix += "    ";
      // Go deeper
      found = FindAccessible(pCAcc, szName, szRole, szClass, paccChild, pvarChild);
      if (*paccChild != pCAcc)
        pCAcc->Release();
      g_sSubPrefix = sParentPrefix;
    }
  }
exit:
  if (vt_output)
  {
    for (int k = 0; k < lChildCount; k++)
      VariantClear(&vt_output[k]);
    delete vt_output;
  }
  return found;
}


运行的遍历错误结果:
obj=0x00E088C8, numChildren=7
name=系统, role=菜单栏, class=MHPToolBar obj=0x00E03FA0,idx=1
    obj=0x00E03FA0, numChildren=0
name=, role=标题栏, class=MHPToolBar obj=0x00E051C0,idx=2
    obj=0x00E051C0, numChildren=5
    name=输入法, role=按下按钮, class=MHPToolBar elem,idx=1
    name=最小化, role=按下按钮, class=MHPToolBar elem,idx=2
    name=最大化, role=按下按钮, class=MHPToolBar elem,idx=3
    name=上下文帮助, role=按下按钮, class=MHPToolBar elem,idx=4
    name=关闭, role=按下按钮, class=MHPToolBar elem,idx=5
name=应用程序, role=菜单栏, class=MHPToolBar obj=0x00E2F598,idx=3  <-----这里开始遍历数据就不一样了,没有得到预期的role=工具栏
    obj=0x00E2F598, numChildren=0
name=MainViewBar, role=客户端, class=MHPToolBar obj=0x00E2F388,idx=4
    obj=0x00E2F388, numChildren=1
    name=, role=窗口, class=ComboBox obj=0x00E2F6F8,idx=1
        obj=0x00E2F6F8, numChildren=7
        name=系统, role=菜单栏, class=ComboBox obj=0x00E2F5F0,idx=1
            obj=0x00E2F5F0, numChildren=0
        name=, role=标题栏, class=ComboBox obj=0x00E2F648,idx=2
            obj=0x00E2F648, numChildren=5
            name=输入法, role=按下按钮, class=ComboBox elem,idx=1
            name=最小化, role=按下按钮, class=ComboBox elem,idx=2
            name=最大化, role=按下按钮, class=ComboBox elem,idx=3
            name=上下文帮助, role=按下按钮, class=ComboBox elem,idx=4
            name=关闭, role=按下按钮, class=ComboBox elem,idx=5
        name=应用程序, role=菜单栏, class=ComboBox obj=0x00E2F4E8,idx=3

[注意]看雪招聘,专注安全领域的专业人才平台!

上传的附件:
  • 1.png (67.36kb,12次下载)
收藏
免费
支持
分享
最新回复 (3)
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
顺便问下MSAA api有么有封装好用的库,最好c++版本的 :)
还有券商交易有么有开源的接口,我这种做法有点傻的 hoho~~
2016-12-16 19:12
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
找到问题原因,没有初始化...
::CoInitialize(NULL);
2016-12-18 00:34
0
雪    币: 28
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
哦,这样啊,好厉害呢
2017-8-10 05:15
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册