从LocalSystem服务生成的GUI应用(通过CreateProcessAsUser)没有焦点

1 投票
2 回答
870 浏览
提问于 2025-04-15 11:34

我创建了一个服务,这个服务可以在特定用户的桌面上显示一个欢迎界面,而且只有当这个用户登录时(也就是所谓的“自助服务用户”)才会显示。

当用户输入一个有效的代码后,欢迎界面会告诉服务,然后服务会进入休眠状态,休眠的时间取决于输入的代码。

欢迎界面在这时会自动关闭。等服务醒来时,它会发现欢迎界面已经不在了,于是就会重新启动它。

这一切都运行得很好,唯一的问题是启动的应用程序没有获得焦点。也就是说,如果我正在使用记事本,而时间到了,欢迎界面会在记事本的后面全屏显示。

我只需要关注Windows Vista,我是在用Python编程,使用的是win32扩展,但我认为这个问题出在从LocalSystem账户调用CreateProcessAsUser时。


更新:

其实这个“问题”是故意设置的限制,目的是为了防止像我这样的应用程序抢占焦点。

你可以通过设置以下内容来改变这种行为:
win32gui.SystemParametersInfo(win32con.SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0)
这相当于临时修改注册表中的一个值:
HKEY_CURRENT_USER\Control Panel\Desktop\ForegroundLockTimeout
这必须以用户身份进行,所以你可以把它放在你要启动的应用程序中,或者为你想启动的应用程序创建一个启动助手。

不过,有些应用程序可能会使用某些API调用来防止被抢占焦点,我现在不太记得具体是什么了。

一个可能不错的解决方案是找到当前用户的所有窗口句柄,然后使用这些句柄通过win32gui.ShowWindow(handle, command)来最小化它们。

不过对于这个特定的问题,设置锁定超时的选项就足够了。

如果有人想知道我是怎么从服务启动一个应用程序到桌面的,这里有一个代码链接

2 个回答

2

你有没有试过从服务里启动其他程序,比如记事本,看看它是否会抢占你浏览器的焦点?如果是这样的话,可能是这个程序在启动时能够重新获得焦点。

另外,我认为应该是lpStartupInfo指向的STARTUPINFO结构中的wShowWindow属性来控制这个行为。你还需要在dwFlags中设置STARTF_USESHOWWINDOW,才能使用nShowWindow。值应该是SW_SHOW,我想,如果你想尝试其他的值,可以查看ShowWindow函数的相关说明。

0

出于一些非常合理的原因,微软不希望某个服务启动一个应用程序并抢占用户的注意力。不过,我找到了一种解决办法,依然可以实现我想要的功能。

我最初的想法是做一个像自助服务机那样的应用程序,启动时有一个需要输入密码的欢迎界面。用户输入一个8位的密码后,这个欢迎界面会在一段时间内消失,时间是根据密码设置的。最开始,我是通过自动启动文件夹来启动这个应用程序的。

不过现在我重新写了代码,让它从我的服务中启动。这样,我可以通过从服务中启动一个辅助应用程序来隐藏主程序,这个辅助程序只负责隐藏主程序并显示欢迎界面。当用户退出欢迎界面后,主程序会恢复到之前的状态。

撰写回答