You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Windows环境下检测并捕获UAC提示窗口?

如何在Windows环境下检测并捕获UAC提示窗口?

兄弟,你遇到的问题核心是UAC提示窗口运行在**安全桌面(Secure Desktop)**上,普通权限的程序根本没法直接访问这个桌面的窗口资源,这就是为什么你用win32gui.GetForegroundWindow()会拿到无效句柄报错,pyautogui也捕获不到它的原因。下面给你几个可行的解决方案:

一、先给你的程序提升权限

UAC窗口属于高权限的安全桌面,你的程序必须以管理员身份运行才能访问它。有两种方式:

  • 手动右键程序,选择“以管理员身份运行”
  • 让程序启动时自动请求管理员权限:可以用这段代码自动检测并提权,不用每次手动操作:
import ctypes
import sys

def is_admin():
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

if not is_admin():
    # 重启程序并请求管理员权限
    ctypes.windll.shell32.ShellExecuteW(
        None, "runas", sys.executable, " ".join(sys.argv), None, 1
    )
    sys.exit()

二、用EnumWindows枚举所有窗口(替代GetForegroundWindow)

提权后,直接用GetForegroundWindow可能还是不稳定(因为安全桌面切换时系统有特殊处理),改用EnumWindows遍历所有窗口,筛选UAC窗口的标题或类名会更可靠:

import win32gui

def callback(hwnd, extra):
    window_list = extra
    title = win32gui.GetWindowText(hwnd)
    # UAC窗口的标题默认是"User Account Control",也可以用类名筛选(类名是#32770)
    if title == "User Account Control" or win32gui.GetClassName(hwnd) == "#32770":
        window_list.append((hwnd, title))
    return True

def find_uac_window():
    window_list = []
    win32gui.EnumWindows(callback, window_list)
    return window_list

# 循环检测示例
import time
while True:
    uac_windows = find_uac_window()
    if uac_windows:
        print(f"检测到UAC窗口:{uac_windows}")
        # 这里可以添加截图逻辑
    time.sleep(1)

如果你的系统是非英文版本,UAC标题会变化,用类名#32770(Windows通用对话框类)筛选会更通用。

三、捕获UAC窗口的截图(替代pyautogui.locateOnScreen)

提权后,pyautogui的全屏截图还是可能捕获不到安全桌面的内容,建议直接针对UAC窗口的句柄用PrintWindow函数精准截图:

import win32gui
import win32ui
import win32con
from PIL import Image

def capture_window(hwnd):
    # 获取窗口的位置和大小
    left, top, right, bottom = win32gui.GetWindowRect(hwnd)
    width = right - left
    height = bottom - top

    # 创建设备上下文对象
    hwnd_dc = win32gui.GetWindowDC(hwnd)
    mfc_dc = win32ui.CreateDCFromHandle(hwnd_dc)
    save_dc = mfc_dc.CreateCompatibleDC()

    # 创建位图用于存储截图
    save_bitmap = win32ui.CreateBitmap()
    save_bitmap.CreateCompatibleBitmap(mfc_dc, width, height)
    save_dc.SelectObject(save_bitmap)

    # 捕获窗口画面
    save_dc.BitBlt((0, 0), (width, height), mfc_dc, (0, 0), win32con.SRCCOPY)

    # 转换为PIL Image格式
    bmp_info = save_bitmap.GetInfo()
    bmp_data = save_bitmap.GetBitmapBits(True)
    img = Image.frombuffer(
        'RGB',
        (bmp_info['bmWidth'], bmp_info['bmHeight']),
        bmp_data, 'raw', 'BGRX', 0, 1
    )

    # 清理资源
    win32gui.DeleteObject(save_bitmap.GetHandle())
    save_dc.DeleteDC()
    mfc_dc.DeleteDC()
    win32gui.ReleaseDC(hwnd, hwnd_dc)

    return img

# 用法示例:当检测到UAC窗口时调用
uac_windows = find_uac_window()
if uac_windows:
    hwnd, _ = uac_windows[0]
    uac_screenshot = capture_window(hwnd)
    uac_screenshot.save("uac_prompt.png")

为啥你原来的代码会报错?

当UAC提示弹出时,系统会自动切换到安全桌面,这个桌面的所有窗口都属于高权限进程,普通权限的程序无法获取它们的有效句柄,所以win32gui.GetForegroundWindow()返回的是无效值,调用GetWindowText时就会抛出pywintypes.error: (1400, 'GetClassName', 'Invalid window handle.')的错误。

备注:内容来源于stack exchange,提问作者Mujtaba

火山引擎 最新活动