为什么 Get­Last­Input­Info() 不会返回我正在模拟的用户的信息?

The Old New Thing (Raymond Chen) 工具

摘要

解释了 Get­Last­Input­Info() 在模拟情况下无法工作,因为它返回的是调用会话的数据,而不是被模拟用户的数据;要获取另一个会话的最后输入时间,必须在该会话中使用辅助进程。

<p>一位客户有一个 Windows NT 服务进程,他们想通过该服务进程获取所有已登录用户的最后输入时间。他们的策略是使用 <code>WTS­Query­User­Token()</code> 获取每个用户的令牌,然后使用该令牌模拟该用户,再调用 <code>Get­Last­Input­Info()</code> 获取该用户的最后输入时间。不幸的是,该函数总是返回服务会话的最后输入信息,而且由于服务是非交互的,它总是报告自系统启动以来没有任何输入。</p> <p><code>Get­Last­Input­Info()</code> 是否支持模拟操作?</p> <p>回想一下,<a title="模拟时此操作是否有效?默认答案为否" href="https://devblogs.microsoft.com/oldnewthing/20110928-00/?p=9533">对于“模拟时此操作是否有效?”的默认答案是“否”</a>。事实上,如果你仔细阅读 <code>Get­Last­Input­Info()</code> 的文档,它明确说明了这一点。</p> <blockquote class="q"><p>此函数对于输入空闲检测非常有用。然而,<b>GetLastInputInfo</b> 并不提供跨所有运行会话的系统级用户输入信息。相反,<b>GetLastInputInfo</b> 提供的是会话特定的用户输入信息,<u>仅针对调用该函数的会话</u>。</p></blockquote> <p>我强调了重要部分。它报告的是调用该函数的会话的最后输入信息。当服务模拟用户时,它会更新其安全上下文以与被模拟用户保持一致,但这并不能改变它仍然在会话零(即服务会话)中运行的事实。</p> <p>如果你需要从另一个会话获取最后输入信息,你需要在那个会话中有一个“朋友”来为你调用它。通常的做法是在目标会话中启动一个辅助进程:该辅助进程收集你需要的信息,然后将信息发送给服务。</p> <p><b>额外闲谈</b>:一个相关的问题是“服务中的 <code>Get­Async­Key­State</code> 是否有效?”答案是技术上有效。不过,它可能并非你所想的那样工作。它返回的是服务所在桌面的异步按键状态。由于服务在非交互式会话中运行,该桌面永远不会看到任何键盘活动。</p> <p>本文《<a href="https://devblogs.microsoft.com/oldnewthing/20260618-00/?p=112444">为什么 &lt;CODE&gt;Get­Last­Input­Info()&lt;/CODE&gt; 不会返回我正在模拟的用户的信息?</a>》最早出现在 <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a> 上。</p>
查看原文
查看缓存全文

缓存时间: 2026/06/20 14:22

# 为什么 `GetLastInputInfo()` 不会返回我正在模拟的用户的信息? - 旧事新说 来源:https://devblogs.microsoft.com/oldnewthing/20260618-00?p=112444 一位客户有一个 Windows NT 服务进程,并且他们想从该服务进程中获取所有已登录用户的最后输入时间。他们的策略是使用 `WTSQueryUserToken()` 获取每个用户的令牌,使用该令牌模拟该用户,然后调用 `GetLastInputInfo()` 来获取该用户的最后输入时间。不幸的是,该函数始终返回服务会话的最后输入信息,而由于服务不是交互式的,它总是显示自系统启动以来没有输入。 `GetLastInputInfo()` 是否支持模拟? 回想一下,“在模拟时,这能工作吗?” 的默认答案是“不行”(https://devblogs.microsoft.com/oldnewthing/20110928-00/?p=9533)。事实上,`GetLastInputInfo()` 的文档如果仔细阅读,会明确说明它不支持。 > 此函数可用于输入空闲检测。但是,**GetLastInputInfo** 不提供跨所有运行会话的系统范围用户输入信息。相反,**GetLastInputInfo** 仅针对调用该函数的会话提供会话特定的用户输入信息。 我强调了重要部分。它报告的是调用该函数的会话的最后输入信息。当服务进行模拟时,它会更新其安全上下文以匹配被模拟的用户,但这并不能改变它仍然在会话零(服务会话)中运行的事实。 如果你需要从另一个会话获取最后输入信息,你需要该会话中的一个“朋友”来替你调用它。通常,这是通过将一个辅助进程启动到目标会话中来完成的:该辅助进程收集你想要的信息,然后将信息发送给服务。 **额外讨论**:一个相关的问题是“服务中能否使用 `GetAsyncKeyState`?” 从技术上讲,答案是肯定的,它可以工作。然而,它可能不像你想的那样工作。它返回服务运行所在桌面的异步键状态。由于服务运行在非交互式会话中,该桌面永远不会看到任何键盘活动。 ### 类别 ## 作者 Raymond Chen Raymond 参与 Windows 的发展已有 30 多年。2003 年,他创办了一个名为“旧事新说”的网站,其受欢迎程度远远超出了他最疯狂的想象,这一发展至今仍让他感到后怕。该网站催生了一本书,巧合的是,书名也是《旧事新说》(Addison Wesley 2007)。他偶尔会出现在 Windows Dev Docs Twitter 账号上,讲述一些不提供有用信息的故事。

相似文章

倾听的幻象

Reddit r/ArtificialInteligence

本文分析了“倾听的幻象”这一心理现象:用户因语言线索而感知到AI具有共情能力,尽管AI并不具备真正的理解力。文章提出了设计指南,以确保透明度并防止用户将人际连接的需求外包给自动化系统。

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

The Old New Thing (Raymond Chen)

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