首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Windows上的Python:“访问被拒绝”有时调用win32gui.SetForegroundWindow()

Windows上的Python:“访问被拒绝”有时调用win32gui.SetForegroundWindow()
EN

Stack Overflow用户
提问于 2022-08-04 21:37:32
回答 1查看 205关注 0票数 3

在Python3.10.5中,使用win32gui模块在Windows 11上创建一个简单的窗口切换应用程序。首先,我列出所有正在运行的窗口的hwnd列表,然后在代码的其他地方使用给定的hwnd切换到其中一个窗口。代码的相关和简化部分如下所示:

代码语言:javascript
运行
复制
def winEnumHandler(hwnd, ctx):
  if win32gui.IsWindowVisible(hwnd):
    windows.append(hwnd)

def switchToWindow(hwnd):
  win32gui.SetForegroundWindow(hwnd)

def main():
  windows = []
  win32gui.EnumWindows(winEnumHandler, None)
  
main()

如果使用wxPython模块构建的Python应用程序位于前台,并且希望切换到除Python应用程序之外的窗口,则代码工作正常,但每当前台有其他应用程序时,我希望切换回应用程序的主框架或运行Python应用程序的Windows命令行,则会出现以下错误:

代码语言:javascript
运行
复制
Exception in thread Thread-2 (showSwitcher):
Traceback (most recent call last):
  File "C:\Users\asamec\AppData\Local\Programs\Python\Python310-32\lib\threading.py", line 1016, in _bootstrap_inner
    self.run()
  File "C:\Users\asamec\AppData\Local\Programs\Python\Python310-32\lib\threading.py", line 953, in run
    self._target(*self._args, **self._kwargs)
  File "c:\Users\asamec\Dropbox\DIY\Python\WinSwitcher\WinSwitcher\src\WinSwitcher.py", line 207, in showSwitcher
    self.switchToApp(app)
  File "c:\Users\asamec\Dropbox\DIY\Python\WinSwitcher\WinSwitcher\src\WinSwitcher.py", line 165, in switchToApp
    self.switchToWindow(hwnd)
  File "c:\Users\asamec\Dropbox\DIY\Python\WinSwitcher\WinSwitcher\src\WinSwitcher.py", line 172, in switchToWindow
    win32gui.SetForegroundWindow(hwnd)
pywintypes.error: (5, 'SetForegroundWindow', 'Access is denied.')   t

因此,问题是:我如何绕过“访问被拒绝”异常,为什么只在从另一个窗口切换到运行在后台的Python应用程序窗口时抛出,而不是从前台的应用程序窗口切换到其他窗口?

更新

基于本文提供的第一个解析器,看起来由于Windows的限制,使用win32gui模块及其API不可能实现所需的窗口切换。那么问题是:即使Python应用程序没有在前台运行,还有其他方法如何切换到特定的窗口吗?我之所以问这个问题,是因为如果进程PID是已知的,那么使用pywinauto模块就可以进行这种切换,下面的代码如下所示:

代码语言:javascript
运行
复制
from pywinauto import Application

app = Application().connect(process=pid)
app.top_window().set_focus()

我不想使用使用pywinauto模块的上述代码的最初原因是,我认为它执行得很慢,但是,我发现性能问题在代码的其他部分。因此,我将这个问题的第一个分析标记为已接受的问题,因为它也回答了我的后续问题,即:为什么pywinauto方法不受Windows系统限制的影响?

接受的anser提供了一种不需要所需应用程序的PID的解决方案,以及切换到该应用程序的相关pywinauto方法。相反,它提供了一个切换到所需窗口的解决方案,而不是通过窗口的hwnd进行处理,这实际上是问题的初衷。答案还解释了绕过Windows窗口切换限制的解决方法在于在运行win32gui.SetForegroundWindow(hwnd)方法之前使用将鼠标指针移出屏幕的技巧。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-07 14:41:06

这是操作系统的一个限制。微软的文档详细解释了当它阻止使用SetForegroundWindow设置前台窗口时

系统限制哪些进程可以设置前台窗口。只有当下列条件之一为真时,进程才能设置前台窗口:

  • 这个过程就是前景进程。
  • 进程由前台进程启动。
  • 进程接收到最后一个输入事件。
  • 没有前台进程。
  • 正在调试该进程。
  • 前台进程不是现代应用程序或启动屏幕。
  • 前景未被锁定(请参见LockSetForegroundWindow)。
  • 前台锁定超时已过期(请参阅SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo)。
  • 菜单没有活动。

当用户使用另一个窗口时,应用程序无法将窗口强制到前台。相反,Windows会闪烁窗口的任务栏按钮以通知用户。可以设置前台窗口的进程可以通过调用AllowSetForegroundWindow函数使另一个进程能够设置前景窗口。dwProcessId指定的进程将失去下次用户生成输入时设置前台窗口的能力,除非输入指向该进程,或者下次进程调用AllowSetForegroundWindow时,除非指定了该进程。

附加细节

pywinauto在调用SetForegroundWindow时也受到同样的限制。然而,他们通过将鼠标位置设置到屏幕外的一个点来绕过这个问题。然后,可以再次成功地调用SetForegroundWindow。由于pywinauto是开源的,所以您也可以查看相应的代码段

测试

当Wordpad实例和任务管理器窗口同时打开时,将执行以下程序。这与选择第二个窗口很好,因为鼠标被移出屏幕。如果鼠标移动被注释掉,则会出现Access is denied.错误。

当然,这需要pywinauto import mouse,但它允许以这种方式轻松演示功能。

代码语言:javascript
运行
复制
import win32gui
import win32con
from pywinauto import mouse
from time import sleep


def foreground(window_title):
    hwnd = win32gui.FindWindow(None, window_title)
    win32gui.ShowWindow(hwnd, win32con.SW_SHOW)
    win32gui.SetForegroundWindow(hwnd)


if __name__ == "__main__":
    foreground("Document - Wordpad")
    sleep(1)
    #if you comment the next line you will get a 'Access is denied.' error
    mouse.move(coords=(-10000, 500))
    foreground("Task Manager")
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73242440

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档