Compare commits

...

6 Commits
1.5.0 ... main

Author SHA1 Message Date
unknown
5800cbbdaa 更新版本。 2025-03-18 08:36:36 +08:00
unknown
56517f059c 优化拖拽文件速度。 2025-03-16 17:58:44 +08:00
unknown
342d8939ab 优化。 2025-03-16 17:49:04 +08:00
unknown
92270def83 优化主界面搜索框,隐藏窗口时同时隐藏搜索框。 2025-03-16 17:41:46 +08:00
unknown
881fbc9f56 修复'文件夹项目'带有特殊符号时,打开文件夹失败的问题。 2025-03-16 17:40:05 +08:00
unknown
2cd721263e 修复'任务栏'右键关闭窗口时,程序并没有完全退出的问题。 2025-03-16 17:39:09 +08:00
8 changed files with 118 additions and 202 deletions

View File

@ -1,6 +1,6 @@
import { BrowserWindow, shell, app } from "electron";
import { join } from "node:path";
import { parsePath, getURLParams } from "../../commons/utils";
import { extname, join } from "node:path";
import { parsePath, getURLParams, getFileIcon } from "../../commons/utils";
import { Item } from "../../../types/item";
import {
batchAdd,
@ -15,8 +15,10 @@ import { writeFile, statSync, readFileSync, accessSync } from "node:fs";
import mime from "mime";
import {
deleteExtname,
getFileName,
getItemName,
isAbsolutePath,
newItem,
} from "../../../commons/utils/common";
import { iconExts } from "../../commons/utils";
import { addAssociateFolderWatcher } from "../classification";
@ -29,6 +31,7 @@ import {
showSaveDialogSync,
} from "../commons/index";
import { fork } from "../../commons/utilityProcessUtils";
import { ShortcutInfo } from "../../../types/common";
// 窗口
let itemAddEditWindow: BrowserWindow | null = null;
@ -260,24 +263,17 @@ function move(idList: Array<number>, toClassificationId: number) {
* @param classificationId
* @param pathList
*/
function drop(classificationId: number, pathList: Array<string>) {
fork(
"getDropItemInfo",
{
classificationId,
pathList,
},
(resultList: Array<Item>) => {
// 添加项目
let itemList = batchAdd(classificationId, resultList);
// 发送消息到页面
sendToWebContent("mainWindow", "onAddItem", {
itemList,
clear: false,
classificationId: null,
});
}
);
async function drop(classificationId: number, pathList: Array<string>) {
// 获取项目信息
let resultList = await getDropItemInfo(classificationId, pathList);
// 添加项目
let itemList = batchAdd(classificationId, resultList);
// 发送消息到页面
sendToWebContent("mainWindow", "onAddItem", {
itemList,
clear: false,
classificationId: null,
});
}
/**
@ -708,6 +704,90 @@ function deleteQuickSearchHistory(itemId: number) {
}
}
/**
*
* @param classificationId
* @param pathList
*/
async function getDropItemInfo(
classificationId: number,
pathList: Array<string>
) {
// 项目列表
let itemList: Array<Item> = [];
// 解析文件信息并添加项目
for (const path of pathList) {
try {
// item
let item = newItem({ classificationId });
// 目标
item.data.target = path;
// 名称
item.name = getFileName(item.data.target);
// 判断是否是快捷方式,如果是的话,需要获取真实路径
if (mime.getType(path) === "application/x-ms-shortcut") {
// 快捷方式
// 获取真实文件路径和参数
let shortcutInfo: ShortcutInfo | null =
global.addon.getShortcutFileInfo(path);
if (shortcutInfo) {
// 路径
if (shortcutInfo.target) {
item.data.target = shortcutInfo.target;
}
// 参数
if (shortcutInfo.arguments) {
item.data.params = shortcutInfo.arguments;
}
}
}
// 获取图标
item.data.icon = await getFileIcon(item.data.target);
// 获取后缀判断是否是url
let ext = extname(item.data.target);
if (ext && ext.toLowerCase() === ".url") {
// url
let url = parseUrlFileContent(readFileSync(item.data.target, "utf-8"));
if (url && url.trim() !== "") {
item.data.target = url;
item.type = 2;
} else {
continue;
}
} else {
// 文件类型
let stats = statSync(item.data.target);
item.type = stats.isFile() ? 0 : 1;
}
// 去掉后缀
if (item.type === 0 || item.type === 2) {
item.name = deleteExtname(item.name);
}
// push
itemList.push(item);
} catch (e) {}
}
return itemList;
}
/**
* .url文件内容以获取URL
* @param content
* @returns
*/
function parseUrlFileContent(content: string) {
if (content) {
const lines = content.split("\n");
for (const line of lines) {
if (line.startsWith("URL=")) {
const url = line.substring(4).trim();
return url;
}
}
}
return null;
}
export {
createAddEditWindow,
createNetworkIconWindow,

View File

@ -203,8 +203,7 @@ export default function () {
// "打开"菜单
let openMenu = false;
if (
(item.type === 0 &&
global.addon.hasRunas(parsePath(item.data.target))) ||
item.type === 0 ||
item.type === 4 ||
(item.type === 3 && item.data.target === "cmd.exe")
) {

View File

@ -25,8 +25,6 @@ let mainWindow: BrowserWindow | null = null;
*
*/
function createMainWindow() {
// 预热
global.addon.hasRunas(process.execPath);
// 如果窗口存在先关闭窗口
if (mainWindow && !mainWindow.isDestroyed() && mainWindow.isVisible()) {
mainWindow.close();
@ -183,6 +181,10 @@ function createMainWindow() {
sendToWebContent("mainWindow", "onCollapseSubClassification", {});
}
});
// 主窗口关闭事件
mainWindow.on("closed", () => {
app.quit();
});
// 创建鼠标hook
let mousedownClassName = null;
addon.createMouseHook((...args: any[]) => {

View File

@ -5,7 +5,7 @@ import {
newItem,
} from "../../commons/utils/common";
import { CommonItem, Item } from "../../types/item";
import { parse, join, extname } from "node:path";
import { parse, join } from "node:path";
import { readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
import xml2js from "xml2js";
import { newCommonItem, newCommonItemData } from "../../commons/utils/common";
@ -43,11 +43,6 @@ process.parentPort.once("message", async (event) => {
res = await getStartMenuItemList(dataParam);
} else if (params.name === "getAppxItemList") {
res = await getAppxItemList();
} else if (params.name === "getDropItemInfo") {
res = await getDropItemInfo(
dataParam.classificationId,
dataParam.pathList
);
} else if (params.name === "refreshItemIcon") {
res = await refreshItemIcon(dataParam);
} else if (params.name === "getDirectoryItemList") {
@ -558,90 +553,6 @@ function getPropertiesIcon(installLocation: string, result: any) {
return null;
}
/**
*
* @param classificationId
* @param pathList
*/
async function getDropItemInfo(
classificationId: number,
pathList: Array<string>
) {
// 项目列表
let itemList: Array<Item> = [];
// 解析文件信息并添加项目
for (const path of pathList) {
try {
// item
let item = newItem({ classificationId });
// 目标
item.data.target = path;
// 名称
item.name = getFileName(item.data.target);
// 判断是否是快捷方式,如果是的话,需要获取真实路径
if (mime.getType(path) === "application/x-ms-shortcut") {
// 快捷方式
// 获取真实文件路径和参数
let shortcutInfo: ShortcutInfo | null =
global.addon.getShortcutFileInfo(path);
if (shortcutInfo) {
// 路径
if (shortcutInfo.target) {
item.data.target = shortcutInfo.target;
}
// 参数
if (shortcutInfo.arguments) {
item.data.params = shortcutInfo.arguments;
}
}
}
// 获取图标
item.data.icon = await getFileIcon(item.data.target);
// 获取后缀判断是否是url
let ext = extname(item.data.target);
if (ext && ext.toLowerCase() === ".url") {
// url
let url = parseUrlFileContent(readFileSync(item.data.target, "utf-8"));
if (url && url.trim() !== "") {
item.data.target = url;
item.type = 2;
} else {
continue;
}
} else {
// 文件类型
let stats = statSync(item.data.target);
item.type = stats.isFile() ? 0 : 1;
}
// 去掉后缀
if (item.type === 0 || item.type === 2) {
item.name = deleteExtname(item.name);
}
// push
itemList.push(item);
} catch (e) {}
}
return itemList;
}
/**
* .url文件内容以获取URL
* @param content
* @returns
*/
function parseUrlFileContent(content: string) {
if (content) {
const lines = content.split("\n");
for (const line of lines) {
if (line.startsWith("URL=")) {
const url = line.substring(4).trim();
return url;
}
}
}
return null;
}
/**
*
* @param itemList

View File

@ -1,7 +1,7 @@
{
"name": "dawn-launcher",
"productName": "Dawn Launcher",
"version": "1.5.0",
"version": "1.5.1",
"main": "dist-electron/main/index.js",
"description": "Windows 快捷启动工具,帮助您整理杂乱无章的桌面,分门别类管理您的桌面快捷方式,让您的桌面保持干净整洁。",
"author": "FanChenIO",

View File

@ -201,12 +201,3 @@ fn shell_execute(operation: String, file: String, params: String, start_location
fn system_item_execute(target: String, params: Option<String>) {
windows::system_item_execute(&target, params.as_deref())
}
/**
*
*/
#[allow(dead_code)]
#[napi]
fn has_runas(path: String) -> bool {
windows::has_runas(path)
}

View File

@ -42,15 +42,14 @@ use windows::{
Shell::{
BHID_SFUIObject, IContextMenu, IShellItem, IShellItemImageFactory, IShellLinkW,
SHCreateItemFromParsingName, SHEmptyRecycleBinW, SHQueryUserNotificationState,
ShellLink, CMF_NORMAL, CMINVOKECOMMANDINFO, GCS_VERBA, QUNS_ACCEPTS_NOTIFICATIONS,
QUNS_APP, QUNS_BUSY, QUNS_NOT_PRESENT, QUNS_PRESENTATION_MODE, QUNS_QUIET_TIME,
ShellLink, CMF_NORMAL, CMINVOKECOMMANDINFO, QUNS_ACCEPTS_NOTIFICATIONS, QUNS_APP,
QUNS_BUSY, QUNS_NOT_PRESENT, QUNS_PRESENTATION_MODE, QUNS_QUIET_TIME,
QUNS_RUNNING_D3D_FULL_SCREEN, SHERB_NOSOUND, SIIGBF_ICONONLY, SLGP_UNCPRIORITY,
},
WindowsAndMessaging::{
CallNextHookEx, CreatePopupMenu, DestroyMenu, FindWindowW, GetClassNameW,
GetCursorPos, GetForegroundWindow, GetMenuItemCount, GetMenuItemInfoA,
GetSystemMetrics, GetWindowRect, SendMessageW, SetForegroundWindow,
SetWindowsHookExW, TrackPopupMenu, WindowFromPoint, HHOOK, MENUITEMINFOA, MIIM_ID,
GetCursorPos, GetForegroundWindow, GetSystemMetrics, GetWindowRect, SendMessageW,
SetForegroundWindow, SetWindowsHookExW, TrackPopupMenu, WindowFromPoint, HHOOK,
MSLLHOOKSTRUCT, SC_MONITORPOWER, SM_CXSCREEN, SM_CYSCREEN, SW_NORMAL, TPM_NONOTIFY,
TPM_RETURNCMD, WH_MOUSE_LL, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN,
WM_MBUTTONUP, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_RBUTTONDOWN,
@ -722,13 +721,6 @@ pub fn shell_execute(
start_location: Option<String>,
) {
thread::spawn(move || {
let mut operation = operation;
// 判断是否是runas如果是的话需要判断文件是否有以管理员身份运行的权限如果没有改为open
if operation == "runas" {
if !has_runas(file.clone()) {
operation = String::from("open");
}
}
// 是否是打开文件夹
let is_dir = operation == "explore";
// dir
@ -743,6 +735,10 @@ pub fn shell_execute(
path.parent().unwrap().display().to_string()
}
});
// 文件夹
let dir_param = format!("\"{}\"", file.to_string());
let dir_param = HSTRING::from(dir_param.as_str());
let dir_param = PCWSTR(dir_param.as_ptr());
// HSTRING
let operation = HSTRING::from(operation.as_str());
let file = HSTRING::from(file.as_str());
@ -759,7 +755,7 @@ pub fn shell_execute(
None,
w!("open"),
w!("explorer.exe"),
file,
dir_param,
None,
SW_SHOWDEFAULT,
);
@ -808,68 +804,3 @@ pub fn system_item_execute(target: &str, params: Option<&str>) {
}
}
}
/**
*
*/
pub fn has_runas(path: String) -> bool {
// IShellItem
let path = HSTRING::from(path);
if let Ok(shell_item) =
unsafe { SHCreateItemFromParsingName::<_, _, IShellItem>(PCWSTR(path.as_ptr()), None) }
{
// IContextMenu
if let Ok(context_menu) =
unsafe { shell_item.BindToHandler::<_, IContextMenu>(None, &BHID_SFUIObject) }
{
// Menu
if let Ok(menu) = unsafe { CreatePopupMenu() } {
// 写入菜单
if let Ok(()) =
unsafe { context_menu.QueryContextMenu(menu, 0, 1, 0x7FFF, CMF_NORMAL) }
{
// 获取菜单总数
let count = unsafe { GetMenuItemCount(menu) };
// 循环每一项菜单
for i in 0..count {
// 获取菜单信息
let mut menu_info = MENUITEMINFOA::default();
menu_info.cbSize = std::mem::size_of::<MENUITEMINFOA>() as u32;
menu_info.fMask = MIIM_ID;
if unsafe { GetMenuItemInfoA(menu, i as u32, true, &mut menu_info) }
.as_bool()
{
// idcmd
let idcmd = menu_info.wID as usize - 1;
// 菜单项比如在指定范围内
if idcmd >= 1 && idcmd <= 0x7FFF {
// 获取菜单命令信息
let mut verb = [0u8; 256];
let pstr = PSTR(verb.as_mut_ptr());
if let Ok(()) = unsafe {
context_menu.GetCommandString(
menu_info.wID as usize - 1,
GCS_VERBA,
None,
pstr,
verb.len() as u32,
)
} {
if let Ok(command) = unsafe { pstr.to_string() } {
if command.to_lowercase() == "runas" {
return true;
}
}
}
}
}
}
unsafe {
DestroyMenu(menu);
}
}
}
}
}
false
}

View File

@ -523,6 +523,8 @@ onMounted(() => {
//
listens.push(
window.main.onShowWindowBefore((data) => {
//
store.search = false;
if (classificationContentRef.value) {
// IDID
let selectedClassificationId: number | null =