Optimize the acquisition of APPX application information and obtain more APPX applications.

This commit is contained in:
unknown 2023-11-10 22:53:38 +08:00
parent 946d94cb5b
commit 0d93c2f922
4 changed files with 300 additions and 288 deletions

View File

@ -31,6 +31,10 @@ features = [
"Win32_UI_Input_Ime", "Win32_UI_Input_Ime",
"Win32_Globalization", "Win32_Globalization",
"Win32_Graphics_Dwm", "Win32_Graphics_Dwm",
"Management_Deployment",
"ApplicationModel",
"Foundation_Collections",
"ApplicationModel_Core",
] ]
[build-dependencies] [build-dependencies]

View File

@ -15,9 +15,7 @@ import { getAbsolutePath, getFileIcon } from "../commons/utils";
// AppxInfo // AppxInfo
export interface AppxInfo { export interface AppxInfo {
packageFamilyName: string; id: string | null;
installLocation: string;
appId: string | null;
icon: string | null; icon: string | null;
name: string | null; name: string | null;
} }
@ -191,76 +189,15 @@ async function getAppxItemList() {
// ID // ID
let id = 1; let id = 1;
// 获取APPX信息 // 获取APPX信息
let stdout = execSync( let appxList = global.addon.getAppxList();
'powershell -Command "Get-AppxPackage | Select-Object PackageFamilyName, InstallLocation | Format-list"'
);
let strAppxInfo = stdout.toString("utf-8");
// 按换行符分割
let lines = strAppxInfo
.trim()
.split("\r\n")
.filter((str) => str.trim() !== "");
// 临时列表 // 临时列表
let tempList: Array<AppxInfo> = []; let tempList = [];
// APPX包名
let packageFamilyName: string | null = null;
// APPX路径
let installLocation: string | null = null;
// 循环的前一个信息
let prev = null;
// 解析每一行
for (let i = 0; i < lines.length; i++) {
let line = lines[i].trim();
let arr = line.split(" : ");
if (arr.length > 1) {
if (arr[0].trim() === "PackageFamilyName") {
if (packageFamilyName && installLocation) {
tempList.push({
packageFamilyName: packageFamilyName,
installLocation: installLocation,
appId: null,
icon: null,
name: null,
});
packageFamilyName = arr[1].trim();
installLocation = null;
prev = "PackageFamilyName";
} else {
packageFamilyName = arr[1].trim();
prev = "PackageFamilyName";
}
} else if (arr[0].trim() === "InstallLocation") {
installLocation = arr[1].trim();
prev = "InstallLocation";
}
} else {
if (prev === "PackageFamilyName") {
packageFamilyName += line;
} else if (prev === "InstallLocation") {
installLocation += line;
}
}
}
if (packageFamilyName && installLocation) {
tempList.push({
packageFamilyName: packageFamilyName,
installLocation: installLocation,
appId: null,
icon: null,
name: null,
});
}
// 读取XML获取图标路径和名称 // 读取XML获取图标路径和名称
for (let temp of tempList) { for (let appx of appxList) {
let appxInfo = await getAppxInfo(temp.installLocation); tempList.push(...(await getAppxInfo(appx)));
temp.appId = appxInfo.appId;
temp.icon = appxInfo.icon;
temp.name = appxInfo.name;
} }
// 过滤
let filterList = tempList.filter((e) => e.icon && e.appId && e.name);
// 图标转BASE64 // 图标转BASE64
for (let appxInfo of filterList) { for (let appxInfo of tempList) {
try { try {
let buffer = readFileSync(appxInfo.icon); let buffer = readFileSync(appxInfo.icon);
let icon = let icon =
@ -274,20 +211,16 @@ async function getAppxItemList() {
} }
} }
// 筛选出有图标的数据 // 筛选出有图标的数据
filterList = filterList.filter((e) => e.icon); tempList = tempList.filter((e) => e.icon);
// 返回列表 // 返回列表
for (const appxInfo of filterList) { for (const appxInfo of tempList) {
resultList.push( resultList.push(
newCommonItem({ newCommonItem({
id: id++, id: id++,
name: appxInfo.name, name: appxInfo.name,
data: newCommonItemData({ data: newCommonItemData({
icon: appxInfo.icon, icon: appxInfo.icon,
target: target: "Shell:AppsFolder\\" + appxInfo.id,
"Shell:AppsFolder\\" +
appxInfo.packageFamilyName +
"!" +
appxInfo.appId,
}), }),
}) })
); );
@ -301,264 +234,272 @@ async function getAppxItemList() {
/** /**
* Appx信息 * Appx信息
*/ */
async function getAppxInfo(installLocation: string) { async function getAppxInfo(appx: any) {
// appx信息 // 结果列表
let appxInfo: AppxInfo = { let resultList = [];
packageFamilyName: null,
installLocation: null,
appId: null,
icon: null,
name: null,
};
// buffer, 解析结果 // buffer, 解析结果
let buffer: Buffer, result: any; let buffer: Buffer, result: any;
try { try {
// 解析 // 解析
buffer = readFileSync(installLocation + "\\AppxManifest.xml"); buffer = readFileSync(join(appx.path, "AppxManifest.xml"));
result = await xml2jsSync(buffer); result = await xml2jsSync(buffer);
// 备用名称 // 循环Application
let executable = null; if (
// targetsize图标 result.Package.Applications &&
let targetSizeIcon: string | null = null; result.Package.Applications[0] &&
let targetSizeIconMax: number | null = null; result.Package.Applications[0].Application &&
// scale图标 result.Package.Applications[0].Application.length > 0
let scaleIcon = null; ) {
let scaleIconMax = null; for (
// 图标 APPID let i = 0;
if (result.Package.Applications && result.Package.Applications[0]) { i < result.Package.Applications[0].Application.length;
if (result.Package.Applications[0].Application[0]) { i++
// APPID ) {
appxInfo.appId = result.Package.Applications[0].Application[0].$.Id; // appx信息
// Executable let appxInfo: AppxInfo = {
executable = result.Package.Applications[0].Application[0].$.Executable; id: null,
// 获取图标 icon: null,
if ( name: null,
result.Package.Applications[0].Application[0]["uap:VisualElements"] != };
null // Application
) { const application = result.Package.Applications[0].Application[i];
// logo地址 // 名称
let logo = if (appx["appName" + i] && appx["appName" + i].trim() !== "") {
result.Package.Applications[0].Application[0][ appxInfo.name = appx["appName" + i];
"uap:VisualElements" } else {
][0].$.Square44x44Logo; appxInfo.name = appx.displayName;
// 解析路径 }
let parsedPath = parse(logo); // 获取ID
// 获取文件夹下所有文件 let id = application.$.Id;
let fileNameList = readdirSync( if (!id || id.trim() === "") {
installLocation + "\\" + parsedPath.dir continue;
); }
// 筛选出和包含logo名称的文件名 appxInfo.id = appx.familyName + "!" + id;
let filterList = fileNameList.filter( // 图标
(f) => f.indexOf(parsedPath.name) >= 0 try {
); // targetsize图标
if (filterList.length > 1) { let targetSizeIcon: string | null = null;
// 获取targetsize图片 let targetSizeIconMax: number | null = null;
let targetSizeList = filterList.filter( // scale图标
(f) => f.indexOf(parsedPath.name + ".targetsize") >= 0 let scaleIcon = null;
let scaleIconMax = null;
// 图标
if (application["uap:VisualElements"]) {
// logo地址
let logo = application["uap:VisualElements"][0].$.Square44x44Logo;
// 解析路径
let parsedPath = parse(logo);
// 获取文件夹下所有文件
let fileNameList = readdirSync(join(appx.path, parsedPath.dir));
// 筛选出和包含logo名称的文件名
let filterList = fileNameList.filter(
(f) => f.indexOf(parsedPath.name) >= 0
); );
if (targetSizeList.length > 0) { if (filterList.length > 1) {
// 获取最大图标尺寸 // 获取targetsize图片
let max = getMaxIconSize( let targetSizeList = filterList.filter(
targetSizeList, (f) => f.indexOf(parsedPath.name + ".targetsize") >= 0
parsedPath.name,
"targetsize"
); );
if (max) { if (targetSizeList.length > 0) {
// 记录max // 获取最大图标尺寸
targetSizeIconMax = max; let max = getMaxIconSize(
// 先获取最终图标 targetSizeList,
let defaultList = targetSizeList.filter( parsedPath.name,
(f) => "targetsize"
f ===
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated_devicefamily-colorfulunplated.png"
); );
targetSizeIcon = if (max) {
defaultList.length > 0 // 记录max
? installLocation + targetSizeIconMax = max;
"\\" + // 先获取最终图标
parsedPath.dir + let defaultList = targetSizeList.filter(
"\\" +
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated_devicefamily-colorfulunplated.png"
: null;
if (!targetSizeIcon) {
// 获取 名称.targetsize-{max}_altform-unplated.png
let defaultUnplatedList = targetSizeList.filter(
(f) => (f) =>
f === f ===
parsedPath.name + parsedPath.name +
".targetsize-" + ".targetsize-" +
max + max +
"_altform-unplated.png" "_altform-unplated_devicefamily-colorfulunplated.png"
); );
if (defaultUnplatedList.length > 0) { targetSizeIcon =
targetSizeIcon = defaultList.length > 0
installLocation + ? appx.path +
"\\" +
parsedPath.dir +
"\\" +
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated.png";
} else {
// 获取 名称.targetsize-{max}_altform.png
let defaultAltFormList = targetSizeList.filter(
(f) =>
f ===
parsedPath.name + ".targetsize-" + max + "_altform.png"
);
if (defaultAltFormList.length > 0) {
targetSizeIcon =
installLocation +
"\\" + "\\" +
parsedPath.dir + parsedPath.dir +
"\\" + "\\" +
parsedPath.name + parsedPath.name +
".targetsize-" + ".targetsize-" +
max + max +
"_altform.png"; "_altform-unplated_devicefamily-colorfulunplated.png"
: null;
if (!targetSizeIcon) {
// 获取 名称.targetsize-{max}_altform-unplated.png
let defaultUnplatedList = targetSizeList.filter(
(f) =>
f ===
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated.png"
);
if (defaultUnplatedList.length > 0) {
targetSizeIcon =
appx.path +
"\\" +
parsedPath.dir +
"\\" +
parsedPath.name +
".targetsize-" +
max +
"_altform-unplated.png";
} else { } else {
// 获取 名称.targetsize-{max}.png // 获取 名称.targetsize-{max}_altform.png
let defaultTargetSizeList = targetSizeList.filter( let defaultAltFormList = targetSizeList.filter(
(f) => (f) =>
f === parsedPath.name + ".targetsize-" + max + ".png" f ===
parsedPath.name +
".targetsize-" +
max +
"_altform.png"
); );
if (defaultTargetSizeList.length > 0) { if (defaultAltFormList.length > 0) {
targetSizeIcon = targetSizeIcon =
installLocation + appx.path +
"\\" + "\\" +
parsedPath.dir + parsedPath.dir +
"\\" + "\\" +
defaultTargetSizeList[0]; parsedPath.name +
".targetsize-" +
max +
"_altform.png";
} else {
// 获取 名称.targetsize-{max}.png
let defaultTargetSizeList = targetSizeList.filter(
(f) =>
f ===
parsedPath.name + ".targetsize-" + max + ".png"
);
if (defaultTargetSizeList.length > 0) {
targetSizeIcon =
appx.path +
"\\" +
parsedPath.dir +
"\\" +
defaultTargetSizeList[0];
}
} }
} }
} }
} }
} }
} // 获取scale图片
// 获取scale图片 let scaleList = filterList.filter(
let scaleList = filterList.filter( (f) => f.indexOf(parsedPath.name + ".scale") >= 0
(f) => f.indexOf(parsedPath.name + ".scale") >= 0
);
if (scaleList.length > 0) {
// 获取最大图标尺寸
let max = getMaxIconSize(scaleList, parsedPath.name, "scale");
if (max) {
// 记录max
scaleIconMax = max;
// 获取 名称.scale-{max}.png
let defaultList = scaleList.filter(
(f) => f === parsedPath.name + ".scale-" + max + ".png"
);
if (defaultList.length > 0) {
scaleIcon =
installLocation +
"\\" +
parsedPath.dir +
"\\" +
defaultList[0];
}
}
} else {
scaleList = filterList.filter(
(f) => f.indexOf(parsedPath.name + ".Theme-Dark_Scale") >= 0
); );
if (scaleList.length > 0) { if (scaleList.length > 0) {
let max = getMaxIconSize( // 获取最大图标尺寸
scaleList, let max = getMaxIconSize(scaleList, parsedPath.name, "scale");
parsedPath.name,
"Theme-Dark_Scale"
);
if (max) { if (max) {
// 记录max // 记录max
scaleIconMax = max; scaleIconMax = max;
// 获取 名称.Theme-Dark_Scale{max}.png // 获取 名称.scale-{max}.png
let defaultList = scaleList.filter( let defaultList = scaleList.filter(
(f) => (f) => f === parsedPath.name + ".scale-" + max + ".png"
f ===
parsedPath.name + ".Theme-Dark_Scale-" + max + ".png"
); );
if (defaultList.length > 0) { if (defaultList.length > 0) {
scaleIcon = scaleIcon =
installLocation + appx.path + "\\" + parsedPath.dir + "\\" + defaultList[0];
"\\" + }
parsedPath.dir + }
"\\" + } else {
defaultList[0]; scaleList = filterList.filter(
(f) => f.indexOf(parsedPath.name + ".Theme-Dark_Scale") >= 0
);
if (scaleList.length > 0) {
let max = getMaxIconSize(
scaleList,
parsedPath.name,
"Theme-Dark_Scale"
);
if (max) {
// 记录max
scaleIconMax = max;
// 获取 名称.Theme-Dark_Scale{max}.png
let defaultList = scaleList.filter(
(f) =>
f ===
parsedPath.name + ".Theme-Dark_Scale-" + max + ".png"
);
if (defaultList.length > 0) {
scaleIcon =
appx.path +
"\\" +
parsedPath.dir +
"\\" +
defaultList[0];
}
} }
} }
} }
} else {
if (filterList.length === 1) {
// 只有一张图片
appxInfo.icon =
appx.path + "\\" + parsedPath.dir + "\\" + filterList[0];
}
} }
} else { }
if (filterList.length === 1) { if (!appxInfo.icon) {
// 只有一张图片 // 判断图标大小
appxInfo.icon = if (targetSizeIcon && !scaleIcon) {
installLocation + "\\" + parsedPath.dir + "\\" + filterList[0]; appxInfo.icon = targetSizeIcon;
} else if (!targetSizeIcon && scaleIcon) {
appxInfo.icon = scaleIcon;
} else if (targetSizeIcon && scaleIcon) {
if (
targetSizeIconMax === 256 ||
targetSizeIconMax > scaleIconMax
) {
appxInfo.icon = targetSizeIcon;
} else if (targetSizeIconMax < scaleIconMax) {
appxInfo.icon = scaleIcon;
} else {
appxInfo.icon = targetSizeIcon;
}
} else if (!targetSizeIcon && !scaleIcon) {
let propertiesIcon = getPropertiesIcon(appx.path, result);
if (propertiesIcon) {
appxInfo.icon = propertiesIcon;
}
}
}
} catch (e) {
if (result) {
let propertiesIcon = getPropertiesIcon(appx.path, result);
if (propertiesIcon) {
appxInfo.icon = propertiesIcon;
} }
} }
} }
} if (
} (!appxInfo.icon || appxInfo.icon.trim() === "") &&
if (!appxInfo.icon) { appx.logo &&
// 判断图标大小 appx.logo.trim() !== ""
if (targetSizeIcon && !scaleIcon) { ) {
appxInfo.icon = targetSizeIcon; appxInfo.icon = appx.logo;
} else if (!targetSizeIcon && scaleIcon) {
appxInfo.icon = scaleIcon;
} else if (targetSizeIcon && scaleIcon) {
if (targetSizeIconMax === 256 || targetSizeIconMax > scaleIconMax) {
appxInfo.icon = targetSizeIcon;
} else if (targetSizeIconMax < scaleIconMax) {
appxInfo.icon = scaleIcon;
} else {
appxInfo.icon = targetSizeIcon;
} }
} else if (!targetSizeIcon && !scaleIcon) { if (
let propertiesIcon = getPropertiesIcon(installLocation, result); appxInfo.name &&
if (propertiesIcon) { appxInfo.name.trim() !== "" &&
appxInfo.icon = propertiesIcon; appxInfo.id &&
appxInfo.id.trim() !== "" &&
appxInfo.icon &&
appxInfo.icon.trim() !== ""
) {
resultList.push(appxInfo);
} }
} }
} }
// 名称 } catch (ex) {}
if (result.Package.Properties) { return resultList;
if (result.Package.Properties[0].DisplayName) {
appxInfo.name = result.Package.Properties[0].DisplayName[0];
}
}
if (
!appxInfo.name ||
(appxInfo.name && appxInfo.name.indexOf("ms-resource:") >= 0)
) {
if (executable && executable.indexOf("ms-resource:") < 0) {
appxInfo.name = parse(executable).name;
} else {
appxInfo.name = null;
}
}
if (!appxInfo.name) {
if (result.Package.Identity && result.Package.Identity[0]) {
let name = result.Package.Identity[0].$.Name;
if (name && name.indexOf("ms-resource:") < 0) {
appxInfo.name = name;
}
}
}
} catch (ex) {
if (result) {
let propertiesIcon = getPropertiesIcon(installLocation, result);
if (propertiesIcon) {
appxInfo.icon = propertiesIcon;
}
}
}
return appxInfo;
} }
/** /**

View File

@ -126,7 +126,7 @@ fn disable_mouse_hook() {
*/ */
#[allow(dead_code)] #[allow(dead_code)]
#[napi] #[napi]
pub fn get_cursor_pos_window_class_name() -> String { fn get_cursor_pos_window_class_name() -> String {
windows::get_cursor_pos_window_class_name() windows::get_cursor_pos_window_class_name()
} }
@ -135,7 +135,7 @@ pub fn get_cursor_pos_window_class_name() -> String {
*/ */
#[allow(dead_code)] #[allow(dead_code)]
#[napi] #[napi]
pub fn get_clipboard_file_list() -> Vec<String> { fn get_clipboard_file_list() -> Vec<String> {
windows::get_clipboard_file_list() windows::get_clipboard_file_list()
} }
@ -144,7 +144,7 @@ pub fn get_clipboard_file_list() -> Vec<String> {
*/ */
#[allow(dead_code)] #[allow(dead_code)]
#[napi] #[napi]
pub fn clipboard_has_bitmap() -> bool { fn clipboard_has_bitmap() -> bool {
windows::clipboard_has_bitmap() windows::clipboard_has_bitmap()
} }
@ -153,7 +153,7 @@ pub fn clipboard_has_bitmap() -> bool {
*/ */
#[allow(dead_code)] #[allow(dead_code)]
#[napi] #[napi]
pub fn get_clipboard_bitmap_base64() -> Option<String> { fn get_clipboard_bitmap_base64() -> Option<String> {
windows::get_clipboard_bitmap_base64() windows::get_clipboard_bitmap_base64()
} }
@ -162,7 +162,7 @@ pub fn get_clipboard_bitmap_base64() -> Option<String> {
*/ */
#[allow(dead_code)] #[allow(dead_code)]
#[napi] #[napi]
pub fn empty_recycle_bin(window: i32) { fn empty_recycle_bin(window: i32) {
windows::empty_recycle_bin(window) windows::empty_recycle_bin(window)
} }
@ -171,6 +171,15 @@ pub fn empty_recycle_bin(window: i32) {
*/ */
#[allow(dead_code)] #[allow(dead_code)]
#[napi] #[napi]
pub fn remove_window_animation(window: i32) { fn remove_window_animation(window: i32) {
windows::remove_window_animation(window); windows::remove_window_animation(window);
} }
/**
* APPX列表
*/
#[allow(dead_code)]
#[napi]
fn get_appx_list() -> Vec<HashMap<String, String>> {
windows::get_appx_list()
}

View File

@ -13,6 +13,7 @@ use std::{
process::Command, process::Command,
sync::atomic::{AtomicBool, Ordering}, sync::atomic::{AtomicBool, Ordering},
}; };
use windows::Management::Deployment::PackageManager;
use windows::{ use windows::{
core::{ComInterface, HSTRING, PCSTR, PCWSTR}, core::{ComInterface, HSTRING, PCSTR, PCWSTR},
w, w,
@ -691,3 +692,60 @@ pub fn remove_window_animation(window: i32) {
); );
}; };
} }
/**
* APPX列表
*/
pub fn get_appx_list() -> Vec<HashMap<String, String>> {
let mut result_list = vec![];
let package_manager: Result<PackageManager, windows::core::Error> = PackageManager::new();
if package_manager.is_err() {
return result_list;
}
let packages = package_manager
.unwrap()
.FindPackagesByUserSecurityId(&HSTRING::default());
if packages.is_err() {
return result_list;
}
for package in packages.unwrap() {
let mut map = HashMap::new();
if let Ok(diaplay_name) = package.DisplayName() {
map.insert(String::from("displayName"), diaplay_name.to_string());
}
if let Ok(path) = package.InstalledPath() {
map.insert(String::from("path"), path.to_string());
}
if let Ok(id) = package.Id() {
if let Ok(family_name) = id.FamilyName() {
map.insert(String::from("familyName"), family_name.to_string());
}
}
if let Ok(logo) = package.Logo() {
if let Ok(path) = logo.Path() {
map.insert(String::from("logo"), path.to_string());
}
}
if let Ok(app_list) = package.GetAppListEntriesAsync() {
if let Ok(app_list) = app_list.get() {
for (index, app) in app_list.into_iter().enumerate() {
if app.DisplayInfo().is_err()
|| app.DisplayInfo().unwrap().DisplayName().is_err()
{
continue;
}
map.insert(
format!("appName{}", index),
app.DisplayInfo()
.unwrap()
.DisplayName()
.unwrap()
.to_string(),
);
}
}
}
result_list.push(map);
}
result_list
}