Python实现专业级USB安全弹出工具(附完整源码)

1周前发布 gsjqwyl
9 0 0

🚀 用Python打造专业级USB安全弹出工具(含完整源码)

此处插入图片描述
请添加图片描述

🌟 个人主页:创客白泽 – CSDN博客
🔥
系列专栏:🐍《Python开源项目实战》
💡 热爱不仅限于代码,热情源于每一个灵感迸发的夜晚。愿以开源之光,照亮前行之途。
🐋 期待大家多多支持,一同进步!
👍 🎉若文章对你有帮助,欢迎 点赞 👍🏻 评论 💬 收藏 ⭐️ 加关注+💗分享给更多人哦

请添加图片描述
在这里插入图片描述

📌 为何需要专业USB弹出工具?

日常使用电脑时,常遭遇“该设备正在被使用,无法安全移除”的困扰。传统解决方式要么是暴力拔插(可能损坏数据),要么是反复尝试弹出(效率低下)。本文将介绍如何利用Python开发一款专业级USB安全弹出工具,它能够:

  1. 智能检测 占用USB设备的进程
  2. 自动终止 顽固进程
  3. 深度解锁 驱动器
  4. 安全弹出 硬件设备
  5. 系统托盘 快捷操作

相较Windows自带的弹出功能,我们的工具具备进程可视化、强制解锁、操作日志等高级特性,是IT技术人员与普通用户的实用利器。

🛠️ 功能概览

功能模块 实现技术 特色亮点
驱动器检测 ctypes.windll.kernel32 实时刷新可移动设备列表
进程扫描 psutil 全面扫描与精准定位
进程终止 win32process 处理权限提升
卷解锁 win32file IOCTL控制 底层磁盘操作
设备弹出 IOCTL_STORAGE_EJECT_MEDIA 硬件级控制
GUI界面 PyQt5 专业交互体验
系统托盘 QSystemTrayIcon 后台常驻与快捷操作

🎨 效果展示

主界面截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

进程检测效果

[14:25:33] 🔍 正在获取进程列表...
[14:25:34] 📊 找到 156 个进程,正在扫描...
[14:25:37] ⚠️ 找到 2 个锁定进程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[14:25:37] 🆔 PID: 1234
[14:25:37] 📛 名称: explorer.exe
[14:25:37] 📂 路径: C:\Windows\explorer.exe
[14:25:37] 💻 命令: explorer /select,D:\test.docx
[14:25:37] 👤 用户: DESKTOP-Admin
[14:25:37] 📊 状态: running
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

系统托盘菜单

在这里插入图片描述

🧰 开发环境准备

必备组件

pip install pywin32 psutil PyQt5 ctypes

特别说明

本程序需管理员权限运行,原因在于:

  • 进程终止操作
  • 底层磁盘控制
  • 硬件设备管理

🏗️ 核心代码解析

1. 驱动器检测机制

def 获取可移动驱动器(self):
    """获取所有可移动的驱动器"""
    驱动器列表 = []
    位掩码 = ctypes.windll.kernel32.GetLogicalDrives()
    for 字母 in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
        if 位掩码 & 1:
            驱动器类型 = ctypes.windll.kernel32.GetDriveTypeW(f"{字母}:\\")
            if 驱动器类型 == win32con.DRIVE_REMOVABLE:
                驱动器列表.append(f"{字母}:")
        位掩码 >>= 1
    return 驱动器列表

关键技术点:

  • GetLogicalDrives()获取所有逻辑驱动器位掩码
  • GetDriveTypeW()判断驱动器类型
  • 位运算遍历26个字母驱动器

2. 进程扫描引擎

def 查找锁定进程(self):
    # 获取进程列表(约150-200个系统进程)
    进程列表 = list(psutil.process_iter(['pid', 'name', 'exe', 'cmdline']))

    # 双重检测机制
    for 进程 in 进程列表:
        # 检测1:打开的文件句柄
        for 项目 in 进程.open_files():
            if 项目.path.lower().startswith(驱动器路径):
                锁定进程列表.append(进程.info)

            # 检测2:工作目录
            try:
                当前工作目录 = 进程.cwd()
                if 当前工作目录 and 当前工作目录.lower().startswith(驱动器路径):
                    锁定进程列表.append(进程.info)

3. 底层解锁三连击

# 1. 锁定卷(禁止写入)
win32file.DeviceIoControl(
    h_volume,
    FSCTL_LOCK_VOLUME,  # 控制码0x00090018
    None, None, None
)

