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,52 +234,63 @@ 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 (
result.Package.Applications &&
result.Package.Applications[0] &&
result.Package.Applications[0].Application &&
result.Package.Applications[0].Application.length > 0
) {
for (
let i = 0;
i < result.Package.Applications[0].Application.length;
i++
) {
// appx信息
let appxInfo: AppxInfo = {
id: null,
icon: null,
name: null,
};
// Application
const application = result.Package.Applications[0].Application[i];
// 名称
if (appx["appName" + i] && appx["appName" + i].trim() !== "") {
appxInfo.name = appx["appName" + i];
} else {
appxInfo.name = appx.displayName;
}
// 获取ID
let id = application.$.Id;
if (!id || id.trim() === "") {
continue;
}
appxInfo.id = appx.familyName + "!" + id;
// 图标
try {
// targetsize图标 // targetsize图标
let targetSizeIcon: string | null = null; let targetSizeIcon: string | null = null;
let targetSizeIconMax: number | null = null; let targetSizeIconMax: number | null = null;
// scale图标 // scale图标
let scaleIcon = null; let scaleIcon = null;
let scaleIconMax = null; let scaleIconMax = null;
// 图标 APPID // 图标
if (result.Package.Applications && result.Package.Applications[0]) { if (application["uap:VisualElements"]) {
if (result.Package.Applications[0].Application[0]) {
// APPID
appxInfo.appId = result.Package.Applications[0].Application[0].$.Id;
// Executable
executable = result.Package.Applications[0].Application[0].$.Executable;
// 获取图标
if (
result.Package.Applications[0].Application[0]["uap:VisualElements"] !=
null
) {
// logo地址 // logo地址
let logo = let logo = application["uap:VisualElements"][0].$.Square44x44Logo;
result.Package.Applications[0].Application[0][
"uap:VisualElements"
][0].$.Square44x44Logo;
// 解析路径 // 解析路径
let parsedPath = parse(logo); let parsedPath = parse(logo);
// 获取文件夹下所有文件 // 获取文件夹下所有文件
let fileNameList = readdirSync( let fileNameList = readdirSync(join(appx.path, parsedPath.dir));
installLocation + "\\" + parsedPath.dir
);
// 筛选出和包含logo名称的文件名 // 筛选出和包含logo名称的文件名
let filterList = fileNameList.filter( let filterList = fileNameList.filter(
(f) => f.indexOf(parsedPath.name) >= 0 (f) => f.indexOf(parsedPath.name) >= 0
@ -377,7 +321,7 @@ async function getAppxInfo(installLocation: string) {
); );
targetSizeIcon = targetSizeIcon =
defaultList.length > 0 defaultList.length > 0
? installLocation + ? appx.path +
"\\" + "\\" +
parsedPath.dir + parsedPath.dir +
"\\" + "\\" +
@ -398,7 +342,7 @@ async function getAppxInfo(installLocation: string) {
); );
if (defaultUnplatedList.length > 0) { if (defaultUnplatedList.length > 0) {
targetSizeIcon = targetSizeIcon =
installLocation + appx.path +
"\\" + "\\" +
parsedPath.dir + parsedPath.dir +
"\\" + "\\" +
@ -411,11 +355,14 @@ async function getAppxInfo(installLocation: string) {
let defaultAltFormList = targetSizeList.filter( let defaultAltFormList = targetSizeList.filter(
(f) => (f) =>
f === f ===
parsedPath.name + ".targetsize-" + max + "_altform.png" parsedPath.name +
".targetsize-" +
max +
"_altform.png"
); );
if (defaultAltFormList.length > 0) { if (defaultAltFormList.length > 0) {
targetSizeIcon = targetSizeIcon =
installLocation + appx.path +
"\\" + "\\" +
parsedPath.dir + parsedPath.dir +
"\\" + "\\" +
@ -427,11 +374,12 @@ async function getAppxInfo(installLocation: string) {
// 获取 名称.targetsize-{max}.png // 获取 名称.targetsize-{max}.png
let defaultTargetSizeList = targetSizeList.filter( let defaultTargetSizeList = targetSizeList.filter(
(f) => (f) =>
f === parsedPath.name + ".targetsize-" + max + ".png" f ===
parsedPath.name + ".targetsize-" + max + ".png"
); );
if (defaultTargetSizeList.length > 0) { if (defaultTargetSizeList.length > 0) {
targetSizeIcon = targetSizeIcon =
installLocation + appx.path +
"\\" + "\\" +
parsedPath.dir + parsedPath.dir +
"\\" + "\\" +
@ -458,11 +406,7 @@ async function getAppxInfo(installLocation: string) {
); );
if (defaultList.length > 0) { if (defaultList.length > 0) {
scaleIcon = scaleIcon =
installLocation + appx.path + "\\" + parsedPath.dir + "\\" + defaultList[0];
"\\" +
parsedPath.dir +
"\\" +
defaultList[0];
} }
} }
} else { } else {
@ -486,7 +430,7 @@ async function getAppxInfo(installLocation: string) {
); );
if (defaultList.length > 0) { if (defaultList.length > 0) {
scaleIcon = scaleIcon =
installLocation + appx.path +
"\\" + "\\" +
parsedPath.dir + parsedPath.dir +
"\\" + "\\" +
@ -499,9 +443,7 @@ async function getAppxInfo(installLocation: string) {
if (filterList.length === 1) { if (filterList.length === 1) {
// 只有一张图片 // 只有一张图片
appxInfo.icon = appxInfo.icon =
installLocation + "\\" + parsedPath.dir + "\\" + filterList[0]; appx.path + "\\" + parsedPath.dir + "\\" + filterList[0];
}
}
} }
} }
} }
@ -512,7 +454,10 @@ async function getAppxInfo(installLocation: string) {
} else if (!targetSizeIcon && scaleIcon) { } else if (!targetSizeIcon && scaleIcon) {
appxInfo.icon = scaleIcon; appxInfo.icon = scaleIcon;
} else if (targetSizeIcon && scaleIcon) { } else if (targetSizeIcon && scaleIcon) {
if (targetSizeIconMax === 256 || targetSizeIconMax > scaleIconMax) { if (
targetSizeIconMax === 256 ||
targetSizeIconMax > scaleIconMax
) {
appxInfo.icon = targetSizeIcon; appxInfo.icon = targetSizeIcon;
} else if (targetSizeIconMax < scaleIconMax) { } else if (targetSizeIconMax < scaleIconMax) {
appxInfo.icon = scaleIcon; appxInfo.icon = scaleIcon;
@ -520,45 +465,41 @@ async function getAppxInfo(installLocation: string) {
appxInfo.icon = targetSizeIcon; appxInfo.icon = targetSizeIcon;
} }
} else if (!targetSizeIcon && !scaleIcon) { } else if (!targetSizeIcon && !scaleIcon) {
let propertiesIcon = getPropertiesIcon(installLocation, result); let propertiesIcon = getPropertiesIcon(appx.path, result);
if (propertiesIcon) { if (propertiesIcon) {
appxInfo.icon = propertiesIcon; appxInfo.icon = propertiesIcon;
} }
} }
} }
// 名称 } catch (e) {
if (result.Package.Properties) { if (result) {
if (result.Package.Properties[0].DisplayName) { let propertiesIcon = getPropertiesIcon(appx.path, result);
appxInfo.name = result.Package.Properties[0].DisplayName[0]; if (propertiesIcon) {
appxInfo.icon = propertiesIcon;
}
} }
} }
if ( if (
!appxInfo.name || (!appxInfo.icon || appxInfo.icon.trim() === "") &&
(appxInfo.name && appxInfo.name.indexOf("ms-resource:") >= 0) appx.logo &&
appx.logo.trim() !== ""
) { ) {
if (executable && executable.indexOf("ms-resource:") < 0) { appxInfo.icon = appx.logo;
appxInfo.name = parse(executable).name;
} else {
appxInfo.name = null;
} }
} if (
if (!appxInfo.name) { appxInfo.name &&
if (result.Package.Identity && result.Package.Identity[0]) { appxInfo.name.trim() !== "" &&
let name = result.Package.Identity[0].$.Name; appxInfo.id &&
if (name && name.indexOf("ms-resource:") < 0) { appxInfo.id.trim() !== "" &&
appxInfo.name = name; appxInfo.icon &&
appxInfo.icon.trim() !== ""
) {
resultList.push(appxInfo);
} }
} }
} }
} catch (ex) { } catch (ex) {}
if (result) { return resultList;
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
}