From a666ed7c4344c9aa1af3e7d5c15942711fd2cd54 Mon Sep 17 00:00:00 2001 From: hulk Date: Fri, 18 Sep 2026 01:13:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(DLPilot):=20=E5=8D=95=E5=AE=9E=E4=BE=8B?= =?UTF-8?q?=E9=94=81=20+=20=E4=B8=B2=E5=8F=A3=E5=8D=A0=E7=94=A8=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=20=E2=80=94=E2=80=94=20=E4=BF=AE=E5=A4=8D'=E6=96=AD?= =?UTF-8?q?=E4=B8=8D=E5=BC=80'=E7=9A=84=E5=AE=9E=E9=99=85=E6=A0=B9?= =?UTF-8?q?=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DLPilot/src/app_gui.py | 20 ++++++++++++++++++++ DLPilot/src/dlpc_rs485.py | 6 +++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/DLPilot/src/app_gui.py b/DLPilot/src/app_gui.py index 49b8980..3bfa930 100644 --- a/DLPilot/src/app_gui.py +++ b/DLPilot/src/app_gui.py @@ -63,10 +63,30 @@ def _apply_dropdown_theme(): ctk.ThemeManager.theme['DropdownMenu']['text_color'] = ('#1A1A1A', '#DADADA') +def _ensure_single_instance(): + """单实例锁(Windows 命名互斥体): 已有实例在运行时返回 False。 + + 双击 exe 开多个实例时, 只有先启动的能连串口, 后续实例连接报"拒绝访问", + 且用户往往只看到后开的窗口 —— 表现为"连不上/断不开"。互斥体句柄随 + 进程存活, 进程退出自动释放。""" + ERROR_ALREADY_EXISTS = 183 + ctypes.windll.kernel32.CreateMutexW(None, False, 'hulk.DLPilot.single') + return ctypes.windll.kernel32.GetLastError() != ERROR_ALREADY_EXISTS + + def run_gui(auto_close=0): """入口: 配置外观并启动主窗口""" ctk.set_appearance_mode('System') _apply_dropdown_theme() + if not _ensure_single_instance(): + from tkinter import messagebox + import tkinter as tk + r = tk.Tk() + r.withdraw() + messagebox.showinfo('DLPilot 已在运行', + '检测到另一个 DLPilot 实例正在运行。\n' + '请使用已打开的窗口(串口同时只能被一个实例占用)。') + return App(auto_close).mainloop() diff --git a/DLPilot/src/dlpc_rs485.py b/DLPilot/src/dlpc_rs485.py index 72fe4d1..437e38f 100644 --- a/DLPilot/src/dlpc_rs485.py +++ b/DLPilot/src/dlpc_rs485.py @@ -301,7 +301,11 @@ class DLPC485: self.ser = None with self._lock: self._target = None - self.on_status(f'连接失败: {e}') + et = str(e) + if 'PermissionError' in repr(e) or '拒绝访问' in et \ + or 'Access is denied' in et: + et += '(串口被占用: 检查串口助手/另一个本工具实例)' + self.on_status(f'连接失败: {et}') if self.ser is not None: try: item = None