admin
2025-06-10 568c763084b926a6f2d632b7ac65b9ec8280752f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import array
 
import cv2
import numpy
import win32api
import win32con
import win32gui
import win32ui
import ctypes
from ctypes import wintypes
 
from utils import invalid_hwnds_manager
 
 
def is_visible(hwnd):
    return win32gui.IsWindowVisible(hwnd)
 
 
# 定义常量
SMTO_NORMAL = 0x0000
SMTO_BLOCK = 0x0001
SMTO_ABORTIFHUNG = 0x0002
SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
 
text_hwnds_doing = set()
 
 
def get_title(hwnd):
    length = ctypes.c_int(256)
    buffer = ctypes.create_unicode_buffer(length.value)
    ctypes.windll.user32.SendMessageTimeoutW(
        hwnd,
        ctypes.c_int(0x000D),  # WM_GETTEXT
        ctypes.c_int(255),
        ctypes.c_void_p(buffer),
        ctypes.c_int(0x0002),  # SMTO_ABORTIFHUNG
        ctypes.c_int(1000),
        ctypes.pointer(ctypes.c_int(0))
    )
    return buffer.value
 
 
def getText(hwnd):
    text_hwnds_doing.add(hwnd)
    try:
        bufSize = win32gui.SendMessage(hwnd, win32con.WM_GETTEXTLENGTH, 0, 0) + 1
        buffer = array.array('b', b'\x00\x00' * bufSize)
        win32gui.SendMessage(hwnd, win32con.WM_GETTEXT, bufSize, buffer)
        text = win32gui.PyGetString(buffer.buffer_info()[0], bufSize - 1)
        return text.replace("\x00", "").strip()
    finally:
        text_hwnds_doing.discard(hwnd)
 
 
# 根据标题模糊匹配
def search_window(title, max_count=3):
    invalid_hwnds = invalid_hwnds_manager.get_hwnds()
    hwnds = []
    try:
        hwnd = win32gui.GetDesktopWindow()
        temp = None
        while True:
            if temp not in invalid_hwnds:
                if temp and win32gui.IsWindowVisible(temp):
                    str_ = getText(temp)
                    if str_.find(title) > -1:
                        hwnds.append(temp)
                        if len(hwnds) >= max_count:
                            break
            temp = win32gui.FindWindowEx(hwnd, temp, None, None)
            if not temp:
                break
    except:
        pass
    return hwnds
 
 
def visual_click(hwnd, pos):
    position = pos[1] * pow(16, 4) + pos[0]
    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, 0x00000001, position)
    win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0x00000000, position)
 
 
def visual_keyboard(hwnd, code):
    win32gui.PostMessage(hwnd, win32con.WM_KEYDOWN, code, 0)
    win32gui.PostMessage(hwnd, win32con.WM_KEYUP, code, 0)
 
 
def visual_keyboard_F5(hwnd):
    win32gui.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_F5, 0)
    win32gui.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_F5, 0)
 
 
# rect格式为:(左,上,右,下坐标)
def window_capture(hwnd, rect, scale, is_test=False):
    rect_ = win32gui.GetWindowRect(hwnd)
    ow = rect_[2] - rect_[0]
    oh = rect_[3] - rect_[1]
    ow = int(ow * scale)
    oh = int(oh * scale)
    w = rect[2] - rect[0]
    h = rect[3] - rect[1]
    if w == 0 or h == 0:
        return None
    # 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
    hWndDC = win32gui.GetWindowDC(hwnd)
    # 创建设备描述表
    mfcDC = win32ui.CreateDCFromHandle(hWndDC)
    # 创建内存设备描述表
    saveDC = mfcDC.CreateCompatibleDC()
    # 创建位图对象准备保存图片
    saveBitMap = win32ui.CreateBitmap()
 
    if not is_test:
        # 为bitmap开辟存储空间
        saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
        # 将截图保存到saveBitMap中
        saveDC.SelectObject(saveBitMap)
        # 保存bitmap到内存设备描述表
        saveDC.BitBlt((0, 0), (ow, h), mfcDC, (rect[0], rect[1]), win32con.SRCCOPY)
    else:
        # 为bitmap开辟存储空间
        saveBitMap.CreateCompatibleBitmap(mfcDC, ow, oh)
        # 将截图保存到saveBitMap中
        saveDC.SelectObject(saveBitMap)
        # 保存bitmap到内存设备描述表
        saveDC.BitBlt((0, 0), (ow, oh), mfcDC, (0, 0), win32con.SRCCOPY)
        # 保存数据
        saveBitMap.SaveBitmapFile(saveDC, "test_origin.png")
        # 内存释放
        win32gui.DeleteObject(saveBitMap.GetHandle())
        saveDC.DeleteDC()
        mfcDC.DeleteDC()
        win32gui.ReleaseDC(hwnd, hWndDC)
 
        #########################保存最新的数据##########################
        hWndDC = win32gui.GetWindowDC(hwnd)
        mfcDC = win32ui.CreateDCFromHandle(hWndDC)
        saveDC = mfcDC.CreateCompatibleDC()
        # 创建位图对象准备保存图片
        saveBitMap = win32ui.CreateBitmap()
        saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
        # 将截图保存到saveBitMap中
        saveDC.SelectObject(saveBitMap)
        saveDC.BitBlt((0, 0), (ow, h), mfcDC, (rect[0], rect[1]), win32con.SRCCOPY)
        saveBitMap.SaveBitmapFile(saveDC, "test_origin_clip.png")
 
    signedIntsArray = saveBitMap.GetBitmapBits(True)
 
    # 内存释放
    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(hwnd, hWndDC)
 
    im_opencv = numpy.frombuffer(signedIntsArray, dtype='uint8')
    im_opencv.shape = (h, w, 4)
    cv2.cvtColor(im_opencv, cv2.COLOR_BGRA2RGB)
    return im_opencv
 
 
def move_window(hwnd, x, y):
    """
    移动窗口
    :param hwnd:
    :param x:
    :param y:
    :return:
    """
    try:
        # 获取窗口的当前矩形区域
        rect = win32gui.GetWindowRect(hwnd)
        width = rect[2] - rect[0]
        height = rect[3] - rect[1]
        # 移动窗口到指定位置 (x, y),并保持窗口的宽度和高度不变
        win32gui.MoveWindow(hwnd, x, y, width, height, True)
        print(f"窗口已移动到位置 ({x}, {y})")
    except Exception as e:
        print(f"移动窗口失败: {e}")
 
 
if __name__ == "__main__":
    # print(search_window("副屏1"))
    # visual_click(0x00152876, (110, 90))
 
    window_capture(0x00010986, (0, 0, 1920, 895))
    # pass