1.根据标题获取句柄

# 根据句柄获取线程和pid
#根据pid停止程序 

import win32gui
import time
import os
import win32process
main_hwnd = win32gui.FindWindow(None, "屏幕截图")
print(main_hwnd)

# 根据句柄获取线程和pid
thread, pid = win32process.GetWindowThreadProcessId(main_hwnd)
# 根据pid停止程序
os.system('taskkill/pid ' + str(pid) + ' /f')

def get_child_windows(parent):
    """ 获得parent的所有子窗口句柄返回子窗口句柄列表 """
    if not parent:
        return
    hwnd_child_list = []
    win32gui.EnumChildWindows(parent, lambda hwnd2, param: param.append(hwnd2), hwnd_child_list)
    return hwnd_child_list


child_hwnd = get_child_windows(main_hwnd)
print(child_hwnd)

def show_window_attr(hWnd):
    '''
    显示窗口的属性
    :return:
    '''
    if not hWnd:
        return

    # 中文系统默认title是gb2312的编码
    title = win32gui.GetWindowText(hWnd)
   #这里可能要把标题的gbk转换成utf-8 ,暂时不管了,可以加个函数
    clsname = win32gui.GetClassName(hWnd)

    # print('窗口句柄:%s ' % (hWnd))

    print('窗口类名:%s' % (clsname))
    # str = "Chrome_WidgetWin_1"
    # if str == clsname:
    #     fd = win32gui.FindWindow(clsname, None)  # 查找窗口句柄
    #     win32gui.ShowWindow(fd, 1)  # 隐藏窗口
    print ('窗口句柄:%s ' % (hWnd))
    print ('窗口标题:%s' % (title))

 2.句柄实现后台输入

# 方法一:麻烦
# 字典字母的对应编号,根据遍历账号密码,得到对应整数型键,然后由WM_IME_CHAR得到字母和数字
dic = {33: '!', 34: '"', 35: '#', 36: '$', 37: '%', 38: '&', 39: "'", 40: '(', 41: ')', 42: '*', 43: '+', 44: ',',
       45: '-', 46: '.', 47: '/', 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', 54: '6', 55: '7', 56: '8',
       57: '9', 58: ':', 59: ';', 60: '<', 61: '=', 62: '>', 63: '?', 64: '@', 65: 'A', 66: 'B', 67: 'C', 68: 'D',
       69: 'E', 70: 'F', 71: 'G', 72: 'H', 73: 'I', 74: 'J', 75: 'K', 76: 'L', 77: 'M', 78: 'N', 79: 'O', 80: 'P',
       81: 'Q', 82: 'R', 83: 'S', 84: 'T', 85: 'U', 86: 'V', 87: 'W', 88: 'X', 89: 'Y', 90: 'Z', 91: '[', 92: '\\',
       93: ']', 94: '^', 95: '_', 96: '`', 97: 'a', 98: 'b', 99: 'c', 100: 'd', 101: 'e', 102: 'f', 103: 'g', 104: 'h',
       105: 'i', 106: 'j', 107: 'k', 108: 'l', 109: 'm', 110: 'n', 111: 'o', 112: 'p', 113: 'q', 114: 'r', 115: 's',
       116: 't', 117: 'u', 118: 'v', 119: 'w', 120: 'x', 121: 'y', 122: 'z', 123: '{', 124: '|', 125: '}', 126: '~'}

text = "231yang."
for i in text:
    value = int([k for k, v in dic.items() if v == i][0])
    print(value)
    win32gui.SendMessage(1970438, win32con.WM_IME_CHAR, value)  # 输入字符串,只能英文和数字,不是按键


# 方法二:ord直接转,中文也可以输入
import win32con
import win32gui
import win32api
import time


for i in text:
    win32gui.SendMessage(hwnd, win32con.WM_IME_CHAR, ord(str(i)))  # 输入字符串,只能英文和数字,不是按键

time.sleep(1)
win32gui.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)


 3.后台粘贴

