Python 获取已创建的窗口的hwnd处理程序

Python 获取已创建的窗口的hwnd处理程序,python,winapi,Python,Winapi,我正在尝试创建一个窗口,然后获取所创建窗口的hwnd 目前,我调用subprocess.run(“run.exe”)来创建窗口,然后继续调用wg.getForeGroundIndow()来获取前台窗口的hwnd,它应该是新创建的窗口。然而,这并不能很好地工作,因为程序必须在被检测为前台之前完成打开,同时用户可能会改变焦点 是否有更一致的方法来获取hwnd 编辑: 以下是我在以下评论的帮助下正在做的事情: def create_window(): user32 = ctypes.windl

我正在尝试创建一个窗口,然后获取所创建窗口的hwnd

目前,我调用
subprocess.run(“run.exe”)
来创建窗口,然后继续调用
wg.getForeGroundIndow()
来获取前台窗口的hwnd,它应该是新创建的窗口。然而,这并不能很好地工作,因为程序必须在被检测为前台之前完成打开,同时用户可能会改变焦点

是否有更一致的方法来获取hwnd

编辑: 以下是我在以下评论的帮助下正在做的事情:

def create_window():
    user32 = ctypes.windll.user32
    ole32 = ctypes.windll.ole32

    EVENT_OBJECT_CREATE = 0x8000
    def callback(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime):
        if is_real_window(hwnd):
            print(get_text(hwnd), "HOOKED")
            user32.UnhookWinEvent(hWinEventHook)
            return hwnd

    WinEventProcType = ctypes.WINFUNCTYPE(
        None, 
        ctypes.wintypes.HANDLE,
        ctypes.wintypes.DWORD,
        ctypes.wintypes.HWND,
        ctypes.wintypes.LONG,
        ctypes.wintypes.LONG,
        ctypes.wintypes.DWORD,
        ctypes.wintypes.DWORD
    )

    WinEventProc = WinEventProcType(callback)

    user32.SetWinEventHook.restype = ctypes.wintypes.HANDLE
    hook = user32.SetWinEventHook(
        EVENT_OBJECT_CREATE,
        EVENT_OBJECT_CREATE,
        0,
        WinEventProc,
        0,
        0,
        0
    )
    if hook == 0:
        print('SetWinEventHook failed')
        sys.exit(1)

    msg = ctypes.wintypes.MSG()

    x = subprocess.Popen("C:\\cygwin64\\bin\\mintty.exe")

    m = user32.GetMessageW(ctypes.byref(msg), 0, 0, 0)
然而,这面临两个问题。首先,虽然我可以在回调函数中访问hwnd,但似乎没有办法让create_窗口返回这个值。其次,GetMessage窗口继续运行,即使在调用UnhookWinEvent之后也是如此

我能做些什么来修复这些

  • 分配回调中接收的
    hwnd
    是一个范围问题。 回调函数是异步调用的,因此不可能返回值; 相反,您可以将该值分配给另一个作用域中的变量,例如,分配给 全局变量:

    def callback((hWinEventHook, event, hwnd, ...):
        global HWND
        HWND = hwnd
        ....
    
  • 虽然
    GetMessage
    似乎永远都在运行,但实际上它正在等待消息被删除 已发布到其消息队列。 正如合同中所述:

    从调用线程的消息队列检索消息。该函数将发送传入的消息,直到已发布的消息可供检索为止

    在调用GetMessage之前,请记住存储线程id,例如在全局变量中:

    def create_window(..):
        global THREAD_ID
        THREAD_ID = win32api.GetCurrentThreadId()
    
        ...
        m = user32.GetMessageW(ctypes.byref(msg), 0, 0, 0)
    
    因此,任何发布到安装了钩子的线程的消息都会使 GetMessage停止“运行”并返回一个值:

    def callback(...):
        ...
        win32gui.PostThreadMessage(THREAD_ID, win32con.WM_QUIT, 0, 0)
        # also valid:
        # win32gui.PostThreadMessage(THREAD_ID, win32con.WM_MOVE, 0, 0)  
    
  • 要取消挂钩,首先需要GetMessage循环退出。自然的 调用
    UnhookWinEvent
    的位置在
    GetMessage
    之后,因此当后面的 退出时,将执行下一步的取消挂钩操作:

    def create_window(hWinEventHook, event, hwnd, ...):
        ...
        m = user32.GetMessage(ctypes.byref(msg), 0, 0, 0)
        user32.UnhookWinEvent( hWinEventHook )
        return HWND
    
  • 为了方便地将回调中接收的
    hwnd
    与其可执行文件匹配, 有一个有用的
    getProcessFileaname
    函数,它返回完整路径 到可执行文件(感谢本文作者 )

  • 分配回调中接收的
    hwnd
    是一个范围问题。 回调函数是异步调用的,因此不可能返回值; 相反,您可以将该值分配给另一个作用域中的变量,例如,分配给 全局变量:

    def callback((hWinEventHook, event, hwnd, ...):
        global HWND
        HWND = hwnd
        ....
    
  • 虽然
    GetMessage
    似乎永远都在运行,但实际上它正在等待消息被删除 已发布到其消息队列。 正如合同中所述:

    从调用线程的消息队列检索消息。该函数将发送传入的消息,直到已发布的消息可供检索为止

    在调用GetMessage之前,请记住存储线程id,例如在全局变量中:

    def create_window(..):
        global THREAD_ID
        THREAD_ID = win32api.GetCurrentThreadId()
    
        ...
        m = user32.GetMessageW(ctypes.byref(msg), 0, 0, 0)
    
    因此,任何发布到安装了钩子的线程的消息都会使 GetMessage停止“运行”并返回一个值:

    def callback(...):
        ...
        win32gui.PostThreadMessage(THREAD_ID, win32con.WM_QUIT, 0, 0)
        # also valid:
        # win32gui.PostThreadMessage(THREAD_ID, win32con.WM_MOVE, 0, 0)  
    
  • 要取消挂钩,首先需要GetMessage循环退出。自然的 调用
    UnhookWinEvent
    的位置在
    GetMessage
    之后,因此当后面的 退出时,将执行下一步的取消挂钩操作:

    def create_window(hWinEventHook, event, hwnd, ...):
        ...
        m = user32.GetMessage(ctypes.byref(msg), 0, 0, 0)
        user32.UnhookWinEvent( hWinEventHook )
        return HWND
    
  • 为了方便地将回调中接收的
    hwnd
    与其可执行文件匹配, 有一个有用的
    getProcessFileaname
    函数,它返回完整路径 到可执行文件(感谢本文作者 )


  • 你控制这两个过程的代码吗?不知道你的意思。我控制调用的python代码,但不控制正在执行的程序。你想用这个应用程序的窗口做什么?我需要hwnd来实现各种各样的功能。设置窗口样式、移动窗口等,因此仅在创建窗口时对其执行某些操作是不够的;我需要HwndWaitForInput和EnumWindows。您是否控制这两个进程的代码?不确定这是什么意思。我控制调用的python代码,但不控制正在执行的程序。你想用这个应用程序的窗口做什么?我需要hwnd来实现各种各样的功能。设置窗口样式、移动窗口等,因此仅在创建窗口时对其执行某些操作是不够的;我需要HwndWaitForInput和EnumWindows