U盘格式化弹窗提示代码问题求助:访问冲突与主线程错误
U盘格式化代码问题修复方案
核心问题分析与修复思路
1. Access Violation (0x0000005) 错误
- 根源:
FormatEx的回调函数被Python垃圾回收机制释放,导致系统调用时访问非法内存。WINFUNCTYPE创建的回调对象如果没有被长期引用,会被GC回收。 - 修复:将回调对象保存为类的实例变量,确保在格式化过程中始终存在。
2. "main thread is not in main loop" 错误
- 根源:同时混用PyQt和Tkinter两个独立GUI框架,两者的主循环机制冲突;且Tkinter要求所有组件操作必须在主线程,代码线程上下文混乱。
- 修复:统一使用PyQt实现所有弹窗和进度提示界面,所有GUI操作严格限制在主线程执行。
3. done_format标记线程不安全
- 根源:布尔值标记在多线程场景下存在竞态条件,类变量与实例变量混用导致逻辑混乱。
- 修复:使用
QThread+信号机制替代原始线程,用信号传递格式化完成状态,避免线程安全问题。
修复后的完整代码
from PyQt5.QtWidgets import (QMessageBox, QApplication, QWidget, QLabel, QVBoxLayout, QProgressBar) from PyQt5.QtCore import QThread, pyqtSignal, Qt import sys from ctypes import * import win32file REMOVABLE = 2 class FormatWorker(QThread): format_finished = pyqtSignal() error_occurred = pyqtSignal(str) def __init__(self, drive, fmt_type, title, parent=None): super().__init__(parent) self.drive = drive self.fmt_type = fmt_type self.title = title self.callback_obj = None def format_callback(self, command, modifier, arg): self.format_finished.emit() return True def run(self): try: fm = windll.LoadLibrary('fmifs.dll') FMT_CB_FUNC = WINFUNCTYPE(c_int, c_int, c_int, c_void_p) FMIFS_UNKNOWN = 0 # 保存回调对象引用,防止被GC回收 self.callback_obj = FMT_CB_FUNC(self.format_callback) # 执行格式化 fm.FormatEx(c_wchar_p(self.drive), FMIFS_UNKNOWN, c_wchar_p(self.fmt_type), c_wchar_p(self.title), True, c_int(0), self.callback_obj) except Exception as e: self.error_occurred.emit(str(e)) class FormatWindow(QWidget): def __init__(self, drive, parent=None): super().__init__(parent) self.drive = drive self.retval = 0 self.init_ui() def init_ui(self): self.setWindowTitle(f"格式化驱动器 {self.drive}") self.setFixedSize(500, 200) self.center_window() layout = QVBoxLayout() layout.setAlignment(Qt.AlignCenter) # 设置字体 self.label = QLabel(f"正在格式化驱动器 {self.drive}...") font = self.label.font() font.setFamily('Arial') font.setPointSize(14) self.label.setFont(font) self.label.setAlignment(Qt.AlignCenter) layout.addWidget(self.label) self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 0) # 无限进度条 layout.addWidget(self.progress_bar) self.setLayout(layout) def center_window(self): qr = self.frameGeometry() cp = QApplication.desktop().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def check_removable_drive(self): drive_type = win32file.GetDriveType(self.drive + ':') if drive_type != REMOVABLE: QMessageBox.critical(self, "错误", "这不是可移动U盘") self.retval = -3 return False return True def show_confirm_dialog(self): reply = QMessageBox.question(self, "确认格式化", f"即将格式化驱动器 {self.drive}\n确定继续吗?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply != QMessageBox.Yes: self.retval = -2 return False return True def start_format(self, fmt_type, title): if not self.check_removable_drive(): self.close() return if not self.show_confirm_dialog(): self.close() return self.worker = FormatWorker(self.drive, fmt_type, title) self.worker.format_finished.connect(self.on_format_finished) self.worker.error_occurred.connect(self.on_error) self.worker.start() def on_format_finished(self): QMessageBox.information(self, "完成", "格式化已完成") self.retval = 0 self.close() def on_error(self, error_msg): QMessageBox.critical(self, "错误", f"格式化失败:{error_msg}") self.retval = -1 self.close() if __name__ == "__main__": app = QApplication(sys.argv) Drive = 'E:\\' Fmat = 'FAT32' Title = '格式化U盘' window = FormatWindow(Drive[0]) window.show() window.start_format(Fmat, Title) sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者ssbg
相关产品推荐
相关产品推荐