# ctrl +v 粘贴
win32api.keybd_event(17, 0, 0, 0)  # 有效,按下CTRL
win32gui.SendMessage(hwnd, win32con.WM_KEYDOWN, ord("V"), 0)  # V
win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0)  # 放开CTRL

 4.句柄后台截图

def screen(index):
    # 获取后台窗口的句柄,注意后台窗口不能最小化
    # 获取Pid(类名, 标题)
    main_hwnd = win32gui.FindWindow("LDPlayerMainFrame", "雷电模拟器" + str(index))  # 获得父句柄
    print(main_hwnd)
    hwndChildList = []
    win32gui.EnumChildWindows(main_hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList)
    hWnd = hwndChildList[0]  # 子句柄的第一个句柄
    # print(hWnd)

    left, top, right, bot = win32gui.GetWindowRect(hWnd)
    if right < 1100:
        # 获取句柄窗口的大小信息
        print("没有最大化,进行最大化")
        win32gui.ShowWindow(main_hwnd, win32con.SW_MAXIMIZE)
        hwndChildList = []
        win32gui.EnumChildWindows(main_hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList)
        hWnd = hwndChildList[0]  # 子句柄的第一个句柄
        left, top, right, bot = win32gui.GetWindowRect(hWnd)
        print(left, top, right, bot)

    width = right - left
    height = bot - top
    # 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
    hWndDC = win32gui.GetWindowDC(hWnd)
    # 创建设备描述表
    mfcDC = win32ui.CreateDCFromHandle(hWndDC)
    # 创建内存设备描述表
    saveDC = mfcDC.CreateCompatibleDC()
    # 创建位图对象准备保存图片
    saveBitMap = win32ui.CreateBitmap()
    # 为bitmap开辟存储空间
    saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
    # 将截图保存到saveBitMap中
    saveDC.SelectObject(saveBitMap)
    # 保存bitmap到内存设备描述表
    saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)

    # 保存图像
    # 方法二(第一部分):PIL保存
    # # 获取位图信息
    bmpinfo = saveBitMap.GetInfo()
    bmpstr = saveBitMap.GetBitmapBits(True)
    # 生成图像
    im_PIL = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)
    im_PIL = im_PIL.resize((720, 1280), Image.ANTIALIAS)  # 图片分辨率跳到720*1280
    im_PIL.save("im_PIL.jpg")  # 保存
    return hWnd
