Microsoft Active Accessibility

http://www.cnblogs.com/gnagwang/archive/2010/04/20/1716006.html


MSAA的全称是Microsoft Active Accessibility。这是类似DCOM技术。技术模型是这样的,UI程序可以暴露出一个Interface,方便另一个程序对其进行控制。 MSAA技术的初衷是为了方便残疾人使用Windows 程序。比如盲人看不到窗口,但是盲人可以通过一个USB读屏器连接到电脑上, 读屏器通过UI程序暴露出来的这个Interface,就可以获取程序信息,通过盲文或者其它形式传递给盲人。

MSAA提供了如此方便的功能, UI自动化测试自然可以借用这项技术。MSAA暴露出来的Interface叫做 IAccessible。测试程序和目标UI程序互操作流程如下:

1. 测试程序调用Windows API: AccessibleObjectFromWindow,传入目标UI程序HWND。

2. AccessibleObjectFromWindow函数向UI程序发送WM_GETOBJECT消息。

3. UI程序创建实现了IAccessible的内部类,然后通过LresultFromObject API把IAccessible 接口返回给测试程序。

4. 测试程序拿到IAccessible接口,开始调用IAccessible接口函数操作测试目标。

IAccessible接口里面的几个关键函数是:

IAccessible::get_accChild/ IAccessible::get_accParent通过这两个函数,调用者可以浏览目标程序的窗口关系树,定位到UI元素。

IAccessible::accLocation/I Accessible::accHitTest读取和分辨目标元素的屏幕位置。

IAccessible::accName/ I Accessible:: accSelect读取元素的名字,对UI元素进行指定的操作,比如选取Listbox里面的某一项等等。

IAccessible::accValue 开发人员可以自定义value属性的实现。比如针对折线图控件,开发人员可以在accValue中返回折线的坐标数列。

MSAA的理念 类似于test hook。 通过主动让UI程序暴露一个接口来让调用者控制。 在具体使用中,测试人员往往是结合MSAA和Win32 API操作,取长补短。一方面对于UI元素丰富的属性,比如style,钩选状态,是否最大化和模拟用户输入等,继续采用Win32 API。 另一方面用MSAA的优势来弥补Win32 API的一些不足,比如:

由于MSAA有自己的get_accChild方法,使其控件树关系并不一定要和Win32 HWNDd关系对应一致。对于自绘窗口,虽然说只有一个HWND, 但是开发人员可以通过实现IAccessible接口来实现逻辑上的层次关系。比如Excel中就可以通过IAccessible把多个cell的子 IAccessible接口暴露给调用者。

IAccessible的实现是由开发者提供, 开发者可以灵活地根据实际情况决定方法的实现。比如前面提到了折线图控件可以返回坐标数列。对于.NET WinForm, 微软在Framework中就提供了IAccessible的默认实现,这样在具体实现中,就可以处理.NET动态维护HWND的细节等

关于IWebBrowser2和MS Active Accessibility接口问题

10-11

rnIWebBrowser2* CDoHtml::GetWebBrowser(CString &strError,HWND hIEWindow)rnrn HWND hTempWnd = (NULL != hIEWindow)?hIEWindow:GetIEHandle();rn //显示装载OLEACC.DLL才知道有没有安装MSAArn HINSTANCE hInst = LoadLibrary( _T("OLEACC.DLL") );rn if( NULL == hInst )rn //如果没有安装MSAArn MessageBox(NULL,_T("Please Install Microsoft Active Accessibility"),"Error",MB_OK); rn return NULL;rn rnrn IWebBrowser2* pWebBrowser2=NULL;rn UINT nMsg = ::RegisterWindowMessage("WM_HTML_GETOBJECT"); rnrn DWORD dwRes; rn ::SendMessageTimeout(hTempWnd, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, &dwRes); rnrn LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, _T("ObjectFromLresult") );rn if ( pfObjectFromLresult != NULL )rn rn HRESULT hr;rn CComPtrspDoc;rnrn hr=pfObjectFromLresult(dwRes,IID_IHTMLDocument2,0,(void**)&spDoc);rn if ( SUCCEEDED(hr) )rn rn CComPtrspWnd2;rn CComPtrspServiceProv;rn hr=spDoc->get_parentWindow ((IHTMLWindow2**)&spWnd2);rn if(SUCCEEDED(hr))rn rn hr=spWnd2->QueryInterface (IID_IServiceProvider,(void**)&spServiceProv);rn if(SUCCEEDED(hr))rn rn hr = spServiceProv->QueryService(SID_SWebBrowserApp,IID_IWebBrowser2,(void**)&pWebBrowser2);rn rn rn rnrn rn ::FreeLibrary(hInst);rn return pWebBrowser2;rnrnrnrn上述代码是网上高手的实现,奇怪的是pfObjectFromLresult()总是调用不成功,返回-2147467259,hIEWindow这个句柄我是用spy直接在IExplorer抓取的,所以应该是没问题的,网上有人说这样是可以,但我总调不成功。 论坛

没有更多推荐了,返回首页