问题描述
- 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:%dn",paccMainWindow); if(1 == FindChild (paccMainWindow, "打开(O):", "可编辑文字", "Edit", &paccControl, &varControl)) { //在这里修改文本编辑框的值 printf("xiu gai wenben nei rongn"); hr = paccControl->put_accValue(varControl,CComBSTR("regedit")); printf("xiu gai cheng gongn"); 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 findalln"); hr = paccParent->QueryInterface(IID_IEnumVARIANT,(void**)&pEnum); if(pEnum) pEnum -> Reset(); //取得父亲拥有的可访问的子的数目 paccParent -> get_accChildCount(&numChildren); printf("numChildren:%dn",numChildren); //搜索并比较每一个子ID,找到名字、角色、类与输入相一致的。 for(index = 1; index <= numChildren && !found; index++) { printf("%dn",index); pCAcc = NULL; // 如果支持IEnumVARIANT接口,得到下一个子ID //以及其对应的 IDispatch 接口 printf("pEnum:%dn",pEnum); if (pEnum) { VariantInit(&varChild); printf("varChild:%dn",varChild); hr = pEnum -> Next(1, &varChild, &numFetched); if(hr==S_OK) printf("S_OKn"); printf("varChild:%dn",varChild); } else { //如果一个父亲不支持IEnumVARIANT接口,子ID就是它的序号 varChild.vt = VT_I4; varChild.lVal = index; } // 找到此子ID对应的 IDispatch 接口 if (varChild.vt == VT_I4) { //通过子ID序号得到对应的 IDispatch 接口 pDisp = NULL; printf("pDisp:%dn",pDisp); hr = paccParent ->get_accChild(varChild,(IDispatch**)&pDisp); printf("pDisp:%dn",pDisp); } else //如果父支持IEnumVARIANT接口可以直接得到子IDispatch 接口 pDisp = varChild.pdispVal; // 通过 IDispatch 接口得到子的 IAccessible 接口 pCAcc if (pDisp) { printf("pCAcc:%dn",pCAcc); hr = pDisp->QueryInterface(IID_IAccessible, (void**)&pCAcc); printf("pCAcc:%dn",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 findalln"); 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) = ''; } 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("getnamen");
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("getrolen");
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("getclassn");
if(paccChild==NULL)
{
printf("IAccessible is NULLn");
return;
}
HWND hwnd;
LPSTR buf;
WindowFromAccessibleObject(paccChild,&hwnd);
GetClassName(hwnd,buf,s);
szObjClass=buf;
printf("getclass endn");
}
我第二次for循环一直运行出错,pDisp的值一直为0
解决方案
使用pDisp之前判断一下指针是否为空,为空就不要调用。同时输出一下返回的错误码信息来分析具体原因。
解决方案二:
!程序运行到第二次for循环的 paccParent ->get_accChild(varChild,&pDisp);就会出现这个](http://img.ask.csdn.net/upload/201504/22/1429668328_835708.png)
解决方案三:
我发现问题好像是IEnumVARIANT得到的值都是负值,应该是枚举到的不对,但是应该怎么写啊