def pc_screen():
    # 获取后台窗口的句柄,注意后台窗口不能最小化
    # 获取Pid(类名, 标题)
    hWnd= win32gui.FindWindow("SDL_app", "Redmi Note 8")  # 屏幕
    # hWnd= win32gui.FindWindow("Qt5QWindowIcon", "QtScrcpy")  # 控制台
    print(hWnd)
    # hwndChildList = []
    # win32gui.EnumChildWindows(main_hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList)
    # hWnd = hwndChildList[0]  # 子句柄的第一个句柄
    # # print(hWnd)

    left, top, right, bot = win32gui.GetWindowRect(hWnd)
    print(left, top, right, bot)

    if (right-left) != 520 and (bot-top) != 1100:
        print("不满足分辨率需要调整")
        win32gui.MoveWindow(hWnd, 0, 0, 520, 1400, True)
        left, top, right, bot = win32gui.GetWindowRect(hWnd)

    else:
        print("满足分辨率不用调整了")
    # if right < 1100:
    #     # 获取句柄窗口的大小信息
    #     print("没有最大化,进行最大化")
    #     win32gui.ShowWindow(hWnd, win32con.SW_MAXIMIZE)
    #     hwndChildList = []
    #     win32gui.EnumChildWindows(main_hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList)
    #     hWnd = hwndChildList[0]  # 子句柄的第一个句柄
    #     left, top, right, bot = win32gui.GetWindowRect(hWnd)
    #     print(left, top, right, bot)

    width = right - left
    height = bot - top
    # 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
    hWndDC = win32gui.GetWindowDC(hWnd)
    # 创建设备描述表
    mfcDC = win32ui.CreateDCFromHandle(hWndDC)
    # 创建内存设备描述表
    saveDC = mfcDC.CreateCompatibleDC()
    # 创建位图对象准备保存图片
    saveBitMap = win32ui.CreateBitmap()
    # 为bitmap开辟存储空间
    saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
    # 将截图保存到saveBitMap中
    saveDC.SelectObject(saveBitMap)
    # 保存bitmap到内存设备描述表
    saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)

    # 保存图像
    # 方法二(第一部分):PIL保存
    # # 获取位图信息
    bmpinfo = saveBitMap.GetInfo()
    bmpstr = saveBitMap.GetBitmapBits(True)
    # 生成图像
    im_PIL = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)
    # im_PIL = im_PIL.resize((720, 1280), Image.ANTIALIAS)  # 图片分辨率跳到720*1280
    im_PIL.save("im_PIL.jpg")  # 保存
    return hWnd

 

 5.cmd后台输入例子

    """获取句柄进行后台cmd输入和回车,如果没有打开cmd就前台就行搜索框打开cmd,在进行输入,不能直接用路径打开cmd"""
    main_hwnd = win32gui.FindWindow(None, cmd_name)
    print(main_hwnd)
    if main_hwnd:
        # ssh 空格+ 用户名@ip
        input("ssh " + username + "@" + hostname, main_hwnd)
        win32gui.PostMessage(main_hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
        time.sleep(1)
        input(password, main_hwnd)
        win32gui.PostMessage(main_hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
        time.sleep(0.5)
        input("supervisorctl reload", main_hwnd)
        win32gui.PostMessage(main_hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
        time.sleep(0.5)
        input("exit", main_hwnd)
        win32gui.PostMessage(main_hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
        time.sleep(0.5)
        input("exit", main_hwnd)
        win32gui.PostMessage(main_hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
        
    else:
        print("没打开cmd,需要打开cmd")
        os.system('start "%s"' % cmd_path)
        get_hwnd()

 6.后台点击

    def click(self, x, y):
        param = win32api.MAKELONG(int(x), int(y))
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, param)
        win32api.SendMessage(self.hwnd, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, param)

 7.浏览器最大化

# -*- coding: utf-8 -*-
# from win32gui import *
# import win32gui, win32process
from win32gui import EnumWindows, IsWindow, IsWindowEnabled, GetWindowText, IsWindowVisible
import os
import time
import rpa.win32._window_action as window

time.sleep(1)
def get_pid_app(category_name, title):
    titles = set()
    def foo(hwnd, mouse):
        # 去掉下面这句就所有都输出了,但是我不需要那么多
        if IsWindow(hwnd) and IsWindowEnabled(hwnd) and IsWindowVisible(hwnd):
            titles.add(GetWindowText(hwnd))

    EnumWindows(foo, 0)
    lt = [t for t in titles if t]
    lt.sort()

    for name in lt:
       
        # 类名, 标题
        log.info(name)
        if title in name:
            print("最大化" + str(name))
            try:
                window.win_maximize(title,category_name)
            except Exception as e:
                log.info(e)

# "廊坊银行 - Internet Explorer","IEFrame"
get_pid_app("IEFrame", "Internet Explorer")
time.sleep(0.5)
# get_pid_app("IEFrame", "廊坊银行 - Internet Explorer")

# exit()
# "廊坊银行 - Internet Explorer","IEFrame"

8.模糊匹配标题获得句柄

import win32gui

def get_hwd(tilte):
    hwnd_title = dict() 
    def get_all_hwnd(hwnd,mouse):
        if win32gui.IsWindow(hwnd) and win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd):
            hwnd_title.update({hwnd:win32gui.GetWindowText(hwnd)})
    win32gui.EnumWindows(get_all_hwnd, 0)

    for h,t in hwnd_title.items():
        if tilte in t:
            # print(([h], [t]))
            return h
print(get_hwd("现金流量表"))

9.使用Win32 API在Python中自动化文件另存对话框交互的优化与简化

简介:
自动化与图形用户界面(GUI)的交互是编程中的常见任务,尤其是在处理重复性任务或需要大量步骤的任务时。在本文中,我们将探讨一种简化且优化的Python脚本,利用Win32 API自动化与文件另存对话框的交互。

代码优化:
提供的Python脚本旨在自动化与Windows中的“另存为”对话框的交互过程。脚本经历以下步骤:

  1. 查找包含指定关键字的主窗口。
  2. 检索子窗口并识别“Edit”控件。
  3. 清空输入内容。
  4. 将文件路径输入“Edit”控件。
  5. 模拟按下回车键。

以下是对原始代码进行的关键优化和简化:

  1. 改进的代码结构:
    优化了代码结构以提高可读性和可维护性。定义了函数来封装特定任务,使代码更加模块化。

  2. get_child_windows 中 param 的默认值:
    确保 get_child_windows 函数中的 param 有一个默认值为空列表,以避免潜在的错误。

  3. 使用绝对路径:
    脚本现在使用 os.path.abspath 获取文件的绝对路径,以确保正确处理文件路径。

  4. 一致的注释:
    添加了一致且信息丰富的注释,以解释脚本的每个步骤,使其更容易被他人理解。

  5. 删除不必要的操作:
    删除了不必要的 taskkill 操作,因为强制终止进程可能导致不可预测的后果。

以下是优化后的代码:

import win32gui
import win32process
import win32con
import time
import os

def get_child_windows(parent):
    """获取“parent”的所有子窗口句柄并返回列表。"""
    if not parent:
        return []
    hwnd_child_list = []
    win32gui.EnumChildWindows(parent, lambda hwnd2, param: param.append(hwnd2), hwnd_child_list)
    return hwnd_child_list

def find_save_dialog(key_word="另存为", class_name='', text='', times=10):
    """查找包含指定关键字的主窗口句柄。"""
    for _ in range(times):
        main_hwnd = win32gui.FindWindow(None, key_word)
        print("主句柄:", main_hwnd)

        if main_hwnd:
            child_hwnd_list = get_child_windows(main_hwnd)
            for hwnd in child_hwnd_list:
                clsname = win32gui.GetClassName(hwnd)
                if text:
                    gettext = win32gui.GetWindowText(hwnd)
                    print(gettext, hwnd)
                    if text == gettext:
                        return hwnd
                if clsname == "Edit":
                    return hwnd
        else:
            time.sleep(0.5)

def clear_input_box(hwnd):
    """清空编辑控件的内容。"""
    win32gui.SendMessage(hwnd, win32con.WM_SETTEXT, 0, '')

def download_id(file_path, key_word="另存为"):
    """自动化文件另存对话框交互。"""
    # if os.path.exists(file_path):
    #     os.remove(file_path)

    final_hwnd = find_save_dialog(key_word)
    if final_hwnd:
        print('输入框句柄为:', final_hwnd)

        # 清空输入框
        clear_input_box(final_hwnd)

        abs_file_path = os.path.abspath(file_path)
        for char in abs_file_path:
            win32gui.SendMessage(final_hwnd, win32con.WM_IME_CHAR, ord(str(char)), 0)
        time.sleep(1)
        win32gui.PostMessage(final_hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
        is_final_hwnd = find_save_dialog(key_word="确认另存为", text='是(&Y)', times=2)
        if is_final_hwnd:
            win32gui.PostMessage(is_final_hwnd, win32con.WM_KEYDOWN, ord("Y"), 0)
            # time.sleep(0.5)
            # win32gui.PostMessage(final_hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
        # win32gui.PostMessage(final_hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)

# 示例用法
download_id(r'B:\新建文件夹\打印.pdf', key_word="将打印输出另存为")
# download_id(r'B:\新建文件夹\打印.pdf', key_word="确认另存为")

结论:
自动化与GUI元素的交互需要仔细考虑特定应用和所使用的GUI框架。提供的优化脚本作为使用Python中的Win32 API自动化与文件另存对话框交互的起点。开发人员可以根据其具体需求和应用场景进一步定制和扩展脚本。