本文主要是介绍翻译 《The Old New Thing》 - The secret life of GetWindowText,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
The secret life of GetWindowText - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20030821-00/?p=42833
Raymond Chen 2003年8月21日
简要
GetWindowText()
函数比你想象的要复杂得多。尽管官方文档试图用简练的语言来阐述它,但这也就意味着你无法获得完整的信息。这里我们尝试给出一个完整的解释。
窗口如何管理它们的文本
窗口类有两种方式来管理它们的文本。可以用户自己手动管理,也可以让系统来代劳。默认情况下,是让系统来管理的。
如果一个窗口类让系统来管理它的文本,系统会执行以下操作:
- 默认的
WM_NCCREATE
消息处理会取CreateWindow/Ex
传入的lpWindowName
参数,并将其保存在一个“特殊的地方”。 - 默认的
WM_GETTEXT
消息处理会从那个“特殊的地方”检索字符串。 - 默认的
WM_SETTEXT
消息处理会将字符串复制到那个“特殊的地方”。
另一方面,如果一个窗口类手动管理它的窗口文本,系统不会做任何特殊处理,窗口类需要自己响应 WM_GETTEXT/WM_SETTEXT
消息,并显式地返回/保存字符串。
典型的"框架窗口"(Frame Window)通常让系统管理它们的窗口文本。自定义控件通常手动管理它们的窗口文本。
GetWindowText() 的问题
GetWindowText()
面临一个问题:窗口文本需要随时可用,不能卡住。FindWindow()
需要获取窗口文本以便找到窗口。任务切换应用程序需要获取窗口文本,以便在切换窗口中显示窗口标题。不应该允许卡住的应用程序阻塞其他应用程序。这在任务切换场景中尤其重要。
这就不能用发送 WM_GETTEXT
消息的方式,因为处理 WM_GETTEXT
的目标窗口可能已经卡住了。相反,GetWindowText()
应该使用“特殊的地方”,因为那里不会受到应用程序卡住的影响。
另一方面,GetWindowText()
用于从对话框上的控件中检索文本,而这些控件经常使用自定义文本管理。这就支持发送 WM_GETTEXT
消息,因为这是检索自定义管理文本的唯一方法。
所以 GetWindowText()
采取了折中的方法。
- 如果从自己进程中的窗口获取文本,那么
GetWindowText()
会发送WM_GETTEXT
消息。 - 如果从其他进程中的窗口获取文本,那么
GetWindowText()
会使用“特殊的地方”中的字符串,而不发送消息。
根据第一条规则,如果你尝试从自己进程中的窗口获取文本,而该窗口卡住了,那么 GetWindowText()
也会卡住。但因为窗口属于你的进程,这是你自己的问题,你自作自受。发送 WM_GETTEXT
消息确保了自定义文本管理的窗口(通常是自定义控件)的文本被正确检索。
根据第二条规则,如果你尝试从另一个进程中的窗口获取文本,那么 GetWindowText()
不会发送消息;它只会从“特殊的地方”检索字符串。因为从另一个进程中的窗口获取文本的最常见原因是获取框架窗口的标题,而框架窗口通常不会进行自定义窗口文本操作,这通常会得到正确的字符串。
文档将这简化为“GetWindowText()
无法从另一个应用程序的窗口检索文本。”(To retrieve the text of a control in another process, send a WM_GETTEXT message directly instead of calling GetWindowText.)
如果我不喜欢这些规则怎么办?
如果第二条规则让你感到困扰,因为你需要从另一个进程中的自定义控件中获取文本,那么你可以手动发送 WM_GETTEXT
消息。由于你没有使用 GetWindowText()
,所以你不受其规则的约束。
不过,请注意,如果目标窗口卡住了,你的应用程序也会卡住,因为 SendMessage()
会在目标窗口响应之前一直等待。
还要注意,由于 WM_GETTEXT
在系统消息范围内(0 到 WM_USER-1
),你不需要做数据编码转换的工作(实际上,你不应该这么做)。USER(user32.dll
) 会为你做好这些工作。
你能举一个这样的例子吗?
假设有这样一个控件:
SampleWndProc(...)
{case WM_GETTEXT:lstrcpyn((LPTSTR)lParam, "Booga!", (int)wParam);return lstrlen((LPTSTR)lParam);case WM_GETTEXTLENGTH: return 7; // lstrlen("Booga!") + null...
}
现在考虑应用程序 A 执行以下操作:
hwnd = CreateWindow("Sample", "Frappy", ...);
现在考虑进程 B 获取应用程序 A 创建的窗口的句柄(通过任何手段)。
TCHAR szBuf[80];
GetWindowText(hwnd, szBuf, 80);
这将返回 szBuf = "Frappy"
,因为它是从“特殊的地方”获取窗口文本的。然而,
SendMessage(hwnd, WM_GETTEXT, 80, (LPARAM)szBuf);
将返回 szBuf = "Booga!"
。
这篇关于翻译 《The Old New Thing》 - The secret life of GetWindowText的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!