WindowFromPoint无法获取隐藏或禁用窗口句柄,可以使用ChildWindowFromPoint/ChildWindowFromPointEx加标志CWP_ALL做不严格搜索。如果严格搜索,需要调用EnumChildWindows来递归找出最合适的子窗口,实现EnumChildProc时需要全局变量/全局类来保存中间值,通过全局函数调用。如果采用Accessibility技术则需要用到AccessibleObjectFromPoint。
GetWindowText有不足,即只发送WM_GETTEXT消息给属于当前进程的窗口;如果窗口属于另一进程并有标题,则GetWindowText也可以获得窗口标题文本,但如果该窗口无标题,GetWindowText返回空字符串。为了获取另一进程中的控件文本,用SendMessage/SendMessageTimeout直接发送WM_GETTEXT消息,见如何获得另一个应用程序窗口中的文本。
枚举基本的Window Style:Window Styles、Scroll-Bar Styles、Static Control Styles、List Box Styles、Edit Control Styles、Combo Box Styles、Button Styles和Extended Window Styles。
CreateToolhelp32Snapshot能从传入的进程ID得到进程名、进程路径等信息,但受限于应用程序是32/64位。当参数是TH32CS_SNAPPROCESS时,Process32First/Process32Next不受32/64位限制;但当参数是TH32CS_SNAPMODULE时,只能用QueryFullProcessImageName,此函数虽然能让32位应用程序获取64位进程信息,但自Windows Vista才可用。Process Explorer之所以不受限制,是因为Process Explorer在64位Windows上启动时,自行释放出procexp64.exe,然后启动该程序,可用eXeScope查看procexp.exe的Resource->BINRES,见解释。
GetBinaryType仅能获取exe后缀可执行文件类型。若想覆盖所有可执行文件,详见How to detect the types of executable files。
通过Microsoft Spy++能看到MSIE的树结构。其中,MSIE6的树结构为IEFrame -> Shell DocObject View -> Internet Explorer_Server;MSIE7的树结构为IEFrame -> TabWindowClass -> Shell DocObject View -> Internet Explorer_Server,如果是多线程浏览器如Sleipnir,树结构则为Shell Embedding -> Shell DocObject View -> Internet Explorer_Server;MSIE8的树结构为IEFrame -> Frame Tab -> TabWindowClass -> Shell DocObject View -> Internet Explorer_Server。以上结构,IEFrameShell和Shell Embedding对应IWebbrowser2,Shell DocObject View对应IHTMLWindow2,Internet Explorer_Server对应IHTMLDocument2。MSIE的document窗口类名为“Internet Explorer_Server”。获得它对应句柄的一种方法是依据MSIE的树结构枚举子类,见MH500的示例;另一种方法则是FindWindowEx(NULL,NULL,L”Internet Explorer_Server”,NULL)配合FindWindowEx(hwndParent,hwndChildAfter,NULL,NULL)递归返回桌面窗口所有子窗口们类名为Internet Explorer_Server的句柄。
MSAA定义的方法ObjectFromLresult通过上面得到的句柄能获得想要的MSIE接口,如:IHTMLDocument、IHTMLDocument2(见KB 249232和Automating IE)和IWebbrowser2(间接取得,见从HWnd得到IWebbrowser2接口)等。
在“Internet Explorer_Server”中选中MSIE元素后为了得到该元素,借助前面已经得到的IHTMLDocument2接口:
1. 从IHTMLDocument2::parentWindow获取IHTMLWindow2接口;
2. 从IHTMLWindow2::QueryInterface(IID_IHTMLWindow3,*)获取IHTMLWindow3接口;
3. 从IHTMLWindow3接口获取window.screenLeft和window.screenTop的值。如果成功,则返回浏览器客户区最左上角点相对于屏幕的坐标
4. 用先前GetCursorPos获取的鼠标坐标减去上面得到的坐标,保存这个差值;
5. 从IHTMLDocument2::elementFromPoint获取IHTMLElement接口。
需要注意的是,步骤3可能会因安全限制返回E_ACCESSDENIED。这时采用另外一种措施替换步骤3来获取该元素所对应的正确位置:
用WindowFromPoint得到的当前“Internet Explorer_Server”句柄,ClientToScreen得到“Internet Explorer_Server”屏幕坐标。
再继续步骤4~5。