在Python3.10.5中,使用win32gui模块在Windows 11上创建一个简单的窗口切换应用程序。首先,我列出所有正在运行的窗口的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模块就可以进行这种切换,下面的代码如下所示:
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)
方法之前使用将鼠标指针移出屏幕的技巧。
发布于 2022-08-07 14:41:06
这是操作系统的一个限制。微软的文档详细解释了当它阻止使用SetForegroundWindow
设置前台窗口时
系统限制哪些进程可以设置前台窗口。只有当下列条件之一为真时,进程才能设置前台窗口:
当用户使用另一个窗口时,应用程序无法将窗口强制到前台。相反,Windows会闪烁窗口的任务栏按钮以通知用户。可以设置前台窗口的进程可以通过调用AllowSetForegroundWindow函数使另一个进程能够设置前景窗口。dwProcessId指定的进程将失去下次用户生成输入时设置前台窗口的能力,除非输入指向该进程,或者下次进程调用AllowSetForegroundWindow时,除非指定了该进程。
附加细节
pywinauto
在调用SetForegroundWindow
时也受到同样的限制。然而,他们通过将鼠标位置设置到屏幕外的一个点来绕过这个问题。然后,可以再次成功地调用SetForegroundWindow
。由于pywinauto
是开源的,所以您也可以查看相应的代码段。
测试
当Wordpad实例和任务管理器窗口同时打开时,将执行以下程序。这与选择第二个窗口很好,因为鼠标被移出屏幕。如果鼠标移动被注释掉,则会出现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")
https://stackoverflow.com/questions/73242440
复制相似问题