game_detector/
ms_store.rs1#[derive(Debug, Clone)]
2pub struct GamePackage {
3 pub app_id: String,
4
5 pub app_publisher: String,
6 pub app_name: String,
7 pub app_version: String,
8 pub app_arch: String,
9 pub app_publisher_id: String,
10
11 pub path: String,
12}
13
14#[cfg(windows)]
17fn parse_app_id(s: &str) -> anyhow::Result<[String; 5]> {
18 use anyhow::Context;
19 let mut parts = s.split('_');
20 let publisher_and_name = parts.next().context("Invalid app id (publisher+name)")?;
21 let mut pan_parts = publisher_and_name.split('.');
22 let publisher = pan_parts.next().context("Invalid app id (publisher)")?;
23 let name = pan_parts.next().context("Invalid app id (name)")?;
24
25 let version = parts.next().context("Invalid app id (version)")?;
26 let arch = parts.next().context("Invalid app id (arch)")?;
27 parts.next().context("Invalid app id (field4)")?;
28 let publisher_id = parts.next().context("Invalid app id (publisher id)")?;
29 Ok([
30 publisher.to_string(),
31 name.to_string(),
32 version.to_string(),
33 arch.to_string(),
34 publisher_id.to_string(),
35 ])
36}
37
38#[cfg(not(windows))]
39pub fn get_game_packages() -> anyhow::Result<Vec<GamePackage>> {
40 Ok(vec![])
41}
42
43#[cfg(windows)]
44pub fn get_game_packages() -> anyhow::Result<Vec<GamePackage>> {
45 use log::warn;
46 use std::path::Path;
47
48 const GAMING_SERVICES_PACKAGE_REPOSITORY: &str =
49 "SOFTWARE\\Microsoft\\GamingServices\\PackageRepository\\Package";
50 const FULL_PACKAGE_REPOSITORY: &str =
51 "SOFTWARE\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppModel\\PackageRepository\\Packages";
52
53 let hklm = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE);
54 let Ok(package_repo) = hklm.open_subkey(GAMING_SERVICES_PACKAGE_REPOSITORY) else {
55 return Ok(vec![]);
57 };
58
59 let mut packages = vec![];
60 for (app_id, _) in package_repo.enum_values().flatten() {
61 let pkg_path = Path::new(FULL_PACKAGE_REPOSITORY).join(&app_id);
62 let pkg = hklm.open_subkey(pkg_path)?;
63 match pkg.get_value::<String, _>("Path") {
64 Ok(path) => match parse_app_id(&app_id) {
65 Ok(o) => {
66 let [app_publisher, app_name, app_version, app_arch, app_publisher_id] = o;
67 packages.push(GamePackage {
68 app_id,
69 app_publisher,
70 app_name,
71 app_version,
72 app_arch,
73 app_publisher_id,
74 path,
75 })
76 }
77 Err(e) => {
78 eprintln!("Couldn't parse package id '{app_id}': {e}");
79 }
80 },
81 Err(e) => {
82 warn!("Couldn't read path key for package '{app_id}': {e}");
83 }
84 }
85 }
86
87 Ok(packages)
88}