#启动exe 文件 import os import subprocess import shutil import time import uiautomation as auto import win32api import win32con from utils.config import cfg # exe_path = cfg('exe.small_exe', None) # if exe_path is None: # print(f"错误:exe_path 未配置") # exit(1) def start_exe(data): exe_path = None if "small" in data: exe_path = cfg('exe.small_exe', None) elif "big" in data: exe_path = cfg('exe.big_exe', None) else: print(f"错误:机型类型未配置") exit(1) try: # 检查文件是否存在 if not os.path.exists(exe_path): print(f"错误:切片软件路径文件不存在 - {exe_path}") return False # 检查是否是文件(不是目录) if not os.path.isfile(exe_path): print(f"错误:路径不是文件 - {exe_path}") return False # 获取 exe 文件所在的目录(工作目录) exe_dir = os.path.dirname(exe_path) print(f"工作目录设置为: {exe_dir}") # 检查工作目录是否存在 if not os.path.exists(exe_dir): print(f"错误:工作目录不存在 - {exe_dir}") return False #清空data文件夹下的所有文件 data_dir = os.path.join(exe_dir, 'data') if os.path.exists(data_dir): # 删除该目录 shutil.rmtree(data_dir) if not os.path.exists(data_dir): os.makedirs(data_dir) # 使用 win32api.ShellExecute 完全模拟双击启动 # ShellExecute 是 Windows 系统双击文件时调用的 API,行为最接近真实双击 try: # 先切换到工作目录(ShellExecute 会使用当前工作目录) original_cwd = os.getcwd() os.chdir(exe_dir) # ShellExecute(hwnd, operation, file, parameters, directory, showCmd) # operation: "open" 表示打开文件(模拟双击) # showCmd: SW_SHOWNORMAL (1) 表示正常显示窗口 result = win32api.ShellExecute( 0, # hwnd: 父窗口句柄,0 表示桌面 "open", # operation: 打开文件 exe_path, # file: 要执行的文件路径 "", # parameters: 命令行参数(空字符串表示无参数) exe_dir, # directory: 工作目录 win32con.SW_SHOWNORMAL # showCmd: 正常显示窗口 ) # 恢复原目录 os.chdir(original_cwd) # ShellExecute 返回值 > 32 表示成功 if result > 32: print(f"✓ 成功启动程序(模拟双击): {exe_path}") print(f" 工作目录: {exe_dir}") print(f" 返回值: {result}") return True else: print(f"✗ ShellExecute 启动失败,返回值: {result}") # 如果 ShellExecute 失败,尝试备用方案 raise Exception(f"ShellExecute 返回错误代码: {result}") except Exception as e: print(f"ShellExecute 启动失败: {e}") # 备用方案1:使用 os.startfile(也使用 ShellExecute,但无法设置工作目录) try: original_cwd = os.getcwd() os.chdir(exe_dir) os.startfile(exe_path) os.chdir(original_cwd) print(f"✓ 使用 os.startfile 成功启动程序: {exe_path}") return True except Exception as e2: print(f"os.startfile 启动也失败: {e2}") # 备用方案2:使用 subprocess(最后手段) try: process = subprocess.Popen( [exe_path], cwd=exe_dir, creationflags=subprocess.CREATE_NEW_CONSOLE ) print(f"✓ 使用 subprocess 成功启动程序: {exe_path}") print(f" 进程ID: {process.pid}") return True except Exception as e3: print(f"subprocess 启动也失败: {e3}") return False except Exception as e: print(f"启动程序时发生异常: {e}") import traceback traceback.print_exc() return False def click_confirm(): """ 触发点击 ESC 键,用于关闭弹框 """ try: # 发送 ESC 键到当前活动窗口 auto.SendKeys('{ESC}') print("✓ 已发送 ESC 键") time.sleep(0.3) return True except Exception as e: print(f"发送 ESC 键失败: {e}") return False def close(): """ 关闭打开的应用程序 通过查找窗口名称并关闭窗口,使用多种方法确保成功 """ try: import win32gui import win32con import win32api import win32process # 应用程序的窗口名称 window_name = cfg('exe.soft_name', None) if window_name is None: print(f"错误:切片软件名称未配置") exit(1) print(f"正在查找窗口: {window_name}") # 方法1: 使用 win32gui 查找窗口(更可靠) hwnd = win32gui.FindWindow(None, window_name) if hwnd: print(f"✓ 找到窗口句柄: {hwnd}") # 激活窗口 win32gui.SetForegroundWindow(hwnd) win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) # 确保窗口不是最小化 time.sleep(0.3) # 方法1: 使用 SendMessage 发送 WM_CLOSE(比 PostMessage 更强制) try: win32gui.SendMessage(hwnd, win32con.WM_CLOSE, 0, 0) print("✓ 使用 SendMessage(WM_CLOSE) 关闭窗口") time.sleep(1) # 检查窗口是否还存在 if not win32gui.IsWindow(hwnd): print("✓ 窗口已成功关闭") return True except Exception as e: print(f"SendMessage(WM_CLOSE) 失败: {e}") # 方法2: 使用 win32api 发送 Alt+F4 按键事件(更可靠) try: win32gui.SetForegroundWindow(hwnd) time.sleep(0.2) # 按下 Alt win32api.keybd_event(win32con.VK_MENU, 0, 0, 0) time.sleep(0.05) # 按下 F4 win32api.keybd_event(win32con.VK_F4, 0, 0, 0) time.sleep(0.05) # 释放 F4 win32api.keybd_event(win32con.VK_F4, 0, win32con.KEYEVENTF_KEYUP, 0) time.sleep(0.05) # 释放 Alt win32api.keybd_event(win32con.VK_MENU, 0, win32con.KEYEVENTF_KEYUP, 0) print("✓ 使用 win32api 发送 Alt+F4") time.sleep(1) # 检查窗口是否还存在 if not win32gui.IsWindow(hwnd): print("✓ 窗口已成功关闭") return True except Exception as e: print(f"win32api Alt+F4 失败: {e}") # 方法3: 尝试使用 uiautomation 的 Close() try: window = auto.WindowControl(searchDepth=1, Name=window_name) if window.Exists(0, 0): window.SetFocus() time.sleep(0.2) window.Close() print("✓ 使用 uiautomation Close() 关闭窗口") time.sleep(1) if not win32gui.IsWindow(hwnd): print("✓ 窗口已成功关闭") return True except Exception as e: print(f"uiautomation Close() 失败: {e}") # 方法4: 如果以上都失败,尝试终止进程(最后手段) print("尝试通过进程ID终止程序...") try: import psutil # 通过窗口句柄获取进程ID _, pid = win32process.GetWindowThreadProcessId(hwnd) process = psutil.Process(pid) process.terminate() print(f"✓ 已终止进程 (PID: {pid})") time.sleep(0.5) return True except ImportError: print("psutil 未安装,无法使用进程终止方式") except Exception as e: print(f"终止进程失败: {e}") print("✗ 所有关闭方法都失败了") return False else: # 如果 win32gui 找不到,尝试使用 uiautomation print("win32gui 未找到窗口,尝试使用 uiautomation...") window = auto.WindowControl(searchDepth=1, Name=window_name) if window.Exists(0, 0): print(f"✓ 使用 uiautomation 找到窗口") window.SetFocus() time.sleep(0.2) hwnd = window.Handle win32gui.SendMessage(hwnd, win32con.WM_CLOSE, 0, 0) print("✓ 使用 SendMessage(WM_CLOSE) 关闭窗口") time.sleep(1) return True else: print(f"✗ 未找到窗口: {window_name}") return False except Exception as e: print(f"关闭应用程序时发生异常: {e}") import traceback traceback.print_exc() return False #if __name__ == "__main__": # start_exe() # #启动成功之后,有一个弹框 的窗口,点击确定 # time.sleep(5) # click_confirm() # time.sleep(10) # close()