gpt4 book ai didi

Windows 上的 Python : "Access is denied" sometimes when calling win32gui. SetForegroundWindow()

转载 作者:行者123 更新时间:2023-12-05 03:20:13 35 4
gpt4 key购买 nike

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

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 命令行,我收到以下错误:

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 Python 模块实际上可以使用以下代码进行这种切换:

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)方法之前将鼠标指针移出屏幕的技巧。

最佳答案

这是操作系统的限制。微软的documentation详细解释了何时阻止使用 SetForegroundWindow 设置前景窗口:

The system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true:

  • The process is the foreground process.
  • The process was started by the foreground process.
  • The process received the last input event.
  • There is no foreground process.
  • The process is being debugged.
  • The foreground process is not a Modern Application or the Start Screen.
  • The foreground is not locked (see LockSetForegroundWindow).
  • The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
  • No menus are active.

An application cannot force a window to the foreground while the user is working with another window. Instead, Windows flashes the taskbar button of the window to notify the user.A process that can set the foreground window can enable another process to set the foreground window by calling the AllowSetForegroundWindow function. The process specified by dwProcessId loses the ability to set the foreground window the next time the user generates input, unless the input is directed at that process, or the next time a process calls AllowSetForegroundWindow, unless that process is specified.

其他详细信息

pywinauto 在调用 SetForegroundWindow 时受到相同的限制。但是,他们通过将鼠标位置设置为屏幕外的点来解决这个问题。然后再次调用SetForegroundWindow即可成功。由于pywinauto是开源的,你也可以看看对应的code snippet .

测试

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

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

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")

关于Windows 上的 Python : "Access is denied" sometimes when calling win32gui. SetForegroundWindow(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73242440/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com