# 2. 卸载文件系统
win32file.DeviceIoControl(
    h_volume,
    FSCTL_DISMOUNT_VOLUME,  # 控制码0x00090020
    None, None, None
)

# 3. 物理弹出
win32file.DeviceIoControl(
    h_volume,
    IOCTL_STORAGE_EJECT_MEDIA,  # 控制码0x2D4808
    None, None, None
)

4. PyQt5多线程处理

class 工作线程(QThread):
    更新进度 = pyqtSignal(str, int, int)  # 进度更新信号

    def 运行(self):
        try:
            if self.操作类型 == '查找':
                self.查找锁定进程()
            elif self.操作类型 == '解锁并弹出':
                self.解锁并弹出驱动器()
        except Exception as e:
            self.记录日志(f"线程错误: {str(e)}")

🚀 使用教程

基本操作流程

  1. 启动程序(自动获取管理员权限)
  2. 从列表选择目标USB驱动器
  3. 点击“查找占用进程”分析问题
  4. 点击“解除占用并弹出”安全移除

高级技巧

  • 托盘快捷操作 :右键系统图标直接选择驱动器
  • 自动刷新 :每5秒自动更新驱动器列表
  • 日志分析 :查看完整的操作记录和错误信息

💾 完整源码下载

完整项目源码:

import ctypes
import sys
import win32api
import win32file
import win32con
import win32process
import psutil
import threading
from datetime import datetime
from time import sleep
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QListWidget, QPushButton, QLabel, QProgressBar, QTextEdit,
                             QSystemTrayIcon, QMenu, QMessageBox, QStyle, QFrame, QAction,
                             QDialog, QVBoxLayout, QHBoxLayout)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt5.QtGui import QIcon, QFont, QPalette, QColor

# Define constants
try:
    from winioctlcon import FSCTL_LOCK_VOLUME, FSCTL_DISMOUNT_VOLUME, IOCTL_STORAGE_EJECT_MEDIA
except ImportError:
    FSCTL_LOCK_VOLUME = 0x00090018
    FSCTL_DISMOUNT_VOLUME = 0x00090020
    IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808

class 弹出进度对话框(QDialog):
    """自定义进度对话框"""
    def __init__(self, 父窗口=None, 驱动器字母=""):
        super().__init__(父窗口)
        self.setWindowTitle("安全弹出USB驱动器")
        self.setWindowIcon(QIcon.fromTheme('drive-removable-media'))
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.setFixedSize(300, 120)

        布局 = QVBoxLayout()
        self.setLayout(布局)

        # 标题标签
        self.标题标签 = QLabel(f"正在安全弹出 {驱动器字母}:...")
        self.标题标签.setAlignment(Qt.AlignCenter)
        布局.addWidget(self.标题标签)

        # 进度条
        self.进度条 = QProgressBar()
        self.进度条.setRange(0, 100)
        self.进度条.setTextVisible(False)
        布局.addWidget(self.进度条)

        # 状态标签
        self.状态标签 = QLabel("准备解除占用...")
        self.状态标签.setAlignment(Qt.AlignCenter)
        布局.addWidget(self.状态标签)

        # 取消按钮
        self.取消按钮 = QPushButton("取消")
        self.取消按钮.clicked.connect(self.拒绝)
        按钮布局 = QHBoxLayout()
        按钮布局.addStretch()
        按钮布局.addWidget(self.取消按钮)
        按钮布局.addStretch()
        布局.addLayout(按钮布局)

        # 设置样式
        self.setStyleSheet("""
            QDialog {
                background-color: #f5f5f5;
            }
            QLabel {
                font-size: 12px;
            }
            QProgressBar {
                border: 1px solid #ccc;
                border-radius: 3px;
                text-align: center;
                height: 12px;
            }
            QProgressBar::chunk {
                background-color: #4CAF50;
                width: 10px;
            }
        """)

    def 更新进度(self, 文本, 值, 最大值):
        """更新进度显示"""
        self.进度条.setMaximum(最大值)
        self.进度条.setValue(值)
        self.状态标签.setText(文本)

class 工作线程(QThread):
    更新进度 = pyqtSignal(str, int, int)
    更新进程文本 = pyqtSignal(str)
    操作完成 = pyqtSignal()
    显示消息 = pyqtSignal(str, str, str)  # title, message, icon

    def __init__(self, 驱
© 版权声明

相关文章

暂无评论

暂无评论...