【开源解析】:Python打造专业级USB安全弹出工具(附完整源码)

🔥 【开源解析】: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 get_removable_drives(self):
    """获取所有可移动驱动器"""
    drives = []
    bitmask = ctypes.windll.kernel32.GetLogicalDrives()
    for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
        if bitmask & 1:
            drive_type = ctypes.windll.kernel32.GetDriveTypeW(f"{
     
     letter}:\\")
            if drive_type == win32con.DRIVE_REMOVABLE:
                drives.append(f"{
     
     letter}:")
        bitmask >>= 1
    return drives

关键技术点:

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

2. 进程扫描引擎

def find_locking_processes(self):
    # 获取进程列表(约150-200个系统进程)
    processes = list(psutil.process_iter(['pid', 'name', 'exe', 'cmdline']))
    
    # 双重检测机制
    for proc in processes:
        # 检测1:打开的文件句柄
        for item in proc.open_files():
            if item.path.lower().startswith(drive_path):
                locking_processes.append(proc.info)
        
        # 检测2:工作目录
        try:
            cwd = proc.cwd()
            if cwd and cwd.lower().startswith(drive_path):
                locking_processes.append(proc.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 WorkerThread(QThread):
    update_progress = pyqtSignal(str, int, int)  # 进度更新信号
    
    def run(self):
        try:
            if self.operation_type == 'find':
                self.find_locking_processes()
            elif self.operation_type == 'unlock_and_eject':
                self.unlock_and_eject_drive()
        except Exception as e:
            self.log_message(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 EjectProgressDialog(QDialog):
    """自定义进度对话框"""
    def __init__(self, parent=None, drive_letter=""):
        super().__init__(parent)
        self.setWindowTitle("安全弹出USB驱动器")
        self.setWindowIcon(QIcon.fromTheme('drive-removable-media'))
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.setFixedSize(300, 120)
        
        layout = QVBoxLayout()
        self.setLayout(layout)
        
        # 标题标签
        self.title_label = QLabel(f"正在安全弹出 {
     
     drive_letter}:...")
        self.title_label.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.title_label)
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setTextVisible(False)
        layout.addWidget(self.progress_bar)
        
        # 状态标签
        self.status_label = QLabel("准备解除占用...")
        self.status_label.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.status_label)
        
        # 取消按钮
        self.cancel_btn = QPushButton("取消")
        self.cancel_btn.clicked.connect(self.reject)
        btn_layout = QHBoxLayout()
        btn_layout.addStretch()
        btn_layout.addWidget(self.cancel_btn)
        btn_layout.addStretch()
        layout.addLayout(btn_layout)
        
        # 设置样式
        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 update_progress(self, text, value, max_value):
        """更新进度显示"""
        self.progress_bar.setMaximum(max_value)
        self.progress_bar.setValue(value)
        self.status_label.setText(text)

class WorkerThread(QThread):
    update_progress = pyqtSignal(str, int, int)
    update_process_text = pyqtSignal(str)
    operation_complete = pyqtSignal()
    show_message = pyqtSignal(str, str, str)  # title, message, icon

    def __init__(self,
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

创客白泽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值