feat:增加Windows桌面图标缓存清理功能

This commit is contained in:
ASLant committed 2025-11-12 09:56:58 +08:00
1 parent 75bf59adeb
commit aada05a1fc
3 files changed
+117 -36

No files matched your search

+80 -35
View File
@@ -7,6 +7,12 @@ use std::path::{Path, PathBuf};
use std::fs;
use encoding_rs::GBK;
#[cfg(target_os = "windows")]
use std::os::windows::process::CommandExt;
#[cfg(target_os = "windows")]
const CREATE_NO_WINDOW: u32 = 0x08000000;
#[derive(Debug, Serialize, Deserialize)]
struct UpxOptions {
mode: String,
@@ -15,6 +21,7 @@ struct UpxOptions {
compression_level: String,
backup: bool,
ultra_brute: bool,
force: bool,
}
#[derive(Debug, Serialize, Deserialize)]
@@ -24,53 +31,42 @@ struct ScanFolderOptions {
}
// 获取UPX可执行文件路径
fn get_upx_path() -> PathBuf {
// 尝试1: 使用打包后的upx (在exe同目录下)
fn get_upx_path() -> Option<PathBuf> {
// 打包后的位置
if let Ok(exe_path) = std::env::current_exe() {
if let Some(exe_dir) = exe_path.parent() {
let bundled_upx = exe_dir.join("upx.exe");
if bundled_upx.exists() {
return bundled_upx;
let upx = exe_dir.join("_up_/upx/upx.exe");
if upx.exists() {
return Some(upx);
}
}
}
// 尝试2: 使用开发环境的upx (src-tauri/../upx/upx.exe)
let dev_upx = PathBuf::from("../../upx/upx.exe");
// 开发环境
let dev_upx = PathBuf::from("../upx/upx.exe");
if dev_upx.exists() {
return dev_upx;
return Some(dev_upx);
}
// 尝试3: 另一个开发环境路径
let dev_upx2 = PathBuf::from("../upx/upx.exe");
if dev_upx2.exists() {
return dev_upx2;
}
// 尝试4: 使用系统PATH中的upx (降级方案)
PathBuf::from("upx")
None
}
#[tauri::command]
async fn process_upx(options: UpxOptions) -> Result<String, String> {
// 获取UPX可执行文件路径
let upx_path = get_upx_path();
let upx_path = get_upx_path().ok_or("未找到 UPX 工具!请确保安装完整")?;
// 检查 UPX 是否可用
let mut upx_check = Command::new(&upx_path);
// 在 Windows 上隐藏控制台窗口
#[cfg(target_os = "windows")]
{
use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x08000000;
upx_check.creation_flags(CREATE_NO_WINDOW);
}
upx_check.creation_flags(CREATE_NO_WINDOW);
let upx_check = upx_check.arg("--version").output();
if upx_check.is_err() {
return Err("未找到 UPX 工具!".to_string());
return Err("UPX 工具无法执行!".to_string());
}
// 检查输入文件是否存在
@@ -101,11 +97,7 @@ async fn process_upx(options: UpxOptions) -> Result<String, String> {
// 在 Windows 上隐藏控制台窗口
#[cfg(target_os = "windows")]
{
use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x08000000;
cmd.creation_flags(CREATE_NO_WINDOW);
}
cmd.creation_flags(CREATE_NO_WINDOW);
// 判断是否覆盖原文件
let is_overwrite = options.input_file == options.output_file;
@@ -122,6 +114,11 @@ async fn process_upx(options: UpxOptions) -> Result<String, String> {
cmd.arg(format!("-{}", options.compression_level));
}
// 添加强制压缩参数
if options.force {
cmd.arg("--force");
}
if is_overwrite {
// 直接覆盖原文件,不使用 -o 参数
cmd.arg(&options.input_file);
@@ -137,6 +134,11 @@ async fn process_upx(options: UpxOptions) -> Result<String, String> {
// 脱壳模式
cmd.arg("-d");
// 添加强制压缩参数(脱壳时也可能需要)
if options.force {
cmd.arg("--force");
}
if is_overwrite {
// 直接覆盖原文件
cmd.arg(&options.input_file);
@@ -267,17 +269,13 @@ fn scan_folder(options: ScanFolderOptions) -> Result<Vec<String>, String> {
// 获取UPX版本
#[tauri::command]
fn get_upx_version() -> Result<String, String> {
let upx_path = get_upx_path();
let upx_path = get_upx_path().ok_or("未找到 UPX 工具!")?;
let mut cmd = Command::new(&upx_path);
// 在 Windows 上隐藏控制台窗口
#[cfg(target_os = "windows")]
{
use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x08000000;
cmd.creation_flags(CREATE_NO_WINDOW);
}
cmd.creation_flags(CREATE_NO_WINDOW);
match cmd.arg("--version").output() {
Ok(output) => {
@@ -293,11 +291,58 @@ fn get_upx_version() -> Result<String, String> {
}
}
// 刷新图标缓存
#[tauri::command]
#[allow(dead_code)]
async fn refresh_icon_cache() -> Result<(), String> {
// 后台执行刷新
tokio::task::spawn_blocking(move || {
#[cfg(target_os = "windows")]
{
// 1. 关闭 Explorer
let _ = Command::new("taskkill")
.args(&["/f", "/im", "explorer.exe"])
.creation_flags(CREATE_NO_WINDOW)
.output();
std::thread::sleep(std::time::Duration::from_millis(500));
// 2. 删除图标缓存
if let Ok(userprofile) = std::env::var("USERPROFILE") {
let cache_db = format!("{}\\AppData\\Local\\IconCache.db", userprofile);
let _ = fs::remove_file(&cache_db);
// 删除缩略图缓存
let explorer_path = format!("{}\\AppData\\Local\\Microsoft\\Windows\\Explorer", userprofile);
if let Ok(entries) = fs::read_dir(&explorer_path) {
for entry in entries.flatten() {
let path = entry.path();
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
if name.starts_with("thumbcache_") {
let _ = fs::remove_file(&path);
}
}
}
}
}
std::thread::sleep(std::time::Duration::from_millis(500));
// 3. 重启 Explorer
let _ = Command::new("explorer.exe")
.creation_flags(CREATE_NO_WINDOW)
.spawn();
}
});
Ok(())
}
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_dialog::init())
.invoke_handler(tauri::generate_handler![process_upx, scan_folder, get_upx_version])
.invoke_handler(tauri::generate_handler![process_upx, scan_folder, get_upx_version, refresh_icon_cache])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
+13
View File
@@ -16,6 +16,11 @@
<span id="upx-version" class="text-gray-400 text-xs select-none"></span>
</div>
<div class="flex items-center space-x-1">
<button id="refresh-icon-btn" class="w-9 h-9 hover:bg-gray-100 flex items-center justify-center transition-all duration-200" style="border-radius: 0.3rem;" title="刷新图标缓存">
<svg class="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
</button>
<button id="settings-btn" class="w-9 h-9 hover:bg-gray-100 flex items-center justify-center transition-all duration-200" style="border-radius: 0.3rem;" title="设置">
<svg class="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
@@ -138,6 +143,14 @@
<p class="text-xs text-gray-500 mt-0.5">处理文件夹时,递归处理所有子目录</p>
</div>
</label>
<label class="flex items-start space-x-3 cursor-pointer p-2.5 hover:bg-gray-50 transition-colors" style="border-radius: 0.3rem;">
<input type="checkbox" id="force-compress" class="w-4 h-4 mt-0.5 text-blue-600 border-gray-300 rounded focus:ring-2 focus:ring-blue-500 cursor-pointer">
<div class="flex-1">
<span class="text-sm font-medium text-gray-800">强制压缩</span>
<p class="text-xs text-gray-500 mt-0.5">强制处理受保护的文件(如 GUARD_CF),可能移除安全特性</p>
</div>
</label>
</div>
</div>
+24 -1
View File
@@ -13,10 +13,12 @@ const overwriteCheckbox = document.getElementById('overwrite');
const backupCheckbox = document.getElementById('backup');
const ultraBruteCheckbox = document.getElementById('ultra-brute');
const includeSubfoldersCheckbox = document.getElementById('include-subfolders');
const forceCompressCheckbox = document.getElementById('force-compress');
const logOutput = document.getElementById('log-output');
const settingsModal = document.getElementById('settings-modal');
const settingsBtn = document.getElementById('settings-btn');
const closeSettingsBtn = document.getElementById('close-settings');
const refreshIconBtn = document.getElementById('refresh-icon-btn');
// 窗口控制按钮
const minimizeBtn = document.getElementById('titlebar-minimize');
@@ -84,6 +86,11 @@ function initWindowControls() {
// 操作按钮初始化
function initOperationButtons() {
// 刷新图标缓存按钮
refreshIconBtn.addEventListener('click', async () => {
await handleRefreshIcon();
});
// 设置按钮 - 显示全局设置
settingsBtn.addEventListener('click', () => {
showSettingsModal();
@@ -496,12 +503,17 @@ async function processUpx(mode, inputFile, outputFile) {
output_file: outputFile,
compression_level: getCompressionLevel(),
backup: backupCheckbox.checked,
ultra_brute: ultraBruteCheckbox.checked
ultra_brute: ultraBruteCheckbox.checked,
force: forceCompressCheckbox.checked
};
if (ultraBruteCheckbox.checked) {
addLog('已启用极限压缩模式', 'info');
}
if (forceCompressCheckbox.checked) {
addLog('已启用强制压缩模式', 'warning');
}
addLog(`开始${mode === 'compress' ? '加壳压缩' : '脱壳解压'}...`, 'info');
@@ -515,6 +527,17 @@ async function processUpx(mode, inputFile, outputFile) {
}
}
// 刷新图标缓存
async function handleRefreshIcon() {
try {
addLog('正在刷新图标缓存...', 'info');
await invoke('refresh_icon_cache');
addLog('图标缓存刷新完成', 'success');
} catch (error) {
addLog(`刷新失败: ${error}`, 'error');
}
}
// 添加日志
function addLog(message, type = 'info', highlight = false) {
const logLine = document.createElement('div');