用户更改键盘布局时程序挂起的问题

The Old New Thing (Raymond Chen) 新闻

摘要

一个调试故事,讲述了当用户更改键盘布局(例如使用 Win+Space 快捷键)时,Windows 程序挂起的原因,是由于一个后台线程创建了窗口但没有泵送消息。修复方法是要么泵送消息,要么销毁窗口。

<p>有客户报告说,当用户更改键盘布局时(比如使用 <kbd>Win</kbd>+<kbd>Space</kbd> 快捷键组合),他们的程序会挂起。他们调试后发现,应用程序中的前景窗口接收到了 <code>WM_<wbr />INPUT­LANG­CHANGE­REQUEST</code> 消息,而当该消息传递给 <code>Def­Window­Proc</code> 时,调用再也没有返回。<code>WM_<wbr />INPUT­LANG­CHANGE­REQUEST</code> 消息有什么诡异之处呢?</p> <p>诡异之处在于,<code>WM_<wbr />INPUT­LANG­CHANGE­REQUEST</code> 消息的默认行为就是更改输入语言!</p> <p>出于历史原因(因此现在也是为了兼容性),当通过热键发起的输入语言更改请求被接受时,系统会将更改应用到该进程的所有线程。这意味着进程中的所有 UI 线程都需要泵送消息,以便它们能够接收键盘状态已更改的通知。</p> <p>在本例中,客户有一个后台线程创建了一个窗口,但没有泵送消息。这阻止了语言更改的完成,并导致主 UI 线程挂起。</p> <p>客户想知道是否有办法配置他们的程序,使得通过热键发起的输入语言更改不要求所有线程都泵送消息。但这只是在试图解决一个过于狭窄的问题。如果你的线程创建了一个窗口,那么它必须泵送消息。今天它导致输入语言更改出问题;明天它会导致 DDE 出问题;后天它又会导致主题更改出问题。</p> <p>即使你有办法改变语言更改的工作方式,这也只是你的无响应线程引起的众多问题之一。你应该修复根本原因:要么泵送消息,要么销毁窗口,使其不再是 UI 线程,也无需再负责泵送消息。</p> <p>本文 <a href="https://devblogs.microsoft.com/oldnewthing/20260513-00/?p=112318">用户更改键盘布局时程序挂起的问题</a> 最初发表于 <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>。</p>
查看原文
查看缓存全文

缓存时间: 2026/05/16 03:31

# 用户更改键盘布局时程序挂起的问题 - The Old New Thing 来源:https://devblogs.microsoft.com/oldnewthing/20260513-00?p=112318 有客户报告,当用户更改键盘布局时(例如通过 `Win+Space` 热键序列),他们的程序会挂起。他们调试到这一步:观察到应用程序中的前景窗口收到了一条 `WM_INPUTLANGCHANGEREQUEST` 消息,而当该消息被传递给 `DefWindowProc` 时,调用再也没有返回。`WM_INPUTLANGCHANGEREQUEST` 消息到底有什么诡异之处呢? 诡异之处在于,`WM_INPUTLANGCHANGEREQUEST` 消息的默认行为是——更改输入语言! 出于历史(因此也出于兼容性)原因,当热键触发的输入语言更改请求被接受时,系统会将该更改应用于该进程的所有线程。这意味着进程中的所有 UI 线程都需要处于消息泵送状态,以便它们能够收到键盘状态已更改的通知。 在这个案例中,客户有一个后台线程创建了一个窗口,但没有泵送消息。这阻止了语言更改的完成,并导致主 UI 线程挂起。 客户想知道是否有办法配置他们的程序,使得由热键触发的输入语言更改不要求所有线程都泵送消息。但这样试图解决的问题范围太窄了。如果你的线程创建了窗口,那么它就必须泵送消息。今天它给输入语言更改带来了麻烦;明天它就会给 DDE 带来问题;后天它又会给主题更改带来问题。 即使你有办法改变语言更改的工作方式,这也只是你的无响应线程所引发的诸多问题之一。你应该修复根本原因:要么泵送消息,要么销毁窗口,使其不再是 UI 线程,从而不再有义务泵送消息。 ### 分类 ### 主题 ## 作者 Raymond Chen Raymond 参与 Windows 的演变已有 30 多年。2003 年,他创办了一个名为 The Old New Thing 的网站,该网站的火爆程度远超他最疯狂的想象,这一发展至今仍令他感到不安。该网站还衍生出一本书,巧合的是书名也是《The Old New Thing》(Addison Wesley 2007 年出版)。他偶尔会出现在 Windows Dev Docs 的 Twitter 账户上,讲述一些不传达有用信息的故事。

相似文章

理解在试图绕过规则时规则背后的原理

The Old New Thing (Raymond Chen)

本文来自微软的《老东西》博客,解释了Windows内核回调函数最佳实践背后的原理,特别是为什么阻塞或等待工作项会违背其目的,并通过一个关于驱动程序导致系统挂起的警示故事来说明。