获得 Win32 窗口句柄的更好的方法
----动态生成并显示 HTML 文档
----再谈禁用HTML的上下文菜单...
编译/NorthTibet
原文出处:MSDN Magazine C++ Q&A
下载源代码
译者注:
在以前的VC知识库 Online Journal 上有三篇文章:
“VC6中使用CHtmlView在对话框控制中显示HTML文件”(第六期)
“如何禁用HTML页面的上下文菜单”(第十一期)
“Convert CHtmlView to CHtmlCtrl...”(第十七期)
这三篇文章的原文实际上都出自 MSDN Magazine 及其前身 MSJ 的“C++ Q&A”专栏作家 Paul DiLascia 之手。此君从1995年开始就成为 MS 在 C++/MFC 方面的高级写手,Paul 在 Windows 应用开发领域的造诣颇深。直到现在仍然在为该专栏撰写技术文章,只不过其文章已不仅仅涉及 C++/MFC,偶尔也写一些 C#。为了微软的 .NET 战略,Paul 可谓忠实、勤奋和敬业......
本文是以上文章所涉及内容的延伸。如果你已经对前述文章讨论的东西了然于心,那么可以直接切入本文的正题。如果你没有看过上面提到的文章,建议最好先看一下,以便了解本文内容的背景,这样对于理解本文所讨论的东西会更有帮助。
背景简介
话说在第六期的“VC6中使用CHtmlView在对话框控制中显示HTML文件”一文中,主要讨论并示范了如何改进 MFC 的 CHtmlView 类,使它能处理基于对话框的应用和各种其它类型的窗口应用,其思路是通过创建 CHtmlView 的派生类 CHtmlCtrl,使得 CHtmlView 摆脱了对文档/视图的依赖。
在第十一期的“如何禁用HTML页面的上下文菜单”一文中,主要讨论了如何通过子类化 IE 服务器窗口(Internet Explorer_Server)来禁用 CHtmlCtrl 的上下文菜单。实际上,真正显示HTML的窗口并不是浏览器(CHtmlView/CHtmlCtrl)窗口,而是一个名为“Internet Explorer_Server”的最底层的子孙窗口。这一点可以通过 Spy++ 来证实,为了获得该窗口的句柄(HWND),在实现过程中使用了一个函数 GetLastChild(HWND hwndParent),其定义如下:
static HWND GetLastChild(HWND hwndParent){ HWND hwnd = hwndParent; while (TRUE) { HWND hwndChild = ::GetWindow(hwnd, GW_CHILD); if (hwndChild==NULL) return hwnd; hwnd = hwndChild; } return NULL;}通过这个函数返回某个父窗口下的最后一个子窗口,也就是说返回子窗口的子窗口的子窗口......直到不再有子窗口为止。可惜这个函数要获得正确的运行结果是有前提的,那就是窗口层次只能是一层,并且最终的窗口后裔是“Internet Explorer_Server”窗口。 在通常情况下,这个假设都成立。不幸的是,如果 HTML 文档中包含象 ComBoxes(组合框) 这样的控制时,这个假设就不灵了。用 Spy++ 不难发现情况并不象你期望的那样─Internet Explorer_Server是最后的子窗口。实际上,在IE中,Edit 和 Button 控制并非人们所想象的那样是子窗口。
获得 Win32 窗口句柄的更好的方法
为了解决这个问题,本文设计了一个更加完善的类:CFindWnd,用更好的算法专门来获取 IE 窗口。CFindWnd 查找某个窗口(给定窗口名字)的第一个子窗口。 例如,它的使用方法如下:
CFindWnd ies(m_hWnd, "Internet Explorer_Server");myHwndIE = ies.m_hWnd;这个类的构造函数调用函数:
FindChildClassHwnd(hwndParent, (LPARAM)this)函数,该函数又调用:
EnumChildWindows 和 FindWindowEx搜索所有后裔窗口直到找到类名匹配窗口为止。FindWindow 用来查找最顶层窗口,而搜索子窗口还得用 FindWindowEx,它是 Win32 API 函数。CFindWnd 返回第一个匹配的窗口,所以它只被用于查找你期望只有一个实例的窗口。通常在搜索特定窗口时,一般最保险的做法都是检查窗口类名。
百家争鸣
有一个读者来信指出:根本没有必要使用子类IE窗口的方法来禁用上下