2008年9月2日星期二

一些Windows编程小技巧

做了一段时间的Windows编程,可以说收获不小。

1. 让主进程进入调试器模式

上周做了一个小工具,封装了mp4box来进程媒体处理,发现了mp4box在处理损坏了的媒体文件的时候有会发生异常,但是它自己没有处理好,会导致异常被Windows捕捉到,而弹出了"Unhandled Exception"的窗口,导致程序阻塞,而我的程序刚好是用于自动化平台的。这个问题挺让人头疼的,对于同一个进程空间的异常,可以通过在FS:[0]来注册自己的结构化异常处理(SEH,在windows核心编程里面有)函数,所有为被捕捉的异常都会被交到这里来处理。

不同进程空间的没有了解到有什么好的处理办法(后来有人说可以通过系统的设置屏蔽掉默认的"Unhandled Exception"的警告)。当时有一种比较容易想到的做法,就是扫出当前的活动窗口,然后发送鼠标时间把其关闭,但是这个只能用超时来做,我不喜欢这种方式。

后来在msdn了解到有一种调试器模式创建进程,可以获得子进程在异常时候触发的各种调试信息,其中就包括地址访问出错,数组越界,除零错误等等,作为调试器,当然可以在这个时候终止掉被启动(被调试)的进程。

具体的可以参考微软关于调试器的资料:http://msdn.microsoft.com/en-us/library/ms679304(VS.85).aspx

2. 获取鼠标所在位置的窗口句柄

获取句柄可以使用WindowFromPoint(POINT)这个 API,获得句柄以后还有一系列的API可以用于获取窗口信息比如标题,尺寸,位置,父窗口等等。

实际使用过程中,发现对于某些窗口,不能直接获取,只能通过ClientWindowFromPoint(hwndFather, POINT)来在一个窗口区域获取子窗口,当然子窗口也要刚好覆盖了这个屏幕位置,这里的POINT坐标需要使用相对于父窗口的坐标--可以通过ScreenToClient来转换坐标。

另外发现一些窗口无法获取句柄,可能是根本就没有窗口句柄,有点奇怪。试过youku网站首页上面的那个flash窗口,是获取不了句柄的,我怀疑不是没有(因为他和ie应该是两个不同的窗口来的,不过也有可能是直接GDI画到上面),而是窗体比较高级,使用我找到的这些API没法获取。

3. 查找子进程的窗体位置

创建子进程以后,可以得到进程的Handle,不过貌似没有直接的办法获取窗体HWND,但是有别的办法,比如枚举窗口EnumWindows(),然后比较Handle或者窗体标题。这部分正准备做,还没有对比哪种实际上更好。

4. 查找网页上面的视频播放器位置

如果有鼠标,直接指过去就是了,如果没有人工操作,可以通过枚举IE窗口的子窗口,然后对比标题或者classID,如果没有的话,我现在用这种算法:

在要查找的区域,比如IE窗口,隔一定步长查找一下最深层的窗体HWND,对于1000*1000这样规模的屏幕,需要采样的点是10^4个,查找最深层窗体需要的层数可能是2-3层,可以限定一下,其实我只见过2层的。

已经采样得到的点,组成了一个Handle矩阵,每个handle组成的都是一个矩形,可能有嵌套。合法的视频窗口都是没有子窗口的,所以可以排除掉一些了,然后剩下的这些,可以取最大的一个当作是视频窗口了,在网页上面应该是正确的。如果遇到广告比视频大的情况,可能要辅以其他的判断方法了,比如查询其ClassID。

5. 在屏幕上面画画

用GDI函数。可以使用Rectangle()等函数,然后注册一个画笔到窗口对应的DC上面去来画矩形。我只用到了画矩形,很好用,选定视频以后把它圈出来。

6. 处理网页

我使用了ActiveX的IE控件,目前只是用于网页浏览,还有IDocHostUIHandler接口没有尝试,打算自己处理DOM。

没有使用Firefox的XPCOM接口,也作为未来尝试的一个计划。

没有评论: