You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 02:27:05