获取每个窗口的HWND?

11
我正在开发一个Python应用程序,我想获取每个打开窗口的HWND。我需要窗口的名称和HWND,以过滤列表并管理一些具体的窗口,移动和调整它们。
我已经尝试自己寻找信息,但是没有找到正确的代码。我尝试了这个代码,但我只得到了每个窗口的标题(这很好),但我也需要HWND
import ctypes
import win32gui
EnumWindows = ctypes.windll.user32.EnumWindows
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
GetWindowText = ctypes.windll.user32.GetWindowTextW
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
IsWindowVisible = ctypes.windll.user32.IsWindowVisible

titles = []
def foreach_window(hwnd, lParam):
    if IsWindowVisible(hwnd):
        length = GetWindowTextLength(hwnd)
        buff = ctypes.create_unicode_buffer(length + 1)
        GetWindowText(hwnd, buff, length + 1)
        titles.append((hwnd, buff.value))
    return True
EnumWindows(EnumWindowsProc(foreach_window), 0)

for i in range(len(titles)):
    print(titles)[i]

win32gui.MoveWindow((titles)[5][0], 0, 0, 760, 500, True)

这里有一个错误:

win32gui.MoveWindow((titles)[5][0], 0, 0, 760, 500, True)
 TypeError: The object is not a PyHANDLE object

6
SO不是一个超市,你不能带着购物清单让别人替你完成工作。你自己做了什么? - Difusio
1
@Difusio:我尝试着自己寻找信息,但是我没有找到正确的代码片段。我已经尝试过这个链接:http://sjohannes.wordpress.com/2012/03/23/win32-python-getting-all-window-titles/, 但是我只能获取每个窗口的标题(这很棒),但是我还需要HWND。 - user1618465
4
请将您编写的代码(无论是基于您找到的还是复制的)以及您收到的错误或其他操作一起发布。我的意思是,请“发布”代码,而非“邮寄”。 - g.d.d.c
5
请不要编辑您的问题,以包含答案中的修复内容,因为这会使得后来的其他人无法理解您的问题。 - abarnert
4个回答

34

你混淆了ctypeswin32gui


你获得的hwnd是通过ctypes获得的,是一个LP_c_long对象。这就是为什么win32gui.MoveWindow无法接受它的原因。你应该将其传递给:

ctypes.windll.user32.MoveWindow(titles[5][0], 0, 0, 760, 500, True)

如果你想使用win32gui.MoveWindow,你可以直接使用Python函数作为回调函数。例如,

import win32gui

def enumHandler(hwnd, lParam):
    if win32gui.IsWindowVisible(hwnd):
        if 'Stack Overflow' in win32gui.GetWindowText(hwnd):
            win32gui.MoveWindow(hwnd, 0, 0, 760, 500, True)

win32gui.EnumWindows(enumHandler, None)

太棒了!让我的浏览器窗口跨越了三个显示器 :-D - ssc
1
非常有用的澄清。基本上不要混用ctypes和win32gui。这一简单语句可以节省很多时间 :) - BeHappy

2
为获取所有可用主窗口的句柄,您需要将0传递给win32gui.EnumChildWindows,然后检查窗口是否具有长度大于0的文本(因为您只想要实际窗口而不是隐藏/临时/弹出/特殊窗口)。

我想做相反的事情,即在弹出窗口/提示(例如UAC提示)出现时获取窗口文本。我该怎么办?因为它对于UAC提示返回无。 - Mujtaba

2
您的问题(现在Martineau已经解决了您最初的问题,即根本没有存储HWND值)是您正在尝试混合使用ctypeswin32gui
如果您知道自己在做什么,可以这样做 - 但如果不知道,请不要这样做。
如果您想获取可以与win32gui一起使用的窗口句柄,请改用{{link1:win32gui.EnumWindows}},而不是直接调用来自user32 DLL的原始函数。

记录一下,我没有修复任何原始问题。 - martineau

1

只需修改代码以获取所有标题,使其像这样执行:

titles.append((hwnd, buff.value))

titles列表将是包含HWND标题文本的元组列表。


非常感谢,但是发生了这种情况:(<__main__.LP_c_long object at 0x022A9030>, u'Spotify') 我没有得到后来将用于win32gui.MoveWindow(hwnd, 0, 0, 760, 500, True)的整数。我该如何获得这个数字? - user1618465
我在你的帮助下更新了帖子。但是为什么我不能在win32gui.MoveWindow()函数中使用HWND值呢? - user1618465
1
理论上,您应该能够使用hwnd.contents.value来获取整数值,但在我的系统上,由于未知原因而挂起。问题在于您混合使用了ctypesPyHANDLEwin32c_long类型。我认为@abarnert有避免混用它们的正确想法。 - martineau
@martineau,问题似乎在于WINFUNCTPYE的第二个参数应该是HWND,而不是指针。 - Marc Stober

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接